PHP - How to split array into variables and pass to a function? - php

There are a few functions with different number of parameters in PHP. I have no idea which function is going to be called, but the function and its parameter is passed to the calling function as array like this
function func1($a,$b){...}
function func2($a){...}
$calls = [func1=>[arg1, arg2], func2=>[arg1]]
I need to call each function with its parameters. I don't know how to pass the parameters as distinct variables. This my code
$func_names = array_keys($calls);
$i = 0;
foreach($calls as $call){
$func_names[$i]($calls[$func_names[$i++]]);
//$func_names[$i]($call); same as above line
}
In each iteration array of arguments of each function is passed to the function not each item of the array separately. How can I solve this problem?
thanks

Use call_user_func_array
mixed call_user_func_array ( callable $callback , array $param_arr )
Example from the linked PHP manual -
<?php
function foobar($arg, $arg2) {
echo __FUNCTION__, " got $arg and $arg2\n";
}
class foo {
function bar($arg, $arg2) {
echo __METHOD__, " got $arg and $arg2\n";
}
}
// Call the foobar() function with 2 arguments
call_user_func_array("foobar", array("one", "two"));
// Call the $foo->bar() method with 2 arguments
$foo = new foo;
call_user_func_array(array($foo, "bar"), array("three", "four"));
?>

<?php
function a($foo) {
echo $foo, "\n";
}
function b($bar, $baz) {
echo $bar, ' and ', $baz, "\n";
}
$calls = ['a'=>['apples'], 'b'=>['bananas','banjos']];
foreach($calls as $k => $v) $k(...$v);
Output:
apples
bananas and banjos

Related

Pass by reference when using splat operator (...)

I have two functions. One of them receive and modify some values in an array that is passed by reference.
function dostuff ($param1, $param2, &$arr) {
//...
//add new elements to $arr
}
The other, which is a method in a class, that wraps the first one:
class Wrapper
{
public function foo (...$args) {
return dostuff(...$args);
}
}
However, if I pass the array to 'foo', the array stays unchanged.
I've tried to declare foo(... &$args) with an & but this led to an syntax error.
Is there a way to pass arguments by reference when using splat operator in PHP?
For PHP 8.x Versions https://3v4l.org/9ivmL
Do it like this:
<?php
class Wrapper
{
public function foo (&...$args) {
return $this->dostuff(...$args);
}
public function dostuff($param1, $param2, &$arr) {
$arr[] = $param1;
$arr[] = $param2;
return count($arr);
}
}
$values = [1,2];
$a=3;
$b=4;
$obj = new Wrapper();
#all parameter must be variables here because there are by ref now
$count = $obj->foo($a,$b, $values);
echo "Elements count: $count\r\n";
print_r($values); //Expected [1,2,3,4]
Output
Elements count: 4
Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 4
)
See: https://www.php.net/manual/en/functions.arguments.php Example #13

PHP Redefine a closure with bind() and its scope [duplicate]

When using anonymous functions in PHP, you can easily use variables from right outside of its scope by using the use() keyword.
In my case the anonymous functions are already defined somewhere, but called later on (somewhere else) in a class.
The following piece of code is to illustrate the idea:
<?php
$bla = function ( $var1 ) use ($arg)
{
echo $var1;
};
class MyClass
{
private $func;
public function __construct ( $func )
{
$this->func = $func;
}
public function test ( $arg )
{
$closure = $this->func;
$closure ( 'anon func' );
}
}
$c = new MyClass($bla);
$c->test ( 'anon func' );
What i'm doing is i create an anonymous function and store that in a variable. I pass that variable to the method of a class and that is where i want to run the anonymous function.
But i can't use the use() keyword to get the $arg parameter from the method this way. Because the anonymous function was declared outside of the method.
But i really need a way to get the variables from the method where the anonymous function is run from. Is there a way to do that, when the anonymous function is declared somewhere else..?
The point of the use keyword is to inherit/close over a particular environment state from the parent scope into the Closure when it's defined, e.g.
$foo = 1;
$fn = function() use ($foo) {
return $foo;
};
$foo = 2;
echo $fn(); // gives 1
If you want $foo to be closed over at a later point, either define the closure later or, if you want $foo to be always the current value (2), pass $foo as a regular parameter.
FWIW, you can do it if you use a use reference (php.net ex 3.3) and a global, ugly since it uses globals, but just to put it out there:
<?php
$bla = function ( $var1 ) use (&$arg)
{
return "var1:$var1, arg:$arg";
};
class MyClass
{
private $func;
public function __construct ( $func )
{
$this->func = $func;
}
public function test ( $param )
{
global $arg;
$arg=$param;
$closure = $this->func;
return $closure ( 'anon func' );
}
}
$c = new MyClass($bla);
echo $c->test ( 'bla bla' ); //var1:anon func, arg:bla bla

