PHP function overloading

PhpArgumentsOverloading

Php Problem Overview


Coming from C++ background ;)
How can I overload PHP functions?

One function definition if there are any arguments, and another if there are no arguments? Is it possible in PHP? Or should I use if else to check if there are any parameters passed from $_GET and POST?? and relate them?

Php Solutions


Solution 1 - Php

You cannot overload PHP functions. Function signatures are based only on their names and do not include argument lists, so you cannot have two functions with the same name. Class method overloading is different in PHP than in many other languages. PHP uses the same word but it describes a different pattern.

You can, however, declare a variadic function that takes in a variable number of arguments. You would use func_num_args() and func_get_arg() to get the arguments passed, and use them normally.

For example:

function myFunc() {
    for ($i = 0; $i < func_num_args(); $i++) {
        printf("Argument %d: %s\n", $i, func_get_arg($i));
    }
}

/*
Argument 0: a
Argument 1: 2
Argument 2: 3.5
*/
myFunc('a', 2, 3.5);

Solution 2 - Php

PHP doesn't support traditional method overloading, however one way you might be able to achieve what you want, would be to make use of the __call magic method:

class MyClass {
    public function __call($name, $args) {

        switch ($name) {
            case 'funcOne':
                switch (count($args)) {
                    case 1:
                        return call_user_func_array(array($this, 'funcOneWithOneArg'), $args);
                    case 3:
                        return call_user_func_array(array($this, 'funcOneWithThreeArgs'), $args);
                 }
            case 'anotherFunc':
                switch (count($args)) {
                    case 0:
                        return $this->anotherFuncWithNoArgs();
                    case 5:
                        return call_user_func_array(array($this, 'anotherFuncWithMoreArgs'), $args);
                }
    	}
    }

    protected function funcOneWithOneArg($a) {

    }

    protected function funcOneWithThreeArgs($a, $b, $c) {

    }

    protected function anotherFuncWithNoArgs() {

    }

    protected function anotherFuncWithMoreArgs($a, $b, $c, $d, $e) {

    }

}

Solution 3 - Php

To over load a function simply do pass parameter as null by default,

class ParentClass
{
   function mymethod($arg1 = null, $arg2 = null, $arg3 = null)  
     {  
        if( $arg1 == null && $arg2 == null && $arg3 == null ){ 
    	   return 'function has got zero parameters <br />';
        }
        else
        {
    	   $str = '';
    	   if( $arg1 != null ) 
    		  $str .= "arg1 = ".$arg1." <br />";

    	   if( $arg2 != null ) 
    		  $str .= "arg2 = ".$arg2." <br />";

    	   if( $arg3 != null ) 
    		  $str .= "arg3 = ".$arg3." <br />";
    	
    	   return $str;
	     }
     }
}

// and call it in order given below ...

 $obj = new ParentClass;

 echo '<br />$obj->mymethod()<br />';
 echo $obj->mymethod();

 echo '<br />$obj->mymethod(null,"test") <br />';
 echo $obj->mymethod(null,'test');

 echo '<br /> $obj->mymethod("test","test","test")<br />';
 echo $obj->mymethod('test','test','test');

Solution 4 - Php

It may be hackish to some, but I learned this way from how Cakephp does some functions and have adapted it because I like the flexibility it creates

The idea is you have different type of arguments, arrays, objects etc, then you detect what you were passed and go from there

function($arg1, $lastname) {
    if(is_array($arg1)){
        $lastname = $arg1['lastname'];
        $firstname = $arg1['firstname'];
	} else {
	    $firstname = $arg1;
	}
	...
}

Solution 5 - Php

<?php   
/*******************************
 * author  : hishamdalal@gmail.com 
 * version : 3.8
 * create on : 2017-09-17
 * updated on : 2020-01-12
 * download example:  https://github.com/hishamdalal/overloadable
 *****************************/

#> 1. Include Overloadable class

