25

Trying to figure out whether PHP supports features like method overloading, inheritance, and polymorphism, I found out:

  • it does not support method overloading
  • it does support inheritance

but I am unsure about polymorphism. I found this Googling the Internet:

I should note that in PHP the polymorphism isn't quite the way it should be. I mean that it does work, but since we have a weak datatype, its not correct.

So is it really polymorphism?

Edit Just can't quite place a definite YES or NO next to PHP supports polymorphism. I would be loath to state: "PHP does not support polymorphism", when in reality it does. Or vice-versa.

Peter Perháč
  • 20,434
  • 21
  • 120
  • 152

9 Answers9

34
class Animal {
    var $name;
    function __construct($name) {
        $this->name = $name;
    }
}

class Dog extends Animal {
    function speak() {
        return "Woof, woof!";
    }
}

class Cat extends Animal {
    function speak() {
        return "Meow...";
    }
}

$animals = array(new Dog('Skip'), new Cat('Snowball'));

foreach($animals as $animal) {
    print $animal->name . " says: " . $animal->speak() . '<br>';
}

You can label it all you want, but that looks like polymorphism to me.

Paolo Bergantino
  • 480,997
  • 81
  • 517
  • 436
  • 4
    sure, but the Animal interface does not specify there will be a speak() method. So I could construct an object like new FPDF(); and then add it to the array of animals. What then? How would it speak() ? – Peter Perháč Apr 14 '09 at 23:43
  • You can specify a speak method in the Animal class, and it would be called if the child class does not specify its own speak. And if it does, you can call it anyways with parent::speak(); – Paolo Bergantino Apr 14 '09 at 23:47
  • 1
    So you would say it DOES support polymorphism. I am thinking of calling it 'unsafe' or 'weak polymorphic behaviour'. what's your opinion? – Peter Perháč Apr 14 '09 at 23:53
  • unsafe and weak aren't words I'd use, to be honest. PHP does also support method overloading as Till shows, but it's not nearly as clean as it should be. I'd say it has polymorphism, all things considered. – Paolo Bergantino Apr 15 '09 at 00:03
  • Yeah, maybe not as clean as it could be, but it's fine for the most part. – Paolo Bergantino Apr 15 '09 at 00:21
  • @Peter: it's definitely polymorphism whether or not the interface is explicitly specified in the base class. The facts that `$animals` holds two distinct types, and the `foreach` loop can invoke type-specific behaviour for each type without any special casing inside it, satisfies the very definition of polymorphism. (While focused on C++, I discuss that at http://stackoverflow.com/questions/5854581/polymorphism-in-c/5854862#5854862) – Tony Delroy Jun 16 '11 at 06:31
  • This is a great example of polymorphism in PHP. I personally prefer this method in C++, so I am glad PHP supports it. – Jeff Davis Apr 30 '12 at 23:01
  • @JeffDavis But i believe in C++, your data structures such as linkedlist or array must be of a single type. In PHP, arrays are not as strict. So how do I implement the same thing in C++? – Kim Stacks Nov 04 '12 at 04:03
  • I am curious about doing the same thing in C++, so I crafted a SO question here http://stackoverflow.com/questions/13215977/example-of-polymorphism-working-with-data-structure-in-c-based-on-php-example – Kim Stacks Nov 04 '12 at 04:09
  • @kimsia My c++ is a little rusty now, but I am pretty sure the example above works fine in c++. You would need to use pointers to the objects, so some of the notation would be different, but in principle it should be the same. – Jeff Davis Nov 05 '12 at 19:49
  • @JeffDavis I got it to work in C++. http://stackoverflow.com/a/13243374/80353 Thanks! – Kim Stacks Nov 06 '12 at 03:28
  • 2
    @PeterPerháč I am late to the discussion, but I wouldn't use the words weak, unsafe, not as clean, or any other qualifier. All of those are relative terms, which begs the question "relative to what?". It is PHP, and you can apply this coding concept to your PHP code. That's it. Implementing the concept is different in PHP than it is in C++ -- so is virtually every other aspect of using the two languages. They're different languages, so of course it is different. Weaker, cleaner, or less safe imply that only C++ has "true polymorphism", which is, clearly, not the case. – Chris Baker Oct 24 '13 at 17:42
17

although PHP does not support method overloading the way you have experienced in other languages, say Java. but you CAN have method overloading in PHP, but the definition method is different. if you want to have different functionality for a given method, with different set of parameters in PHP, you can do something like this:

class myClass {
    public function overloadedMethod() {
        // func_num_args() is a build-in function that returns an Integer.
        // the number of parameters passed to the method.
        if ( func_num_args() > 1 ) {
            $param1 = func_get_arg(0);
            $param2 = func_get_arg(1);
            $this->_overloadedMethodImplementation2($param1,$param2)
        } else {
            $param1 = func_get_arg(0);
            $this->_overloadedMethodImplementation1($param1)
        }
    }

