Подтвердить что ты не робот

Похоже, что полиморфизм в PHP действительно полиморфизм?

Попытка выяснить, поддерживает ли PHP такие функции, как перегрузка, наследование и полиморфизм методов, я узнал:

  • он не поддерживает перегрузку метода
  • он поддерживает наследование

но я не уверен в полиморфизме. Я нашел этот googling в Интернете:

Следует отметить, что в PHP Полиморфизм не совсем так, как это должно быть. Я имею в виду, что он работает, но поскольку у нас есть слабый тип данных, его Неправильно.

И действительно ли это полиморфизм?

Edit Просто не можете разместить определенное ДА или НЕТ рядом с PHP supports polymorphism. Я бы не хотел утверждать: "PHP не поддерживает полиморфизм", когда на самом деле это происходит. Или наоборот.

4b9b3361

Ответ 1

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>';
}

Вы можете пометить все, что хотите, но для меня это похоже на полиморфизм.

Ответ 2

хотя PHP не поддерживает перегрузку метода, как вы это испытывали на других языках, например Java. но вы можете перегружать метод в PHP, но метод определения отличается. если вы хотите иметь разную функциональность для данного метода, с различным набором параметров в PHP, вы можете сделать что-то вроде этого:

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
    }
}

может быть более чистая реализация, но это всего лишь образец.

PHP поддерживает наследование и интерфейсы. поэтому вы можете использовать полиморфизм. вы можете иметь такой интерфейс:

// 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);
     }
}

теперь в вашем приложении вы можете использовать его следующим образом:

// 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();
}

вы правы, PHP не является сильным типизированным языком, мы никогда не говорили о том, что любое из ваших $backupSolutions будет "MyBackupAbstract" или "MyBackupInterface", но это не помешает нам иметь характер полиморфизма, который отличается функциональностью используя те же методы.

Ответ 3

__call() и __callStatic() должны поддерживать перегрузку метода. Подробнее об этом можно узнать в manual. Или что именно вы после?

ОБНОВЛЕНИЕ: Я только что заметил другие ответы.

Для другого способа перегрузки метода рассмотрим следующее:

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

Конечно, не очень, но он позволяет делать практически все, что вам нужно.

Ответ 4

PHP имеет полиморфизм на основе классов, но не имеет формального механизма для реализации полиморфизма на основе аргументов.

Полиморфизм на основе классов означает, что вы можете думать в терминах базового класса, и вызываемые методы зависят от конечного класса. Например, если у вас есть массив объектов различных классов, таких как Triangle и Circle, и каждый из этих классов расширяет один и тот же класс Shape, вы можете рассматривать ваш массив как просто набор фигур. Вы можете прокручивать фигуры и вызывать каждый метод getArea(). Полиморфизм - это явление, при котором вызываемый метод getArea() зависит от класса объекта. Если ваша фигура является треугольником, вызывается Triangle:: getArea(), если Circle, то вызов Circle:: getArea() вызывается - даже если ваш код не различает круг и треугольник, но относится к каждому объекту как просто форму. Одна и та же строка кода приводит к выполнению другого блока кода в зависимости от класса объекта.

Полиморфизм на основе аргументов является признаком некоторых строго типизированных языков, в которых несколько методов с одним и тем же именем могут быть определены в одном классе при условии, что они имеют разные параметры; то какой метод вызывается, зависит от предоставленных аргументов. Вы можете эмулировать полиморфизм на основе аргументов в слабо типизированных языках, таких как PHP, вручную рассматривая типы аргументов в вашем методе. Это то, что делает jQuery для реализации полиморфного API, несмотря на отсутствие у него естественного полиморфизма на основе аргументов.

Итак, если под "поддерживает полиморфизм" вы подразумеваете конкретно, что он обеспечивает формальный механизм для реализации полиморфизма на основе аргументов, ответ отрицательный. Для любого более широкого толкования ответ да. Разумеется, феномен полиморфизма на основе классов встречается на каждом объектно-ориентированном языке; и не имеет смысла для языка, который выполняет неявное преобразование типа для реализации полиморфизма на основе аргументов.

Ответ 5

Вы все же можете переопределять методы, просто не перегружая их. Перегрузка (на С++) - это то, где вы используете одно и то же имя метода для нескольких методов, отличающихся только числом и типами параметров. Это было бы сложно в PHP, поскольку он был слабо типизирован.

Переопределение - это то, где подкласс заменяет метод в базовом классе. На самом деле это основа полиморфизма, и вы можете сделать это в PHP.

Ответ 7

PHP допускает полиморфный код, который генерирует ошибку компиляции на других языках. Простой иллюстрирует это. Первый код С++, который генерирует ожидаемую ошибку компиляции:

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();
}

Компилятор С++ выдает это сообщение об ошибке для строки db.whoami()

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

потому что Base не имеет метода whoami(). Однако аналогичный PHP-код не находит таких ошибок до времени выполнения.

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.

Цикл foreach работает с выходом

I am Derived1
I am Derived2

Пока вы не вызовете тест ($ b) и не передадите экземпляр Base, вы получите ошибку времени выполнения. Поэтому после foreach вывод будет

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

О единственном, что вы можете сделать, чтобы сделать PHP более безопасным, было бы добавить проверку времени выполнения для проверки, если $b является экземпляром класса, который вы намеревались.

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

Но вся точка полиморфизма заключается в том, чтобы исключить такие проверки времени выполнения.

Ответ 8

Полиморфизм может быть реализован следующими способами:

  • method overriding - нормальный симпатичный был как указано выше

  • method overloading

Вы можете создать иллюзию перегрузки метода магическим методом __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, мы действительно working under the hood, чтобы дать желаемое поведение и дать ощущение of method overloading

Ответ 9

Для того, что я видел здесь, php не поддерживает полиморфизм и методы перегрузки. Вы можете взломать свой путь, чтобы фактически приблизиться к обеим функциональным возможностям, но они далеки от первоначальной цели. Многие из примеров здесь либо расширяют класс, либо создают хак для эмуляции полиморфизма.