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>";
Related
I want to do something like this:
I have a function like this that I don't know what exactly inside it, I just know that the function should have a parameter and one return, it may have if statement, foreach or anything. I want to get function find that parameter and return, and specify it's code:
function a($param) {
if($param > 1) {
return $param;
}
}
and I want to pass this function to another function and edit it and then call it:
function b(a($param)) {
// get function code
// change return in that function to something else like echo
// specify if statements and anything else and change to what I want
// and then call it and use it
}
Is this possible in php?
Is this possible in php?
Yes, that is called code re-use. The idea is to re-use the existing function but not modifying it's code. You can have your function, too, thought.
Let's take the echo example as it's that straight forward:
echo a($param);
Done.
Now that is perhaps too trivial in your case. So why not write a function your own?:
function b($param) {
$result = a($param);
// ... do whatever you want with the result ...
return $result; // finally return.
}
And then:
echo b($param); // use your function instead of the other.
This is a common way to re-use the code of functions within your own code.
If the original function is not doing what you need, take a different one that does or communicate with its author(s) to raise your issue(s).
Now what if it is not always a() but maybe a1(), a2(), ..., aN() to be used in b()?
One way to handle this is to abstract from a() by making it a function parameter of b():
function b(callable $a, $param) {
$result = $a($param);
// ... do whatever you want with the result ...
return $result; // finally return.
}
Now b() can be called with any kind-of-a() function and its $param.
This might not fully suffice in your case but perhaps opens up a direction you can benefit from.
Let's see.
Perhaps the additional parameter $a stands in the way when calling b().
Previously it was:
echo a($param);
Then:
echo b($param);
And it now became:
$a = 'a' . random_int(1, 99); // $a could be any-kind-of-a()
// ...
echo b($a, $param);
Now similar to having a function as a parameter to make it "dynamic", it is also possible in PHP to have it as a return value: A function that returns a function:
function b_of_a(callable $a): callable {
// b()'s original implementation (enclosing $a)
return function ($param) use ($a) {
$result = $a($param);
// ... do whatever you want with the result ...
return $result; // finally return.
};
};
Similar to a() -> $a() there is now b() -> $b():
$a = 'a' . random_int(1, 99); // $a could be any-kind-of-a()
// ...
$b = b_of_a($a); // b() with any-kind-of-a() as $b
// ...
echo $b($param);
What were fixed function names in the original code have become variables you can pass around. The way both the kind-of-a() and the kind-of-b() function calls are preserved: with the single parameter.
And while the code of b() is fixed, what is a() within it, can be injected as a parameter.
RT
function 1 :
$class->$func()
function 2:
//Simple callback
call_user_func($func)
//Static class method call
call_user_func(array($class,$func))
//Object method call
$class = new MyClass();
call_user_func(array($class, $func));
Is there a difference? I want to see the sourcecode(https://github.com/php/php-src) should we do?
call_user_func_array is very slow performance-wise, that's why in many cases you want to go with explicit method call. But, sometimes you want to pass arbitrary number of arguments passed as an array, e.g.
public function __call($name, $args) {
$nargs = sizeof($args);
if ($nargs == 0) {
$this->$name();
}
elseif ($nargs == 1) {
$this->$name($args[0]);
}
elseif ($nargs == 2) {
$this->$name($args[0], $args[1]);
}
#...
// you obviously can't go through $nargs = 0..10000000,
// so at some point as a last resort you use call_user_func_array
else {
call_user_func_array(array($this,$name), $args);
}
}
I'd go with checking $nargs up to 5 (it's usually unlikely that a function in PHP accepts more than 5 arguments, so in most cases we will call a method directly without using call_user_func_array which is good for performance)
The result of $class->method($arg) is the same as call_user_func_array(array($class,'method'), array($arg)), but the first one is faster.
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 have the following function:
<?php
class Test{
function myFunction(){
return array('first','second','third');
}
}
?>
And I can print out the elements of the array:
$var=new Test();
$varr=$var->myFunction();
print($varr[1]);
Is there a way to condense this statement so I don't have to assign $var->myFunction() to a second variable (in this case $varr)?
PHP does not support this very well (as of PHP 5.3) as Tim Cooper already highlighted. So you need to think twice if you really need to have this compacted.
You can do things quite dynamically e.g. by return an ArrayObject instead of an array:
class Test
{
function myFunction()
{
return new ArrayObject(array('first','second','third'), 3);
}
}
$var = new Test();
print($var->myFunction()->{1});
Which will decorate the array data with some additional methods and ways of accessing. Another way would be for functions w/o parameter to fool the PHP parser and offer a property instead of a function dynamically:
class Test
{
function myFunction()
{
return array('first','second','third');
}
public function __get($name)
{
return $this->$name();
}
}
$var = new Test();
print($var->myFunction[1]);
But I don't know if this is really useful in an application.
So check your motivation why you want to compact the code and then decide on your own.
In PHP 5.4 you'll be able to do:
$varr=$var->myFunction()[1];
Until then, using list might help out:
list(,$varr) = $var->myFunction();
Another solution is to modify your method to accept an optional index of the item to return:
function myFunction($index = null){
$arr = array('first','second','third');
return $index == null ? $arr : $arr[$index];
}
$varr = $var->myFunction(1);
Can I have two methods sharing the same name, but with different arguments?
One would be public static and would take 2 arguments, the other one just public and takes only one argument
example
class product{
protected
$product_id;
public function __construct($product_id){
$this->product_id = $product_id;
}
public static function getPrice($product_id, $currency){
...
}
public function getPrice($currency){
...
}
}
No. PHP does not support classic overloading. (It does implement something else that is called overloading.)
You can get the same result by using func_get_args() and it's related functions though:
function ech()
{
$a = func_get_args();
for( $t=0;$t<count($a); $t++ )
{
echo $a[$t];
}
}
I'm just giving you the super lazy option:
function __call($name, $args) {
$name = $name . "_" . implode("_", array_map("gettype", $args)));
return call_user_func_array(array($this, $name), $args);
}
That would for example invoke the real function name getPrice_string_array for two parameters of that type. That's sort of what languages with real method signature overloading support would do behind the scenes.
Even lazier would be just counting the arguments:
function __callStatic($name, $args) {
$name = $name . "_" . count($args);
return call_user_func_array(array($this, $name), $args);
}
That would invoke getPrice_1 for 1 argument, or getPrice_2 for, you guessed it, two arguments. This might already suffice for most use cases. Of course you can combine both alternatives, or make it more clever by search for all alternative real method names.
If you want to keep your API pretty and user-friendly implementing such elaborate workarounds is acceptable. Very much so.
PHP currently doesn't support overloading in known way, but you can still achieve your goal by using magic methods.
From PHP5 manual: overloading.
You could, kind of...
I consider it very much "hack" solutions, but you could make a single function and assign a standard value, that wouldn't otherwise be okay to use, to the parameters as needed. Then if you do not pass the function a certain parameter, it will be set to fx "-1".
public function getPrice($product_id = "-1", $currency) {
if($product_id = "-1") {
//do something
}else {
//do something
}
}
Or if you really need one method to be static, you can make a method that evaluates which method to call and call that instead of your getPrice:
public function whichGetPrice($product_id = "-1", $currency) {
if($product !== "-1") {
getStaticPrice($product_id, $currency);
}else {
getPrice($currency);
}
}
Like I said, very much "hack" solutions. It's not exactly pretty, nor a way people would expect you to do it. So I wouldn't necessarily recommend it, but it can help you do what you want.