    protected function _overloadedMethodImplementation1($param1) {
        // code 1
    }

    protected function _overloadedMethodImplementation2($param1,$param2) {
        // code 2
    }
}

there could be cleaner implementation, but this is just a sample.

PHP supports inheritance and interfaces. so you can have polymorphism using them. you can have an interface like this:

// file: MyBackupInterface.php
interface MyBackupInterface {
    // saves the data on a reliable storage
    public function saveData();
    public function setData();
}

// file: myBackupAbstract.php
require_once 'MyBackupInterface.php';
class MyBackupAbstract implements MyBackupInterface {
     protected $_data;
     public function setData($data) {
         $this->_data= $data;
     }
     // there is no abstract modifier in PHP. so le'ts avoid this class to be used in other ways
     public function __construct() {
          throw new Exception('this class is abstract. you can not instantiate it');
     }
}

// file: BackupToDisk.php
require_once 'MyBackupAbstract.php';
class BackupToDisk extends MyBackupAbstract {
     protected $_savePath;

     // implement other methods ...

     public function saveData() {
           // file_put_contents() is a built-in function to save a string into a file.
           file_put_contents($this->_savePath, $this->_data);
     }
}

// file: BackupToWebService.php
require_once 'MyBackupAbstract.php';
class BackupToWebService extends MyBackupAbstract {
     protected $_webService;
     // implement other methods ...

     public function saveData() {
           // suppose sendData() is implemented in the class
           $this->sendData($this->_data);
     }
}

now in your application, you might use it like this:

// file: saveMyData.php
// some code to populate $myData
$backupSolutions = array( new BackupToDisk('/tmp/backup') , new BackupToWebService('webserviceURL') );
foreach ( $backupSolutions as $bs ) {
    $bs->setData($myData);
    $bs->saveData();
}

you are right, PHP is not strong typed language, we never mentioned that any of your $backupSolutions would be a 'MyBackupAbstract' or 'MyBackupInterface', but that would not stop us from having the nature of polymorphism which is different functionality over using the same methods.

farzad
  • 8,775
  • 6
  • 32
  • 41
7

PHP has class-based polymorphism, but lacks a formal mechanism for implementing argument-based polymorphism.

Class-based polymorphism means that you can think in terms of a base class, and have the methods being called depend on the final class. For instance, if you have an array of objects of various classes such as Triangle and Circle, and each of these classes extends the same class Shape, you can regard your array as merely a collection of shapes. You can loop through the shapes and call each shape's getArea() method. Polymorphism is the phenomenon whereby the getArea() method being called depends on the class of the object. If your shape is a Triangle, Triangle::getArea() gets called, if a Circle, then Circle::getArea() gets called--even though your code doesn't distinguish between a Circle and a Triangle but regards each object as merely a Shape. The same line of code results in a different block of code being executed, depending on the object's class.

Argument-based polymorphism is a feature of some strongly-typed languages, wherein multiple methods of the same name can be defined in a single class, provided that they have different parameters; then which method is called depends on the arguments provided. You can emulate argument-based polymorphism in weakly-typed languages like PHP by manually considering your argument types within your method. This is what jQuery does in order to implement a polymorphic API despite JavaScript's lack of native argument-based polymorphism.

So if by "supports polymorphism" you mean specifically that it provides a formal mechanism for implementing argument-based polymorphism, the answer is no. For any broader interpretation, the answer is yes. It stands to reason that the phenomenon of class-based polymorphism occurs in every Object-Oriented language; and it makes no sense for a language that performs implicit type conversion to implement argument-based polymorphism.

Val Kornea
  • 4,469
  • 3
  • 40
  • 41
6

__call() and __callStatic() should support method overloading. More on this is available in the manual. Or what exactly are you after?

UPDATE: I just noticed the other replies.

For another way to overload a method, consider the following:

<?php
public function foo()
{
    $args = func_get_arg();
}

Certainly not pretty, but it allows you to do virtually whatever you want.

Till
  • 22,236
  • 4
  • 59
  • 89
  • tool box? :) Hehe... yeah, just remember, to not use it. Also, in case you are after monkey patching, look into runkit. – Till Apr 14 '09 at 23:59
  • 2
    "Homer's Tule Box" is what Homer Simpson has written on his toolbox. :) – Pekka Dec 09 '09 at 14:25
4

You can still override methods, just not overload them. Overloading (in C++) is where you use the same method name for multiple methods, differing only in number and types of parameters. This would be hard in PHP since it's weak-typed.

Overriding is where the sub-class replaces a method in the base class. Which is really the basis for polymorphism, and you can do that in PHP.

GoatRider
  • 1,213
  • 6
  • 12
  • sorry, this is not exactly what I meant. I understand why method overloading is not supported in PHP, and the difference between overloading and overriding. But can I proclaim it does support polymorphism? – Peter Perháč Apr 14 '09 at 23:40
  • We can implement method overloading in PHP by giving an illusion as i have illustrated in my answer. – Angelin Nadar Aug 16 '14 at 12:48