class Overloadable
{
	static function call($obj, $method, $params=null) {
		$class = get_class($obj);
		// Get real method name
		$suffix_method_name = $method.self::getMethodSuffix($method, $params);

		if (method_exists($obj, $suffix_method_name)) {
			// Call method
			return call_user_func_array(array($obj, $suffix_method_name), $params);
		}else{
			throw new Exception('Tried to call unknown method '.$class.'::'.$suffix_method_name);
		}
	}

	static function getMethodSuffix($method, $params_ary=array()) {
		$c = '__';
		if(is_array($params_ary)){
			foreach($params_ary as $i=>$param){
				// Adding special characters to the end of method name 
				switch(gettype($param)){
					case 'array':       $c .= 'a'; break;
					case 'boolean':     $c .= 'b'; break;
					case 'double':      $c .= 'd'; break;
					case 'integer':     $c .= 'i'; break;
					case 'NULL':        $c .= 'n'; break;
					case 'object':
						// Support closure parameter
						if($param instanceof Closure ){
							$c .= 'c';
						}else{
							$c .= 'o'; 
						}
					break;
					case 'resource':    $c .= 'r'; break;
					case 'string':      $c .= 's'; break;
					case 'unknown type':$c .= 'u'; break;
				}
			}
		}
		return $c;
	}
	// Get a reference variable by name
	static function &refAccess($var_name) {
		$r =& $GLOBALS["$var_name"]; 
		return $r;
	}
}
//----------------------------------------------------------
#> 2. create new class
//----------------------------------------------------------

class test 
{
	private $name = 'test-1';

	#> 3. Add __call 'magic method' to your class

	// Call Overloadable class 
	// you must copy this method in your class to activate overloading
	function __call($method, $args) {
		return Overloadable::call($this, $method, $args);
	}

	#> 4. Add your methods with __ and arg type as one letter ie:(__i, __s, __is) and so on.
	#> methodname__i = methodname($integer)
	#> methodname__s = methodname($string)
	#> methodname__is = methodname($integer, $string)

	// func(void)
	function func__() {
		pre('func(void)', __function__);
	}
	// func(integer)
	function func__i($int) {
		pre('func(integer '.$int.')', __function__);
	}
	// func(string)
	function func__s($string) {
		pre('func(string '.$string.')', __function__);
	}    
	// func(string, object)
	function func__so($string, $object) {
		pre('func(string '.$string.', '.print_r($object, 1).')', __function__);
		//pre($object, 'Object: ');
	}
	// func(closure)
	function func__c(Closure $callback) {
		
		pre("func(".
			print_r(
				array( $callback, $callback($this->name) ), 
				1
			).");", __function__.'(Closure)'
		);
		
	}   
	// anotherFunction(array)
	function anotherFunction__a($array) {
		pre('anotherFunction('.print_r($array, 1).')', __function__);
		$array[0]++;        // change the reference value
		$array['val']++;    // change the reference value
	}
	// anotherFunction(string)
	function anotherFunction__s($key) {
		pre('anotherFunction(string '.$key.')', __function__);
		// Get a reference
		$a2 =& Overloadable::refAccess($key); // $a2 =& $GLOBALS['val'];
		$a2 *= 3;   // change the reference value
	}
	
}

//----------------------------------------------------------
// Some data to work with:
$val  = 10;
class obj {
	private $x=10;
}

//----------------------------------------------------------
#> 5. create your object

// Start
$t = new test;

#> 6. Call your method

// Call first method with no args:
$t->func(); 
// Output: func(void)

$t->func($val);
// Output: func(integer 10)

$t->func("hello");
// Output: func(string hello)

$t->func("str", new obj());
/* Output: 
func(string str, obj Object
(
	[x:obj:private] => 10
)
)
*/

// call method with closure function
$t->func(function($n){
	return strtoupper($n);
});

/* Output:
func(Array
(
	[0] => Closure Object
		(
			[parameter] => Array
				(
					[$n] => 
				)

		)

	[1] => TEST-1
)
);
*/

