PHP Parse an arrays values to a function - php

Ok so I have a function with 2 mandatory arguments and then it must have many optional arguments too.
function example($a,$b, $username, $email) {
// code
}
My data for the optional arguments comes from an array
$x = array('joeblogs', 'joe#blogs.com');
How would i be able to parse these? bearing in mind that the function may be required to parse a different set of arguments each time.
An example is with CakePHP you can specify the action arguments that are required

Something like this?
$a = 'a';
$b = 'b';
$x = array('joeblogs', 'joe#blogs.com');
$args = array_merge(array($a, $b), $x);
call_user_func_array('example', $args);
See http://php.net/manual/en/function.call-user-func-array.php

There are two approaches to optional arguments.
In the first, you specify all of the arguments like this:
function example($a, $b, $c=null, $d=null, $e=null)
Parameters $a and $b are required. The others are optional and are null if nothing is provided. This method requires that each of the optional parameters be specified in the indicated order. If you want to call the method using only $a, $b and $e you have to provide null values for $c and $d:
example($a, $b, null, null, $d);
The second method accepts an array as the third parameter. This array will be checked for keys and processed based on the keys found:
function example($a, $b, $c=array()) {
$optionalParam1 = ( !empty( $c['param1'] ) ) : $c['param1'] ? null;
$optionalParam2 = ( !empty( $c['param2'] ) ) : $c['param2'] ? null;
In this way, you can check for each key that may be provided. Null values will be provided for any key not populated.

Following shows syntax for optional parameters and default values
function example($a,$b, $username = '', $email = '') {
}
Another possibility is to pass an "optional values array"
function example($a,$b, $optional_values = array()) {
if($optional_values[0] != '') { blah blah .... }
}

This solution is a merge of your sugestion and Jez's solution.
call_user_func_array(array($controller, $action), $getVars);
Where $controller is the instance of your controller, $action is the string to the action that you want to call, and $getVars is an array of parameters.
The first parameter of the call_user_func_array function is a callback. It's possible to define a method invocation as callback.
Here is a link to the documentation of PHP's callback: http://www.php.net/manual/pt_BR/language.pseudo-types.php#language.types.callback

To pass the array parameters to a function you can use call_user_func_array:
$args = array( 'foo', 'bar', 'joeblogs', 'joe#blogs.com' );
call_user_func_array( 'example', $args );
Or simple pass any number of parameters:
example( $a, $b, $username, $email );
To retrieve the parameters inside function use func_get_args:
function example() {
$args = func_get_args();
print_r( $args );
// output:
// Array (
// [0] => foo
// [1] => bar
// [2] => joeblogs
// [3] => joe#blogs.com
// )
}

Related

Passing the right parameters to variable methods in PHP

I'm setting up a PHP API that will expose functionality and vend data to my users, and I'm looking for an elegant way of passing to my functions the arguments that my users are "passing" to me. I can determine what method my users are calling ($_POST['method']) and depending on the method, zero or more arguments to the method. I validate them using a metadata array. For example:
$methods = array(
'say_hello' => array('name'),
'say_goodbye' => array(),
'do_something' => array( 'foo', 'bar' )
);
I have corresponding functions for these:
function say_hello( $name ) { printf( "Hello, %s, $name ); }
function say_goodbye() { printf( "Goodbye!" ); }
function do_something( $foo, $bar ) { printf( "%d + %d = %d.", $foo, $bar, $foo+$bar ); }
When a POST comes in, I check that the method they're requesting is an array key of mine (so they're not passing in $_POST['method'] = 'exec' or anything nefarious), and I can do the actual call as:
$method = $_POST['method'];
$method(); // make the call
And knowing the method also allows me to determine what - if any - arguments should go into it:
$args = $methods[ $method ]; // an array of 0-2 items
But is there a good way for me to combine this without a big if-elseif-elseif-... ?
if( 'say_hello'==$method )
$method( $_POST['name'] );
elseif( ... )
...
Something like Python's myfunc(*args) is what I'm looking to do, that would let me somehow accomplish:
$method = $_POST['method'];
$args = $methods[ $method ];
$method( $args );
Right now, my best bet is to load the arguments in the methods:
function do_something()
{
$foo = $_POST['foo'];
$bar = $_POST['bar'];
...

Passing parameter to a function by parameter name? [duplicate]

Is it possible in PHP to specify a named optional parameter when calling a function/method, skipping the ones you don't want to specify (like in python)?
Something like:
function foo($a, $b = '', $c = '') {
// whatever
}
foo("hello", $c="bar"); // we want $b as the default, but specify $c
No, it is not possible (before PHP 8.0): if you want to pass the third parameter, you have to pass the second one. And named parameters are not possible either.
A "solution" would be to use only one parameter, an array, and always pass it... But don't always define everything in it.
For instance :
function foo($params) {
var_dump($params);
}
And calling it this way : (Key / value array)
foo([
'a' => 'hello',
]);
foo([
'a' => 'hello',
'c' => 'glop',
]);
foo([
'a' => 'hello',
'test' => 'another one',
]);
Will get you this output :
array
'a' => string 'hello' (length=5)
array
'a' => string 'hello' (length=5)
'c' => string 'glop' (length=4)
array
'a' => string 'hello' (length=5)
'test' => string 'another one' (length=11)
But I don't really like this solution :
You will lose the phpdoc
Your IDE will not be able to provide any hint anymore... Which is bad
So I'd go with this only in very specific cases -- for functions with lots of optional parameters, for instance...
PHP 8 was released on November 26, 2020 with a new feature called named arguments.
In this major version release, "named parameters" (aka "named arguments") afford developers some really cool new techniques when calling native and custom functions.
The custom function in this question can now be called with the first parameter (because there is no default for it) and then only the third parameter passed by using named parameters like this: (Demo)
function foo($a, $b = '', $c = '') {
echo $a . '&' . $b . '&' . $c;
}
foo("hello", c: "bar");
// output: hello&&bar
Notice that the second parameter did not need to be declared in the function call because it has a default value defined -- the default value is automatically used within the function body.
Part of the beauty of this new feature is that you don't need to be careful about the order of your named parameters -- the order of their declaration is irrelevant. foo(c: "bar", a: "hello"); works just the same. Having the ability to "skip" declarations and write declarative parameters will improve the readability of your scripts. The only downside of this new feature is that there will be a little bit more bloat in the function calls, but I (and many others) think the benefits outweigh this "cost".
Here is an example of a native function omitting the limit parameter, writing the parameters out of their normal order, and declaring a reference variable. (Demo)
echo preg_replace(
subject: 'Hello 7',
pattern: '/[a-z ]/',
count: $counted,
replacement: ''
)
. " & " . $counted;
// output: H7 & 5
There is more to tell about this new feature. You can even use an associative array to pass the named parameters to the function where the spread/splat operator can be used to unpack the data!
(*notice the slight difference in declaring the reference variable.) (Demo)
$params = [
'subject' => 'Hello 7', // normally third parameter
'pattern' => '/[a-z ]/', // normally first parameter
// 'limit' // normally fourth parameter, omitted for this demonstration; the default -1 will be used
'count' => &$counted, // normally fifth parameter
// ^-- don't forget to make it modifiable!
'replacement' => '', // normally second parameter
];
echo preg_replace(...$params) . " & " . $counted;
// same output as the previous snippet
For more information, here are a few leads that explain further about this feature and some common related errors: (I have no affiliation with the following sites)
https://wiki.php.net/rfc/named_params
https://stitcher.io/blog/php-8-named-arguments
https://stitcher.io/blog/why-we-need-named-params-in-php
No, PHP cannot pass arguments by name.
If you have a function that takes a lot of arguments and all of them have default values you can consider making the function accept an array of arguments instead:
function test (array $args) {
$defaults = array('a' => '', 'b' => '', 'c' => '');
$args = array_merge($defaults, array_intersect_key($args, $defaults));
list($a, $b, $c) = array_values($args);
// an alternative to list(): extract($args);
// you can now use $a, $b, $c
}
See it in action.
No, it isn't.
The only way you can somewhat do that is by using arrays with named keys and what not.
As of PHP 5.4 you have shorthand array syntax (not nessecary to specify arrays with cumbersome "array" and instead use "[]").
You can mimic named parameters in many ways, one good and simple way might be:
bar('one', ['a1' => 'two', 'bar' => 'three', 'foo' => 'four']);
// output: twothreefour
function bar ($a1, $kwargs = ['bar' => null, 'foo' => null]) {
extract($kwargs);
echo $a1;
echo $bar;
echo $foo;
}
You can keep the phpdoc and the ability to set defaults by passing an object instead of an array, e.g.
class FooOptions {
$opt1 = 'x';
$opt2 = 'y';
/* etc */
};
That also lets you do strict type checking in your function call, if you want to:
function foo (FooOptions $opts) {
...
}
Of course, you might pay for that with extra verbosity setting up the FooOptions object. There's no totally-free ride, unfortunately.
It's not exactly pretty, but it does the trick, some might say.
class NamedArguments {
static function init($args) {
$assoc = reset($args);
if (is_array($assoc)) {
$diff = array_diff(array_keys($assoc), array_keys($args));
if (empty($diff)) return $assoc;
trigger_error('Invalid parameters: '.join(',',$diff), E_USER_ERROR);
}
return array();
}
}
class Test {
public static function foobar($required, $optional1 = '', $optional2 = '') {
extract(NamedArguments::init(get_defined_vars()));
printf("required: %s, optional1: %s, optional2: %s\n", $required, $optional1, $optional2);
}
}
Test::foobar("required", "optional1", "optional2");
Test::foobar(array(
'required' => 'required',
'optional1' => 'optional1',
'optional2' => 'optional2'
));
Normally you can't but I think there a lot of ways to pass named arguments to a PHP function. Personally I relay on the definition using arrays and just call what I need to pass:
class Test{
public $a = false;
private $b = false;
public $c = false;
public $d = false;
public $e = false;
public function _factory(){
$args = func_get_args();
$args = $args[0];
$this->a = array_key_exists("a",$args) ? $args["a"] : 0;
$this->b = array_key_exists("b",$args) ? $args["b"] : 0;
$this->c = array_key_exists("c",$args) ? $args["c"] : 0;
$this->d = array_key_exists("d",$args) ? $args["d"] : 0;
$this->e = array_key_exists("e",$args) ? $args["e"] : 0;
}
public function show(){
var_dump($this);
}
}
$test = new Test();
$args["c"]=999;
$test->_factory($args);
$test->show();
live example here:
http://sandbox.onlinephpfunctions.com/code/d7f27c6e504737482d396cbd6cdf1cc118e8c1ff
If I have to pass 10 arguments, and 3 of them are the data I really need, is NOT EVEN SMART to pass into the function something like
return myfunction(false,false,10,false,false,"date",false,false,false,"desc");
With the approach I'm giving, you can setup any of the 10 arguments into an array:
$arr['count']=10;
$arr['type']="date";
$arr['order']="desc";
return myfunction($arr);
I have a post in my blog explaining this process in more details.
http://www.tbogard.com/2013/03/07/passing-named-arguments-to-a-function-in-php
With PHP, the order of arguments is what matters. You can't specify a particular argument out of place, but instead, you can skip arguments by passing a NULL, as long as you don't mind the value in your function having a NULL value.
foo("hello", NULL, "bar");
If you really really want, try the reflection.
And skip with null.
function getDefaultValueByNull($fn, $inputs) {
$ref = new ReflectionFunction($fn);
$args = array_map(function($p) {
return [
$p->getName(),
$p->isDefaultValueAvailable() ? $p->getDefaultValue() : NULL,
];
}, $ref->getParameters());
foreach($inputs as $i=>$val) { if ($val!==NULL) $args[$i][1] = $val; }
return array_column($args, 1, 0);
}
function sum($a=9, $b) {
extract(getDefaultValueByNull(__FUNCTION__, func_get_args()));
return $a+$b;
}
echo sum(NULL, 1); // 10
Here's what I've been using. A function definition takes one optional array argument which specifies the optional named arguments:
function func($arg, $options = Array()) {
$defaults = Array('foo' => 1.0,
'bar' => FALSE);
$options = array_merge($default, $options);
// Normal function body here. Use $options['foo'] and
// $options['bar'] to fetch named parameter values.
...
}
You can normally call without any named arguments:
func("xyzzy")
To specify an optional named argument, pass it in the optional array:
func("xyzzy", Array('foo' => 5.7))
No not really. There are a few alternatives to it you could use.
test(null,null,"hello")
Or pass an array:
test(array('c' => "hello"));
Then, the function could be:
function test($array) {
$c = isset($array[c]) ? $array[c] : '';
}
Or add a function in between, but i would not suggest this:
function ctest($c) { test('','',$c); }
I dont think so...
If you need to call, for example, the substr function, that has 3 params, and want to set the $length without set the $start, you'll be forced to do so.
substr($str,0,10);
a nice way to override this is to always use arrays for parameters
In very short, sometimes yes, by using reflection and typed variables. However I think this is probably not what you are after.
A better solution to your problem is probably to pass in the 3 arguments as functions handle the missing one inside your function yourself
<?php
function test(array $params)
{
//Check for nulls etc etc
$a = $params['a'];
$b = $params['b'];
...etc etc
}
You can't do it the python way. Anway, you could pass an associative array and than use the array entries by their name:
function test ($args=array('a'=>'','b'=>'','c'=>''))
{
// do something
}
test(array('c'=>'Hello'));
This doesn't reduce the typing, but at least it's more descriptive, having the arguments' names visible and readable in the call.
Here is a work around:
function set_param_defaults($params) {
foreach($params['default_values'] as $arg_name => $arg_value) {
if (!isset($params[$arg_name])) {
$params[$arg_name] = $arg_value;
}
}
return $params;
}
function foo($z, $x = null, $y = null) {
$default_values = ['x' => 'default value for x', 'y' => 'default value for y'];
$params = set_param_defaults(get_defined_vars());
print "$z\n";
print $params['x'] . "\n";
print $params['y'] . "\n";
}
foo('set z value', null, 'set y value');
print "\n";
foo('set z value', 'set x value');
ALTERNATIVELY:
Personally I would go with this method.
function foo($z, $x_y) {
$x_y += ['x' => 'default value for x', 'y' => 'default value for y'];
print "$z\n";
print $x_y['x'] . "\n";
print $x_y['y'] . "\n";
}
foo('set z value', ['y' => 'set y value']);
print "\n";
foo('set z value', ['x' => 'set x value']);
Print outs for both examples.
1st call:
set z value
default value for x
set y value
2nd call:
set z value
set x value
default value for y
Just use the associative array pattern Drupal uses. For optional defaulted arguments, just accept an $options argument which is an associative array. Then use the array + operator to set any missing keys in the array.
function foo ($a_required_parameter, $options = array()) {
$options += array(
'b' => '',
'c' => '',
);
// whatever
}
foo('a', array('c' => 'c’s value')); // No need to pass b when specifying c.

Dynamically call Class with variable number of parameters in the constructor

I know that it is possible to call a function with a variable number of parameters with call_user_func_array() found here -> http://php.net/manual/en/function.call-user-func-array.php . What I want to do is nearly identical, but instead of a function, I want to call a PHP class with a variable number of parameters in it's constructor.
It would work something like the below, but I won't know the number of parameters, so I won't know how to instantiate the class.
<?php
//The class name will be pulled dynamically from another source
$myClass = '\Some\Dynamically\Generated\Class';
//The parameters will also be pulled from another source, for simplicity I
//have used two parameters. There could be 0, 1, 2, N, ... parameters
$myParameters = array ('dynamicparam1', 'dynamicparam2');
//The instantiated class needs to be called with 0, 1, 2, N, ... parameters
//not just two parameters.
$myClassInstance = new $myClass($myParameters[0], $myParameters[1]);
You can do the following using ReflectionClass
$myClass = '\Some\Dynamically\Generated\a';
$myParameters = array ('dynamicparam1', 'dynamicparam2');
$reflection = new \ReflectionClass($myClass);
$myClassInstance = $reflection->newInstanceArgs($myParameters);
PHP manual: http://www.php.net/manual/en/reflectionclass.newinstanceargs.php
Edit:
In php 5.6 you can achieve this with Argument unpacking.
$myClass = '\Some\Dynamically\Generated\a';
$myParameters = ['dynamicparam1', 'dynamicparam2'];
$myClassInstance = new $myClass(...$myParameters);
I implement this approach a lot when function args are > 2, rather then end up with an Christmas list of arguments which must be in a specific order, I simply pass in an associative array. By passing in an associative array, I can check for necessary and optional args and handle missing values as needed. Something like:
class MyClass
{
protected $requiredArg1;
protected $optionalArg1;
public function __construct(array $options = array())
{
// Check for a necessary arg
if (!isset($options['requiredArg1'])) {
throw new Exception('Missing requiredArg1');
}
// Now I can just localize
$requiredArg1 = $options['requiredArg1'];
$optionalArg1 = (isset($options['optionalArg1'])) ? $options['optionalArg1'] : null;
// Now that you have localized args, do what you want
$this->requiredArg1 = $requiredArg1;
$this->optionalArg1 = $optionalArg1;
}
}
// Example call
$class = 'MyClass';
$array = array('requiredArg1' => 'Foo!', 'optionalArg1' => 'Bar!');
$instance = new $class($array);
var_dump($instance->getRequiredArg1());
var_dump($instance->getOptionalArg1());
I highly recommend using an associative array, however it is possible to use a 0-index array. You will have to be extremely careful when constructing the array and account for indices that have meaning, otherwise you will pass in an array with offset args and wreck havoc with your function.
You can do that using func_get_args().
class my_class {
function __construct( $first = NULL ) {
$params = func_get_args();
if( is_array( $first ) )
$params = $first;
// the $params array will contain the
// arguments passed to the child function
foreach( $params as $p )
echo "Param: $p\n";
}
}
function my_function() {
$instance = new my_class( func_get_args() );
}
echo "you can still create my_class instances like normal:";
$instance = new my_class( "one", "two", "three" );
echo "\n\n\n";
echo "but also through my_function:";
my_function( "one", "two", "three" );
Basically, you simply pass the result of func_get_args to the constructor of your class, and let it decide whether it is being called with an array of arguments from that function, or whether it is being called normally.
This code outputs
you can still create my_class instances like normal:
Param: one
Param: two
Param: three
but also through my_function:
Param: one
Param: two
Param: three
Hope that helps.
I've found here
Is there a call_user_func() equivalent to create a new class instance?
the example:
function createInstance($className, array $arguments = array())
{
if(class_exists($className)) {
return call_user_func_array(array(
new ReflectionClass($className), 'newInstance'),
$arguments);
}
return false;
}
But can somebody tell me if there is an example for classes with protected constructors?

how to pass more arguments to php array_walk?

I want to know how to pass more arguments to my array_walk..
$addresses = array('www.google.com', 'www.yahoo.com', 'www.microsoft.com');
$a = 'hey';
$b = 'hey';
array_walk($addresses, array($this, '_handle'), $a, $b); // $a and $b parameters doesn't get passed
private function _handle($address,$a, $b) {
echo $address; // www.google.com
echo $a // 012
echo $b // 012
}
How do I pass parameters anyway? I have to pass more than 5 parameters.. please teach me.. thanks!
The third parameter is a mixed data type. If you have many parameters, I would suggest putting them into an Array - perhaps an associative array to name them. You'd then pull them back out of that param:
$addresses = array('www.google.com', 'www.yahoo.com', 'www.microsoft.com');
$params = array('first','second');
array_walk($addresses, array($this, '_handle'), $params);
private function _handle($address,$count, $params) {
echo $address; // www.google.com
echo $params[0]; // first
echo $params[1]; // second
}
It will only allow one argument for user data. I suggest passing your values as an array.
array_walk($addresses, array($this, '_handle'), array($a, $b));
The function passed to array_walk() takes 2-3 parameters.
Array Value (as a reference, if needed)
Array Key
Custom data (optional)
To pass multiple variables to array_walk pass an array.
array_walk($addresses, array($this, '_handle'), array('a'=>$a, 'b'=>$b));
private function _handle($address, $k, $data){
echo $address;
echo $data['a'];
echo $data['b'];
}
You can use the use keyword with an anonymous function like this:
Note: $custom_var is a mixed datatype so can be an array if you want to pass several values
$custom_var = 'something';
array_walk(
$array,
function( &$value, $key) use ( $custom_var ){
// Your code here, you can access the value of $custom_var
});

Does PHP allow named parameters so that optional arguments can be omitted from function calls?

Is it possible in PHP to specify a named optional parameter when calling a function/method, skipping the ones you don't want to specify (like in python)?
Something like:
function foo($a, $b = '', $c = '') {
// whatever
}
foo("hello", $c="bar"); // we want $b as the default, but specify $c
No, it is not possible (before PHP 8.0): if you want to pass the third parameter, you have to pass the second one. And named parameters are not possible either.
A "solution" would be to use only one parameter, an array, and always pass it... But don't always define everything in it.
For instance :
function foo($params) {
var_dump($params);
}
And calling it this way : (Key / value array)
foo([
'a' => 'hello',
]);
foo([
'a' => 'hello',
'c' => 'glop',
]);
foo([
'a' => 'hello',
'test' => 'another one',
]);
Will get you this output :
array
'a' => string 'hello' (length=5)
array
'a' => string 'hello' (length=5)
'c' => string 'glop' (length=4)
array
'a' => string 'hello' (length=5)
'test' => string 'another one' (length=11)
But I don't really like this solution :
You will lose the phpdoc
Your IDE will not be able to provide any hint anymore... Which is bad
So I'd go with this only in very specific cases -- for functions with lots of optional parameters, for instance...
PHP 8 was released on November 26, 2020 with a new feature called named arguments.
In this major version release, "named parameters" (aka "named arguments") afford developers some really cool new techniques when calling native and custom functions.
The custom function in this question can now be called with the first parameter (because there is no default for it) and then only the third parameter passed by using named parameters like this: (Demo)
function foo($a, $b = '', $c = '') {
echo $a . '&' . $b . '&' . $c;
}
foo("hello", c: "bar");
// output: hello&&bar
Notice that the second parameter did not need to be declared in the function call because it has a default value defined -- the default value is automatically used within the function body.
Part of the beauty of this new feature is that you don't need to be careful about the order of your named parameters -- the order of their declaration is irrelevant. foo(c: "bar", a: "hello"); works just the same. Having the ability to "skip" declarations and write declarative parameters will improve the readability of your scripts. The only downside of this new feature is that there will be a little bit more bloat in the function calls, but I (and many others) think the benefits outweigh this "cost".
Here is an example of a native function omitting the limit parameter, writing the parameters out of their normal order, and declaring a reference variable. (Demo)
echo preg_replace(
subject: 'Hello 7',
pattern: '/[a-z ]/',
count: $counted,
replacement: ''
)
. " & " . $counted;
// output: H7 & 5
There is more to tell about this new feature. You can even use an associative array to pass the named parameters to the function where the spread/splat operator can be used to unpack the data!
(*notice the slight difference in declaring the reference variable.) (Demo)
$params = [
'subject' => 'Hello 7', // normally third parameter
'pattern' => '/[a-z ]/', // normally first parameter
// 'limit' // normally fourth parameter, omitted for this demonstration; the default -1 will be used
'count' => &$counted, // normally fifth parameter
// ^-- don't forget to make it modifiable!
'replacement' => '', // normally second parameter
];
echo preg_replace(...$params) . " & " . $counted;
// same output as the previous snippet
For more information, here are a few leads that explain further about this feature and some common related errors: (I have no affiliation with the following sites)
https://wiki.php.net/rfc/named_params
https://stitcher.io/blog/php-8-named-arguments
https://stitcher.io/blog/why-we-need-named-params-in-php
No, PHP cannot pass arguments by name.
If you have a function that takes a lot of arguments and all of them have default values you can consider making the function accept an array of arguments instead:
function test (array $args) {
$defaults = array('a' => '', 'b' => '', 'c' => '');
$args = array_merge($defaults, array_intersect_key($args, $defaults));
list($a, $b, $c) = array_values($args);
// an alternative to list(): extract($args);
// you can now use $a, $b, $c
}
See it in action.
No, it isn't.
The only way you can somewhat do that is by using arrays with named keys and what not.
As of PHP 5.4 you have shorthand array syntax (not nessecary to specify arrays with cumbersome "array" and instead use "[]").
You can mimic named parameters in many ways, one good and simple way might be:
bar('one', ['a1' => 'two', 'bar' => 'three', 'foo' => 'four']);
// output: twothreefour
function bar ($a1, $kwargs = ['bar' => null, 'foo' => null]) {
extract($kwargs);
echo $a1;
echo $bar;
echo $foo;
}
You can keep the phpdoc and the ability to set defaults by passing an object instead of an array, e.g.
class FooOptions {
$opt1 = 'x';
$opt2 = 'y';
/* etc */
};
That also lets you do strict type checking in your function call, if you want to:
function foo (FooOptions $opts) {
...
}
Of course, you might pay for that with extra verbosity setting up the FooOptions object. There's no totally-free ride, unfortunately.
It's not exactly pretty, but it does the trick, some might say.
class NamedArguments {
static function init($args) {
$assoc = reset($args);
if (is_array($assoc)) {
$diff = array_diff(array_keys($assoc), array_keys($args));
if (empty($diff)) return $assoc;
trigger_error('Invalid parameters: '.join(',',$diff), E_USER_ERROR);
}
return array();
}
}
class Test {
public static function foobar($required, $optional1 = '', $optional2 = '') {
extract(NamedArguments::init(get_defined_vars()));
printf("required: %s, optional1: %s, optional2: %s\n", $required, $optional1, $optional2);
}
}
Test::foobar("required", "optional1", "optional2");
Test::foobar(array(
'required' => 'required',
'optional1' => 'optional1',
'optional2' => 'optional2'
));
Normally you can't but I think there a lot of ways to pass named arguments to a PHP function. Personally I relay on the definition using arrays and just call what I need to pass:
class Test{
public $a = false;
private $b = false;
public $c = false;
public $d = false;
public $e = false;
public function _factory(){
$args = func_get_args();
$args = $args[0];
$this->a = array_key_exists("a",$args) ? $args["a"] : 0;
$this->b = array_key_exists("b",$args) ? $args["b"] : 0;
$this->c = array_key_exists("c",$args) ? $args["c"] : 0;
$this->d = array_key_exists("d",$args) ? $args["d"] : 0;
$this->e = array_key_exists("e",$args) ? $args["e"] : 0;
}
public function show(){
var_dump($this);
}
}
$test = new Test();
$args["c"]=999;
$test->_factory($args);
$test->show();
live example here:
http://sandbox.onlinephpfunctions.com/code/d7f27c6e504737482d396cbd6cdf1cc118e8c1ff
If I have to pass 10 arguments, and 3 of them are the data I really need, is NOT EVEN SMART to pass into the function something like
return myfunction(false,false,10,false,false,"date",false,false,false,"desc");
With the approach I'm giving, you can setup any of the 10 arguments into an array:
$arr['count']=10;
$arr['type']="date";
$arr['order']="desc";
return myfunction($arr);
I have a post in my blog explaining this process in more details.
http://www.tbogard.com/2013/03/07/passing-named-arguments-to-a-function-in-php
With PHP, the order of arguments is what matters. You can't specify a particular argument out of place, but instead, you can skip arguments by passing a NULL, as long as you don't mind the value in your function having a NULL value.
foo("hello", NULL, "bar");
If you really really want, try the reflection.
And skip with null.
function getDefaultValueByNull($fn, $inputs) {
$ref = new ReflectionFunction($fn);
$args = array_map(function($p) {
return [
$p->getName(),
$p->isDefaultValueAvailable() ? $p->getDefaultValue() : NULL,
];
}, $ref->getParameters());
foreach($inputs as $i=>$val) { if ($val!==NULL) $args[$i][1] = $val; }
return array_column($args, 1, 0);
}
function sum($a=9, $b) {
extract(getDefaultValueByNull(__FUNCTION__, func_get_args()));
return $a+$b;
}
echo sum(NULL, 1); // 10
Here's what I've been using. A function definition takes one optional array argument which specifies the optional named arguments:
function func($arg, $options = Array()) {
$defaults = Array('foo' => 1.0,
'bar' => FALSE);
$options = array_merge($default, $options);
// Normal function body here. Use $options['foo'] and
// $options['bar'] to fetch named parameter values.
...
}
You can normally call without any named arguments:
func("xyzzy")
To specify an optional named argument, pass it in the optional array:
func("xyzzy", Array('foo' => 5.7))
No not really. There are a few alternatives to it you could use.
test(null,null,"hello")
Or pass an array:
test(array('c' => "hello"));
Then, the function could be:
function test($array) {
$c = isset($array[c]) ? $array[c] : '';
}
Or add a function in between, but i would not suggest this:
function ctest($c) { test('','',$c); }
I dont think so...
If you need to call, for example, the substr function, that has 3 params, and want to set the $length without set the $start, you'll be forced to do so.
substr($str,0,10);
a nice way to override this is to always use arrays for parameters
In very short, sometimes yes, by using reflection and typed variables. However I think this is probably not what you are after.
A better solution to your problem is probably to pass in the 3 arguments as functions handle the missing one inside your function yourself
<?php
function test(array $params)
{
//Check for nulls etc etc
$a = $params['a'];
$b = $params['b'];
...etc etc
}
You can't do it the python way. Anway, you could pass an associative array and than use the array entries by their name:
function test ($args=array('a'=>'','b'=>'','c'=>''))
{
// do something
}
test(array('c'=>'Hello'));
This doesn't reduce the typing, but at least it's more descriptive, having the arguments' names visible and readable in the call.
Here is a work around:
function set_param_defaults($params) {
foreach($params['default_values'] as $arg_name => $arg_value) {
if (!isset($params[$arg_name])) {
$params[$arg_name] = $arg_value;
}
}
return $params;
}
function foo($z, $x = null, $y = null) {
$default_values = ['x' => 'default value for x', 'y' => 'default value for y'];
$params = set_param_defaults(get_defined_vars());
print "$z\n";
print $params['x'] . "\n";
print $params['y'] . "\n";
}
foo('set z value', null, 'set y value');
print "\n";
foo('set z value', 'set x value');
ALTERNATIVELY:
Personally I would go with this method.
function foo($z, $x_y) {
$x_y += ['x' => 'default value for x', 'y' => 'default value for y'];
print "$z\n";
print $x_y['x'] . "\n";
print $x_y['y'] . "\n";
}
foo('set z value', ['y' => 'set y value']);
print "\n";
foo('set z value', ['x' => 'set x value']);
Print outs for both examples.
1st call:
set z value
default value for x
set y value
2nd call:
set z value
set x value
default value for y
Just use the associative array pattern Drupal uses. For optional defaulted arguments, just accept an $options argument which is an associative array. Then use the array + operator to set any missing keys in the array.
function foo ($a_required_parameter, $options = array()) {
$options += array(
'b' => '',
'c' => '',
);
// whatever
}
foo('a', array('c' => 'c’s value')); // No need to pass b when specifying c.

Categories