Use variables inside an anonymous function, which is defined somewhere else

When using anonymous functions in PHP, you can easily use variables from right outside of its scope by using the use() keyword.
In my case the anonymous functions are already defined somewhere, but called later on (somewhere else) in a class.
The following piece of code is to illustrate the idea:
<?php
$bla = function ( $var1 ) use ($arg)
{
echo $var1;
};
class MyClass
{
private $func;
public function __construct ( $func )
{
$this->func = $func;
}
public function test ( $arg )
{
$closure = $this->func;
$closure ( 'anon func' );
}
}
$c = new MyClass($bla);
$c->test ( 'anon func' );
What i'm doing is i create an anonymous function and store that in a variable. I pass that variable to the method of a class and that is where i want to run the anonymous function.
But i can't use the use() keyword to get the $arg parameter from the method this way. Because the anonymous function was declared outside of the method.
But i really need a way to get the variables from the method where the anonymous function is run from. Is there a way to do that, when the anonymous function is declared somewhere else..?
The point of the use keyword is to inherit/close over a particular environment state from the parent scope into the Closure when it's defined, e.g.
$foo = 1;
$fn = function() use ($foo) {
return $foo;
};
$foo = 2;
echo $fn(); // gives 1
If you want $foo to be closed over at a later point, either define the closure later or, if you want $foo to be always the current value (2), pass $foo as a regular parameter.
FWIW, you can do it if you use a use reference (php.net ex 3.3) and a global, ugly since it uses globals, but just to put it out there:
<?php
$bla = function ( $var1 ) use (&$arg)
{
return "var1:$var1, arg:$arg";
};
class MyClass
{
private $func;
public function __construct ( $func )
{
$this->func = $func;
}
public function test ( $param )
{
global $arg;
$arg=$param;
$closure = $this->func;
return $closure ( 'anon func' );
}
}
$c = new MyClass($bla);
echo $c->test ( 'bla bla' ); //var1:anon func, arg:bla bla

How to pass argument in function?

