I recently got asked (in an interview) if PHP supports method overloading and overriding. Without properly processing the question, I luckily gave a doubtful "yes" for an answer. The interviewer,  thank goodness, didn't require further details. At that moment, it wasn't really clear to me how PHP accomplishes these two forms of polymorphism. Be careful: in PHP, they are tricky!, specially Method overloading.

Let's remind what method overloading & overriding are (and let's use Java for comparison): 

  • Method overloading is when you define the same method name twice (or more), within the same class, using different set of parameters.
    public class Calculator
    {
    	protected double memory = 0;
    	
    	public void Add(int number)
    	{
    		memory += number;
    	}
    
    	public void Add(double number)
    	{
    		memory += number;
    	}
    
    	public void Add(int number1, int number2)
    	{
    		memory += number1 + number2;
    	}
    
    }
  • Method overriding is when you extend a class and rewrite a method (with the same set of parameters) defined in the parent class.
    public class CalculatorPercentage extends Calculator {
    
    	public void Add(int number)
    	{
    		memory += (memory*number/100);
    	}
    
    	public void Add(double number)
    	{
    		memory += (memory*number/100);
    	}
    
    	public void Add(int number1, int number2)
    	{
    		memory += (memory*number1/100) + (memory*number2/100);
    	}
    
    }

Now let's try to translate the Calculator class to PHP, in a very very naive way.

class Calculator
{
	protected $memory = 0;
	
	public function Add(int $number)
	{
		$this->memory += $number;
	}

	public function Add(double $number)
	{
		$this->memory += $number;
	}

	public function Add(int $number1, int $number2)
	{
		$this->memory += $number1 + $number2;
	}

}

If we try to run it, PHP will throw a fatal error:

PHP Fatal error: Cannot redeclare Calculator::Add()

That's because PHP actually doesn't fully support method overriding but it provides you two ways of achieving it: using Magic Methods and Variable-length argument lists

Magic method

__call(string $name , array $arguments) is a magic function that will be called whenever you request a method that hasn't been declared within your class (neither within its parents). Also, Type Hinting doesn't work with scalar types in PHP5.

Adjusting our previous naive-attempt code, we would have:

class Calculator
{
	protected $memory = 0;
	
	public function __call($method_name, $parameters)
	{
		if ($method_name == "Add")
		{
			switch (sizeof($parameters))
			{
				case 1:
					$this->memory += $parameters[0];
				break;
				case 2:
					$this->memory += $parameters[0] + $parameters[1];
				break;
			}
		}
	}
}

... and its child class CalculatorPercentage:

class CalculatorPercentage extends Calculator
{
    	public function __call($method_name, $parameters)
	{
        	if ($method_name == "Add")
	        {
        	    switch (sizeof($parameters))
	            {
        	        case 1:
                	    $this->memory += ( $this->memory * $parameters[0] / 100 );
	                break;
        	        case 2:
                	    $this->memory += ( $this->memory * $parameters[0] / 100 ) + ( $this->memory * $parameters[1] / 100 );
	                break;
	            }
        	}
	}    
}

Variable-length argument lists

In PHP versions lower than 5.5, we can completely omit the parameters signature part in the method declaration and still recover that information using func_num_args() and  func_get_args() within its body to decide which behavior the method should take to a given set of parameters. 

For instance,

function example()
{
	echo "You've called me passing ". func_num_args()." arguments.\n";
	if ( func_num_args() )
		print_r( func_get_args() );
}

example();
example('Hello world');
example(array('1',2), '3', new stdClass());

would output:

You've called me passing 0 arguments.
You've called me passing 1 arguments.
Array
(
    [0] => Hello world
)
You've called me passing 3 arguments.
Array
(
    [0] => Array
        (
            [0] => 1
            [1] => 2
        )

    [1] => 3
    [2] => stdClass Object
        (
        )

)

In PHP versions greater than 5.6, we can use ... on the method's signature to indicate that method will receive a variable-length list of parameters. Making use of this resource, our Calculator class can be written as follows:

class Calculator
{
	protected $memory = 0;
	
	public function Add(...$parameters)
	{
		foreach($parameters as $number)
			$this->memory += $number;
	}
}