## Passing by Reference:

echo '<br><br>$val='.$val;
// Output: $val=10

$t->anotherFunction(array(&$val, 'val'=>&$val));
/* Output:
anotherFunction(Array
(
	[0] => 10
	[val] => 10
)
)
*/

echo 'Result: $val='.$val;
// Output: $val=12

$t->anotherFunction('val');
// Output: anotherFunction(string val)

echo 'Result: $val='.$val;
// Output: $val=36







// Helper function
//----------------------------------------------------------
function pre($mixed, $title=null){
	$output = "<fieldset>";
	$output .= $title ? "<legend><h2>$title</h2></legend>" : "";
	$output .= '<pre>'. print_r($mixed, 1). '</pre>';
	$output .= "</fieldset>";
	echo $output;
}
//----------------------------------------------------------

Solution 6 - Php

What about this:

function($arg = NULL) {

    if ($arg != NULL) {
        etc.
        etc.
    }
}

Solution 7 - Php

In PHP 5.6 you can use the splat operator ... as the last parameter and do away with func_get_args() and func_num_args():

function example(...$args)
{
   count($args); // Equivalent to func_num_args()
}

example(1, 2);
example(1, 2, 3, 4, 5, 6, 7);

You can use it to unpack arguments as well:

$args[] = 1;
$args[] = 2;
$args[] = 3;
example(...$args);

Is equivalent to:

example(1, 2, 3);

Solution 8 - Php

<?php

	class abs
	{
		public function volume($arg1=null, $arg2=null, $arg3=null)
		{	
			if($arg1 == null && $arg2 == null && $arg3 == null)
		{
			echo "function has no arguments. <br>";
		}
		
		else if($arg1 != null && $arg2 != null && $arg3 != null)
			{
			$volume=$arg1*$arg2*$arg3;
			echo "volume of a cuboid ".$volume ."<br>";
			}
			else if($arg1 != null && $arg2 != null)
			{
			$area=$arg1*$arg2;
			echo "area of square  = " .$area ."<br>";
			}
			else if($arg1 != null)
			{
			$volume=$arg1*$arg1*$arg1; 
			echo "volume of a cube = ".$volume ."<br>";
			}
			
			
		}
		
		
	}
	
	$obj=new abs();
	echo "For no arguments. <br>";
	$obj->volume();
	echo "For one arguments. <br>";
	$obj->volume(3);
	echo "For two arguments. <br>";
	$obj->volume(3,4);
	echo "For three arguments. <br>";
	$obj->volume(3,4,5);
	?>

Solution 9 - Php

Sadly there is no overload in PHP as it is done in C#. But i have a little trick. I declare arguments with default null values and check them in a function. That way my function can do different things depending on arguments. Below is simple example:

public function query($queryString, $class = null) //second arg. is optional
{
    $query = $this->dbLink->prepare($queryString);
    $query->execute();

    //if there is second argument method does different thing
    if (!is_null($class)) { 
        $query->setFetchMode(PDO::FETCH_CLASS, $class);
    }

    return $query->fetchAll();
}

//This loads rows in to array of class
$Result = $this->query($queryString, "SomeClass");
//This loads rows as standard arrays
$Result = $this->query($queryString);

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionVamsi Krishna BView Question on Stackoverflow
Solution 1 - PhpBoltClockView Answer on Stackoverflow
Solution 2 - PhpStephenView Answer on Stackoverflow
Solution 3 - PhpAdil AbbasiView Answer on Stackoverflow
Solution 4 - PhpSeanDowneyView Answer on Stackoverflow
Solution 5 - PhpHisham DalalView Answer on Stackoverflow
Solution 6 - PhpMarlin OuversonView Answer on Stackoverflow
Solution 7 - PhpmtpultzView Answer on Stackoverflow
Solution 8 - PhpRaman Deep BajwaView Answer on Stackoverflow
Solution 9 - PhpRovshan MamedovView Answer on Stackoverflow