i have function like this.
function load($name, $arg1, $arg2, $arg3, $arg4){
$this->$name = new $name($arg1, $arg2, $arg3, $arg4);
}
the load() method will load some class and set it as class property and the infinite arguments, depend in the class they assigned.
another example if i only set method $this->load with 3 argument, the this what will happen in the process
function load($name, $arg1, $arg2){
$this->$name = new $name($arg1, $arg2);
}
it is possible do something like that?
You can use combination of func_get_args(), ReflectionClass and the help of this comment like this:
function load(){
$args = func_get_args();
if( !count( $args)){
throw new Something();
}
$name = array_shift( $args);
$class = new ReflectionClass($name);
$this->$name = $class->newInstanceArgs($args);
}
An easier way of handling this is to use an array for the $arg variables. The other constructors dynamically called (new $name()) would then need to accept an array as their input as well, and you can simply pass through the array of parameters:
// Params in an array
$params = array(1,2,3,4,5);
// Pass into the load() function
function load($name, $params) {
// And pass them through to the dynamic constructor
$this->$name = new $name($params);
}
Unless you set default values on the arguments, you must pass in values when the function is called:
function load($name, $arg1, $arg2, $arg3, $arg4){
load('x'); // fails, didn't specify args 1->4
but with defaults:
function load($name, $arg1, $arg2 = null, $arg3 = null, $arg4 = null){
load('x', 'y'); // works, args 2->4 are optional
load('x'); // fails, didn't specify arg1
load('x', 'y', 'z'); // works, args 3->4 are null.
There are other options - pass in option arguments in an array, or use func_get_arg()
function load($name) {
load('x', 'y', 'z') // not an error, use func_get_args/func_num_args to get the extras
func_get_args() might be what you're looking for. From the PHP Docs:
<?php
function foo()
{
$numargs = func_num_args();
echo "Number of arguments: $numargs<br />\n";
if ($numargs >= 2) {
echo "Second argument is: " . func_get_arg(1) . "<br />\n";
}
$arg_list = func_get_args();
for ($i = 0; $i < $numargs; $i++) {
echo "Argument $i is: " . $arg_list[$i] . "<br />\n";
}
}
foo(1, 2, 3);
?>
The above example will output:
Number of arguments: 3<br />
Second argument is: 2<br />
Argument 0 is: 1<br />
Argument 1 is: 2<br />
Argument 2 is: 3<br />
There is a way to define a function with a truly variable-size arguments in PHP. You need to use func_get_args function in your function:
function load() {
$args = fnc_get_args();
$name = $args[0];
$arg1 = $args[1];
...
}
You'll need to then determine what/how to call next.

Reference to static method in PHP?

In PHP, I am able to use a normal function as a variable without problem, but I haven't figured out how to use a static method. Am I just missing the right syntax, or is this not possible?
(EDIT: the first suggested answer does not seem to work. I've extended my example to show the errors returned.)
function foo1($a,$b) { return $a/$b; }
class Bar
{
static function foo2($a,$b) { return $a/$b; }
public function UseReferences()
{
// WORKS FINE:
$fn = foo1;
print $fn(1,1);
// WORKS FINE:
print self::foo2(2,1);
print Bar::foo2(3,1);
// DOES NOT WORK ... error: Undefined class constant 'foo2'
//$fn = self::foo2;
//print $fn(4,1);
// DOES NOT WORK ... error: Call to undefined function self::foo2()
//$fn = 'self::foo2';
//print $fn(5,1);
// DOES NOT WORK ... error: Call to undefined function Bar::foo2()
//$fn = 'Bar::foo2';
//print $fn(5,1);
}
}
$x = new Bar();
$x->UseReferences();
(I am using PHP v5.2.6 -- does the answer change depending on version too?)
PHP handles callbacks as strings, not function pointers. The reason your first test works is because the PHP interpreter assumes foo1 as a string. If you have E_NOTICE level error enabled, you should see proof of that.
"Use of undefined constant foo1 - assumed 'foo1'"
You can't call static methods this way, unfortunately. The scope (class) is relevant so you need to use call_user_func instead.
<?php
function foo1($a,$b) { return $a/$b; }
class Bar
{
public static function foo2($a,$b) { return $a/$b; }
public function UseReferences()
{
$fn = 'foo1';
echo $fn(6,3);
$fn = array( 'self', 'foo2' );
print call_user_func( $fn, 6, 2 );
}
}
$b = new Bar;
$b->UseReferences();
In php 5.2, you can use a variable as the method name in a static call, but to use a variable as the class name, you'll have to use callbacks as described by BaileyP.
However, from php 5.3, you can use a variable as the class name in a static call. So:
class Bar
{
public static function foo2($a,$b) { return $a/$b; }
public function UseReferences()
{
$method = 'foo2';
print Bar::$method(6,2); // works in php 5.2.6
$class = 'Bar';
print $class::$method(6,2); // works in php 5.3
}
}
$b = new Bar;
$b->UseReferences();
?>
You could use the full name of static method, including the namespace.
<?php
function foo($method)
{
return $method('argument');
}
foo('YourClass::staticMethod');
foo('Namespace\YourClass::staticMethod');
The name array array('YourClass', 'staticMethod') is equal to it. But I think the string may be more clear for reading.
In PHP 5.3.0, you could also do the following:
<?php
class Foo {
static function Bar($a, $b) {
if ($a == $b)
return 0;
return ($a < $b) ? -1 : 1;
}
function RBar($a, $b) {
if ($a == $b)
return 0;
return ($a < $b) ? 1 : -1;
}
}
$vals = array(3,2,6,4,1);
$cmpFunc = array('Foo', 'Bar');
usort($vals, $cmpFunc);
// This would also work:
$fooInstance = new Foo();
$cmpFunc = array('fooInstance', 'RBar');
// Or
// $cmpFunc = array('fooInstance', 'Bar');
usort($vals, $cmpFunc);
?>
Coming from a javascript background and being spoiled by it, I just coded this:
function staticFunctionReference($name)
{
return function() use ($name)
{
$className = strstr($name, '::', true);
if (class_exists(__NAMESPACE__."\\$className")) $name = __NAMESPACE__."\\$name";
return call_user_func_array($name, func_get_args());
};
}
To use it:
$foo = staticFunctionReference('Foo::bar');
$foo('some', 'parameters');
It's a function that returns a function that calls the function you wanted to call. Sounds fancy but as you can see in practice it's piece of cake.
Works with namespaces and the returned function should work just like the static method - parameters work the same.
This seems to work for me:
<?php
class Foo{
static function Calc($x,$y){
return $x + $y;
}
public function Test(){
$z = self::Calc(3,4);
echo("z = ".$z);
}
}
$foo = new Foo();
$foo->Test();
?>
In addition to what was said you can also use PHP's reflection capabilities:
class Bar {
public static function foo($foo, $bar) {
return $foo . ' ' . $bar;
}
public function useReferences () {
$method = new ReflectionMethod($this, 'foo');
// Note NULL as the first argument for a static call
$result = $method->invoke(NULL, '123', 'xyz');
}
}
"A member or method declared with static can not be accessed with a variable that is an instance of the object and cannot be re-defined in an extending class"
(http://theserverpages.com/php/manual/en/language.oop5.static.php)

Categories