Is what seems like polymorphism in PHP really poly

2020-02-09 06:17发布

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.

9条回答
干净又极端
2楼-- · 2020-02-09 06:55

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

查看更多
男人必须洒脱
3楼-- · 2020-02-09 07:01
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.

查看更多
Evening l夕情丶
4楼-- · 2020-02-09 07:03

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.

查看更多
成全新的幸福
5楼-- · 2020-02-09 07:06

__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.

查看更多
ら.Afraid
6楼-- · 2020-02-09 07:09

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.

查看更多
The star\"
7楼-- · 2020-02-09 07:11

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.

查看更多
登录 后发表回答