Apologies for the newbie question but i have a function that takes two parameters one is an array one is a variable function createList($array, $var) {}. I have another function which calls createList with only one parameter, the $var, doSomething($var); it does not contain a local copy of the array. How can I just pass in one parameter to a function which expects two in PHP?
attempt at solution :
function createList (array $args = array()) {
//how do i define the array without iterating through it?
$args += $array;
$args += $var;
}
If you can get your hands on PHP 5.6+, there's a new syntax for variable arguments: the ellipsis keyword.
It simply converts all the arguments to an array.
function sum(...$numbers) {
$acc = 0;
foreach ($numbers as $n) {
$acc += $n;
}
return $acc;
}
echo sum(1, 2, 3, 4);
Doc: ... in PHP 5.6+
You have a couple of options here.
First is to use optional parameters.
function myFunction($needThis, $needThisToo, $optional=null) {
/** do something cool **/
}
The other way is just to avoid naming any parameters (this method is not preferred because editors can't hint at anything and there is no documentation in the method signature).
function myFunction() {
$args = func_get_args();
/** now you can access these as $args[0], $args[1] **/
}
You can specify no parameters in your function declaration, then use PHP's func_get_arg or func_get_args to get the arguments.
function createList() {
$arg1 = func_get_arg(0);
//Do some type checking to see which argument it is.
//check if there is another argument with func_num_args.
//Do something with the second arg.
}
Related
I have been given a API which I am currently back engineering. there is one function in particular that gives me troubles with fully understanding its purpose/use.
private function split($data, Callable $callback)
{
$split = array();
if ($data) {
$split = array_map(function($joined) use ($callback) {
return $callback(explode('::', $joined));
}, explode(',', $data));
}
return $split;
}
I dont fully understand the concept of Callable, and function within array_map, function($joined) then this function USE callable variable, Could someone explain this concept form me please
A Callable argument is an argument that you can call ! As you can see in the code, the argument $callback is used like a function: $callback(...)
This is called high-order programming and this is really useful in certain cases. A simple example: Let's say you have to code a function that adds 2 and another function that multiplies by 2 every elements of an array. A simple but verbose way to do that is:
function multiply($array) {
$results = array();
foreach ($array as $number) {
$results[] = $number * 2;
}
return $results;
}
function add($array) {
$results = array();
foreach ($array as $number) {
$results[] = $number + 2;
}
return $results;
}
A lot of code is the same in the 2 functions. High-order programming is useful in this case, what you can do is create a function apply($function, $array) that apply the function $function to all the elements of $array and returns an array with the result.
function apply($function, $array) {
$results = array();
foreach ($array as $number) {
$results[] = $function($number);
}
return $results;
}
Now, if you want to multiply all the elements by 2 or add 2, you simply do:
function multiply($array) {
return apply(function($number) {
return $number * 2;
}, $array);
}
function add($array) {
return apply(function($number) {
return $number + 2;
}, $array);
}
You see, we give a function as an argument to the apply function. This function (called $function in apply) is applied to all the elements of $array, and apply returns the results (called $results).
The PHP function array_map does exactly the same thing. When your code calls array_map, it gives a function that takes one argument (the element of the array to process) and returns the processed element (here, it simply applies the function $callback to it).
I have a body function and a function called within the first one.
As can be seen below I don't change the parameters name while using in the second function.
Is it necessary to change the params names for use inside _display_bar();? What are the side effects if I don't?
function main_func($form, &$form_state, $key, $code) {
$output = '';
...
$output .= _display_navbar($trans, $status_names);
return $output
}
function _display_navbar($trans, $status_names) {
$trans = 'bla';
$status_names = 'another bla';
$bar = $trans . ':' .$status_names;
return $bar;
};
Variables have function scope. Unless you specifically declare otherwise, the names are only valid inside the function. They do not bleed into other scopes. There are no side effects. You don't need to use unique names.
It actually does not matter. But you better should not have the same names - it is confusing. Let me give you an example. $s will have 3 after the first function call to sum; 7 after the second function call to sum. The parameters did not have the same name as the function parameter names.
To answer your question fully - there are absolutely no side effects.
function main()
{
$a = 1;
$b = 2;
$s = sum($a, $b);
$d = 3;
$e = 4;
$s = sum($d, $e);
}
function sum($first, $second)
{
$ret = $first + $second;
return $ret;
}
Once a variable is passed to a function, the name of the variable is not important. Only the data is passed through. So your function could be this:
function _display_navbar($foo, $bar) {
$foo = 'bla';
return $bar;
}
And it will return what ever was passed as the second parameter regardless of what the variable name was.
The names you pass as function arguments must be in scope at the point they are called.
It doesn't matter if they have the same name as the formal function parameters, but you must recognise that just because they have the same name doesn't mean that brings them into scope.
So, in your code:
function main_func($form, &$form_state, $key, $code) {
$output = '';
...
$output .= _display_navbar($trans, $status_names);
the last line will be incorrect, unless $trans and $status_names are in scope at the time.
I have a code problem which stems from the fact that I am using certain libraries of code I cannot change.
I use the following code to pass execution of any undefined methods to another class, and it works fine but it seems like a waste doubling up.
Any suggestions?
Basically I want to know if it's possible to pass an unknown number of parameters to a method (without using call_user_func_array(), just in case they need to be passed by reference). I am not asking how to use func_get_args(), rather the reverse.
Or should I just allow for a few more arguments in the first logic path (the list() code)?
class Foo {
__construct() {
$this->external = new ClassThatIHaveNoControlOver();
}
function bar($name) {
return 'Hi '.$name;
}
function __call($method, $arguments) {
if (count($arguments) < 3) {
// call_user_func_array won't pass by reference, as required by
// ClassThatIHaveNoControlOver->foobar(), so calling the function
// directly for up to 2 arguments, as I know that foobar() will only
// take 2 arguments
list($first, $second) = $arguments + Array(null, null);
return $this->external->$method($first, $second);
} else {
return call_user_func_array(array($this->external, $method), $arguments);
}
}
}
$foo = new Foo();
$firstName = 'Bob';
$lastName = 'Brown';
echo $foo->bar($firstName); // returns Hi Bob as expected
echo $foo->foobar($firstName, $lastName); // returns whatever
// ClassThatIHaveNoControlOver()->foobar() is meant to return
EDIT
Just to clarify, I know I can use this method to rejig the parameters as references, but that would mean passing everything as a reference, even if the method didn't require it - something I was trying to avoid, but seems unlikely at the moment.
As commented in the thread question post's comments this is an example and not necessarily (likely) best practice.
//Some vars
$foo = "shoe";
$bar = "bucket";
//Array of references
$arr = Array(&$foo, &$bar);
//Show that changing variable value affects array content
$foo = "water";
echo $arr[0];
//Sample function
function fooBar($a)
{
$a[0] = "fire";
}
//Call sample function
call_user_func("fooBar",$arr);
//Show that function changes both array contents and variable value by reference
echo $arr[0];
echo $foo;
Expanding a bit on the discussion, again not the most industry standard approach but it'll do the job.
function pushRefOnArray(&$arr, &$var, $key = false)
{
if(isset($key))
$arr[$key] = &$var;
else
$arr[] = &$var;
}
Essentially you can dynamically build your array and call pushRefToArray() any time you need to pass an item to be passed as reference rather than by value.
You could use something like this:
public function __call($method, $params = array()) {
switch (count($params)) {
case 0:
return $this->external->{$method}();
case 1:
return $this->external->{$method}($params[0]);
case 2:
return $this->external->{$method}($params[0], $params[1]);
case 3:
return $this->external->{$method}($params[0], $params[1], $params[2]);
default:
return call_user_func_array(array(&this->external, $method), $params);
}
}
I started off OOP with Java, and now I'm getting pretty heavy into PHP. Is it possible to create multiples of a function with different arguments like in Java? Or will the interpreted / untyped nature of the language prevent this and cause conflicts?
Everyone else has answers with good code explanations. Here is an explanation in more high level terms: Java supports Method overloading which is what you are referring to when you talk about function with the same name but different arguments. Since PHP is a dynamically typed language, this is not possible. Instead PHP supports Default arguments which you can use to get much the same effect.
If you are dealing with classes you can overload methods with __call() (see Overloading) e.g.:
class Foo {
public function doSomethingWith2Parameters($a, $b) {
}
public function doSomethingWith3Parameters($a, $b, $c) {
}
public function __call($method, $arguments) {
if($method == 'doSomething') {
if(count($arguments) == 2) {
return call_user_func_array(array($this,'doSomethingWith2Parameters'), $arguments);
}
else if(count($arguments) == 3) {
return call_user_func_array(array($this,'doSomethingWith3Parameters'), $arguments);
}
}
}
}
Then you can do:
$foo = new Foo();
$foo->doSomething(1,2); // calls $foo->doSomethingWith2Parameters(1,2)
$foo->doSomething(1,2,3); // calls $foo->doSomethingWith3Parameters(1,2,3)
This might not be the best example but __call can be very handy sometimes. Basically you can use it to catch method calls on objects where this method does not exist.
But it is not the same or as easy as in Java.
Short answer: No. There can only be one function with a given name.
Longer answer: You can do this by creating a convoluted include system that includes the function with the right number of arguments. Or, better yet, you can take advantage of PHP allowing default values for parameters and also a variable amount of parameters.
To take advantage of default values just assign a value to a parameter when defining the function:
function do_something($param1, $param2, $param3 = 'defaultvaule') {}
It's common practice to put parameters with default values at the end of the function declaration since they may be omitted when the function is called and makes the syntax for using them clearer:
do_something('value1', 'value2'); // $param3 is 'defaultvaule' by default
You can also send a variable amount of parameters by using func_num_args() and func_get_arg() to get the arguments:
<?php
function dynamic_args() {
echo "Number of arguments: " . func_num_args() . "<br />";
for($i = 0 ; $i < func_num_args(); $i++) {
echo "Argument $i = " . func_get_arg($i) . "<br />";
}
}
dynamic_args("a", "b", "c", "d", "e");
?>
Following isn't possible with php
function funcX($a){
echo $a;
}
function funcX($a,$b){
echo $a.$b;
}
Instead do this way
function funcX($a,$b=null){
if ($b === null) {
echo $a; // even though echoing 'null' will display nothing, I HATE to rely on that
} else {
echo $a.$b;
}
}
funcX(1) will display 1, func(1,3) will display 13
Like everyone else said, it's not supported by default. Felix's example using __call() is probably the best way.
Otherwise, if you are using classes that inherit from each other you can always overload the method names in your child classes. This also allows you to call the parent method.
Take these classes for example...
class Account {
public function load($key,$type) {
print("Loading $type Account: $key\n");
}
}
class TwitterAccount extends Account {
public $type = 'Twitter';
public function load($key) {
parent::load($key,$this->type);
}
}
Then you can call them like so...
$account = new Account();
$account->load(123,'Facebook');
$twitterAccount = new TwitterAccount();
$twitterAccount->load(123);
And your result would be...
Loading Facebook Account: 123
Loading Twitter Account: 123
No this isn't possible, because PHP cannot infer from the arguments which function you want (you don't specify which types you expect). You can, however, give default values to arguments in php.
That way the caller can give different amounts of arguments. This will call the same function though.
Example is:
function test($a = true)
This gives a default of true if 0 arguments are given, and takes the calling value if 1 argument is given.
I know it's a bit old issue, but since php56 you can:
function sum(...$numbers) {
$acc = 0;
foreach ($numbers as $n) {
$acc += $n;
}
return $acc;
}
echo sum(1, 2, 3, 4);
ref: http://php.net/manual/en/functions.arguments.php
Overloading is not possible in PHP but you can get around it to some extend with default parameter values as explained in other responses.
The limit to this workaround is when one wants to overload a function/method according to the parameter types. This is not possible in PHP, one need to test the parameter types yourself, or write several functions. The functions min and max are a good example of this : if there is one parameter of array type it returns the min/max of the array, otherwise it returns the min/max of the parameters.
I had the idea of something like:
function process( $param1 , $type='array' ) {
switch($type) {
case 'array':
// do something with it
break;
case 'associative_array':
// do something with it
break;
case 'int_array':
// do something with it
break;
case 'string':
// do something with it
break;
// etc etc...
}
}
I have got 2 methods, getArrayWithoutKey which will output all the entries of an array without supplying any key value. The second method getArrayWithKey will output a particular entry from the same array using a key value. Which is why I have used method overloading there.
class abcClass
{
private $Arr=array('abc'=>'ABC Variable', 'def'=>'Def Variable');
public function setArr($key, $value)
{
$this->Arr[$key]=$value;
}
private function getArrWithKey($key)
{
return $this->Arr[$key];
}
private function getArrWithoutKey()
{
return $this->Arr;
}
//Method Overloading in PHP
public function __call($method, $arguments)
{
if($method=='getArr')
{
if(count($arguments)==0)
{
return $this->getArrWithoutKey();
}
elseif(count($arguments)==1)
{
return $this->getArrWithKey(implode(',' , $arguments));
}
}
}
}
/* Setting and getting values of array-> Arr[] */
$obj->setArr('name', 'Sau');
$obj->setArr('address', 'San Francisco');
$obj->setArr('phone', 7777777777);
echo $obj->getArr('name')."<br>";
print_r( $obj->getArr());
echo "<br>";
I would like to write a function that (amongst other things) accepts a variable number of arguments and then passes them to sprintf().
For example:
<?php
function some_func($var) {
// ...
$s = sprintf($var, ...arguments that were passed...);
// ...
}
some_func("blah %d blah", $number);
?>
How do I do this in PHP?
function some_func() {
$args = func_get_args();
$s = call_user_func_array('sprintf', $args);
}
// or
function some_func() {
$args = func_get_args();
$var = array_shift($args);
$s = vsprintf($var, $args);
}
The $args temporary variable is necessary, because func_get_args cannot be used in the arguments list of a function in PHP versions prior to 5.3.
use a combination of func_get_args and call_user_func_array
function f($var) { // at least one argument
$args = func_get_args();
$s = call_user_func_array('sprintf', $args);
}
Or better yet (and a bit safer too):
function some_func(string $fmt, ... $args) {
$s = vsprintf($fmt, $args);
}
This is PHP 7.4, not sure if it works in earlier versions.
use $numargs = func_num_args();
and func_get_arg(i) to retrieve the argument
Here is the way:
http://www.php.net/manual/en/functions.arguments.php#functions.variable-arg-list
basically, you declare your function as usual, without parameters, then you call func_num_args() to find out how many arguments they passed you, and then you get each one by calling func_get_arg() or func_get_args(). That's easy :)