4

Some call this duck typing.

Martin
  • 5,945
  • 7
  • 50
  • 77
3

Polymorphism can be implemented in the following methods:

  1. method overriding - normal pretty was as above

  2. method overloading

You can create an illusion of method overloading by the magic method __call():

class Poly {
    function __call($method, $arguments) {
        if ($method == 'edit') {
            if (count($arguments) == 1) {

                return call_user_func_array(array($this,'edit1'), $arguments);
            } else if (count($arguments) == 2) {
                return call_user_func_array(array($this,'edit2'), $arguments);
            }
        }
    }
    function edit1($x) {
        echo "edit with (1) parameter";
    }

    function edit2($x, $y) {
        echo "edit with (2) parameter";
    }

}

$profile = new Poly();
$profile->edit(1);
$profile->edit(1,2);

Expln:

1) Here we are utilizing the power of __call() of listening calls of 
   non-available     methods and 
2) after knowing it who had called with their inputs diverting them to desired 
   method 

In php, we are actually working under the hood to give the desired behaviour and giving the feeling of method overloading

Angelin Nadar
  • 8,944
  • 10
  • 43
  • 53
3

PHP allows for polymorphic code that would generate an compile error in other languages. A simple illustrates this. First C++ code that generates an expected compile error:

class Base {};

class CommonDerivedBase {
   public:
    // The "= 0" makes the method and class abstract
    // virtual means polymorphic method
    virtual whoami() = 0;
};

class DerivedBase : public CommonDerivedBase {
   public:    
     void  whoami() { cout << "I am DerivedBase \n"; }
};

class Derived1 : public CommonDerivedBase {
  public:
    void  whoami() { cout << "I am Derived1\n"; }
};

class Derived2 : public CommonDerivedBase {
public:
 void whoami() { cout <<  "I am Derived2\n"; }
};

/* This will not compile */
void  test_error(Base& db)
{
   db.whoami();
}

The C++ compiler will issue this error message for the line db.whoami()

error: no member named 'whoami' in 'Base'

because Base does not have a method called whoami(). However, the analogous PHP code does not find such errors until run time.

class Base {}

abstract class DerivedCommonBase {
  abstract function whoami();
}

class Derived1 extends DerivedCommonBase {

 public function whoami() { echo "I am Derived1\n"; }
}

class Derived2 extends DerivedCommonBase {

 public function whoami() { echo "I am Derived2\n"; }
}

/* In PHP, test(Base $b) does not give a runtime error, as long as the object 
 * passed at run time derives from Base and implements whoami().
 */
function test(Base $b)
{
  $b->whoami(); 
}

$b = new Base();
$d1 = new Derived1();
$d2 = new Derived2();

$a = array();

$a[] = $d1;
$a[] = $d2;

foreach($a as $x) {

  echo  test($x);
}

test($d1);
test($d2);
test($b); //<-- A run time error will result.

The foreach loop works with the output

I am Derived1
I am Derived2

Not until you call test($b) and pass an instance of Base will your get a run time error. So after the foreach, the output will be

I am Derived1
I am Derived2
PHP Fatal error:  Call to undefined method Base::whoami() in
home/kurt/public_html/spl/observer/test.php on line 22

About the only thing you can do to make the PHP safer would be to add a run time check to test if $b is an instance of the class you intended.

function test(Base $b)
{
  if ($b instanceof DerivedCommonBase) {
     $b->whoami(); 
  } 
}

But the whole point of polymorphism is to eliminate such run time checks.

Kurt Krueckeberg
  • 1,225
  • 10
  • 11
  • I really don't see your point. You're saying "if I call a method on a class which neither implements the method nor implements or extends any interface or class which does have the method, I get an error which wasn't caught at compile time." The exact same could be said of the code `$myVariable = "abc"; $myVariable->MyTestMethod();`. Of course it's logical that if you call a random function on a completely unrelated object it doesn't run. The fact it isn't spotted until runtime is because of PHP's dynamic and weak typing. Ergo, you demonstrated a completely misconstructed polymorphism attempt. – Byson Oct 30 '14 at 15:55
  • To demonstrate my point, here's the result of the code: ` $myVariable = "abc"; $myVariable->MyTestMethod();` --- `Fatal error: Call to a member function MyTestMethod() on a non-object in ...\tests\test2.php on line 5` So yes, I do not see what's unexpected... – Byson Oct 30 '14 at 16:01
1

For what I’ve seen here php do not support polymorphism, nor overloading methods. You can hack your way to actually get close to both of these oop functionalities, but they are far from the original purpose of it. Many of the examples here either are extending a class or creating a hack to emuluate polymorphism.

Rolando
  • 19
  • 1