First, if this question doesn't belong here (and there is a better place for it), let me know.
Second, I'm asking this question about "code quality", not "performance".
Third, This isn't really related to PHP but as each laguage have their "Good Practices", I prefer specify it.
Finally, if there is a similar question, sorry about that, I didn't find it.
Now the Question:
Is it better to have a method parameter as array or as a "Configuration"
class ?
For example, I'm working with Doctrine and in my Reporsitory, i often have one method that accepts "criteria" and another method prepareCriteria
that use the $criteria
array to build the QueryBuilder
.
And the more I work with array in these cases, the more I wonder if it wouldn't be better to have some CriteriaBuilder
(or CriteriaConfiguration
or whatever) to completely control the typing of the parameters passed and not rely on simple string key of an array.
What are your thoughts about that ?
ps: I don't really knwo what tags can be fitted to this sort of question. I added doctrine
as I'm talking about it as example, but if you have more precise tags that could be used, let me know.
The probably best practice in PHP is to use verbose associative arrays and string assertions with only a small overhead when assertions are disabled on production systems or as of PHP7 even expections with zero cost. It's annoying when writing code but readable on later code reviews and also discovering errors when testing code at development time.
Just to show an example:
php.ini
zend.assertions = 1
assert.warning = 1
assert.exception = 1
assert.bail = 1
PHP
function foobar(array $config)
{
assert
(
(function($keys_allowed, $keys_expected)use($config)
{
// do not stop execution until all issues are output
$opt_expt = assert_options(ASSERT_EXCEPTION, 0);
$opt_bail = assert_options(ASSERT_BAIL , 0);
$ok = 1;
$ok &= assert( empty( $diff = array_diff_key(array_fill_keys($keys_expected, 1), $config) ),
new AssertionError('Missing mandatory keys: (' . join(', ', array_keys($diff)) . ')'));
$ok &= assert( empty( $diff = array_diff_key($config, $keys_allowed) ),
new AssertionError('Disallowed keys: (' . join(', ', array_keys($diff)) . ')'));
$ok &= assert( empty( $diff = array_filter
( $config,
function($v, $k)use($keys_allowed)
{
return isset($keys_allowed[$k]) && $keys_allowed[$k] !== gettype($v);
},
ARRAY_FILTER_USE_BOTH)
),
new AssertionError('Type error on items: (' . join(', ', array_keys($diff)) . ')'));
//restore configured behaviour
assert_options(ASSERT_EXCEPTION, $opt_expt);
assert_options(ASSERT_BAIL , $opt_bail);
return $ok;
})
(
[ 'foo' => 'string', 'bar' => 'integer', 'baz' => 'boolean' ], [ 'baz' ]
)
, new AssertionError('Arguments assertion in function `' . __FUNCTION__ . '` failed.')
);
// foobar function stuff
echo 'Ok!', PHP_EOL;
}
// test
foobar(['foo' => '1', 'baz' => true ] ); // Ok!
foobar([ 'bar' => 1 , 'baz' => true ] ); // Ok!
foobar(['foo' => 1 , 'baz' => true ] ); // Warning: type ; Fatal error
foobar(['foo' => '1', 'bar' => 1 ] ); // Warning: missing ; Fatal error
foobar(['foo' => 1 , 'bar' => '1' , 'forbidden' => 'x'] ); // Warnings: missing, disallowed, type ; Fatal error
The outer assertion throws a fatal error stopping the execution while the inner assertions throw non-breaking warnings.
You can easily transform the anonymous function into a named function taking the used variable as additional parameter.