2009-04-14 21 views
20

Tratando de averiguar si PHP soporta características como la sobrecarga de métodos, herencia y polimorfismo, descubrí:¿Es realmente polimorfismo lo que parece ser polimorfismo en PHP?

  • que no soporta la sobrecarga de métodos
  • que hace apoyo herencia

pero No estoy seguro sobre el polimorfismo. Encontré este Google buscar en 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.

Entonces, ¿es realmente el polimorfismo?

Editar Simplemente no puedo colocar un SÍ o NO definida junto a PHP supports polymorphism. Me resistiría a afirmar: "PHP no es compatible con el polimorfismo", cuando en realidad lo hace. O viceversa.

+5

"PHP admite el polimorfismo, pero tiene algunas limitaciones". Tada. :) –

+0

gracias :) votó su respuesta. –

+0

¿Por qué este lenguaje de preguntas es independiente? Me parece completamente sobre PHP. – beldaz

Respuesta

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

Puedes etiquetarlo como quieras, pero eso me parece polimorfismo.

+4

seguro, pero la interfaz de Animal no especifica que habrá un método de speak(). Entonces podría construir un objeto como el nuevo FPDF(); y luego agrégalo a la matriz de animales. ¿Entonces que? ¿Cómo hablaría()? –

+0

Puede especificar un método de voz en la clase Animal, y se llamaría si la clase secundaria no especifica su propia voz. Y si lo hace, puedes llamarlo de todos modos con parent :: speak(); –

+1

Entonces dirías que NO admite el polimorfismo. Estoy pensando en llamarlo "inseguro" o "comportamiento polimórfico débil". ¿cual es tu opinion? –

4

Aún puede anular métodos, simplemente no los sobrecargue. Sobrecarga (en C++) es donde se usa el mismo nombre de método para múltiples métodos, que difieren solo en el número y los tipos de parámetros. Esto sería difícil en PHP ya que es de tipo débil.

Anulación es cuando la subclase reemplaza a un método en la clase base. Que es realmente la base del polimorfismo, y puedes hacerlo en PHP.

+0

lo siento, esto no es exactamente lo que quise decir. Entiendo por qué la sobrecarga de métodos no es compatible con PHP, y la diferencia entre la sobrecarga y la anulación. ¿Pero puedo proclamar que apoya el polimorfismo? –

+0

Podemos implementar la sobrecarga de métodos en PHP dando una ilusión como lo he ilustrado en mi respuesta. –

6

__call() y __callStatic() deben soportar la sobrecarga de métodos. Más sobre esto está disponible en el manual. ¿O qué estás buscando exactamente?

ACTUALIZACIÓN: Acabo de notar las otras respuestas.

Por otra manera de sobrecargar un método, tenga en cuenta lo siguiente:

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

Ciertamente no es bonito, pero le permite hacer prácticamente lo que quiera.

+1

este es un buen truco :) bueno para mantener en "caja de tule" :) –

+0

caja de herramientas? :) Jeje ... sí, solo recuerda, para no usarlo. Además, en caso de que estés buscando el parche de monos, mira en el runkit. – Till

+2

"Homer's Tule Box" es lo que Homer Simpson ha escrito en su caja de herramientas. :) –

16

aunque PHP no admite la sobrecarga de método de la forma que ha experimentado en otros lenguajes, por ejemplo, Java. pero PUEDE tener sobrecarga de método en PHP, pero el método de definición es diferente. si usted quiere tener una funcionalidad diferente para un método dado, con un conjunto diferente de parámetros en PHP, puede hacer algo como esto:

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

podría preverse una aplicación más limpia, pero esto es sólo una muestra.

PHP admite herencia e interfaces. para que pueda tener polimorfismo usándolos.usted puede tener una interfaz de la siguiente manera:

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

ahora en su aplicación, es posible utilizar de esta manera:

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

tiene usted razón, PHP no es un lenguaje fuerte con tipo, nunca se menciona que cualquier de sus $ backupSolutions sería un 'MyBackupAbstract' o 'MyBackupInterface', pero eso no nos impediría tener la naturaleza del polimorfismo, que es una funcionalidad diferente a la de usar los mismos métodos.

+2

+1 para una buena respuesta –

1

Por lo que he visto aquí php no es compatible con el polimorfismo, ni los métodos de sobrecarga. Puedes hackear tu camino para realmente acercarte a estas funcionalidades, pero están lejos del propósito original. Muchos de los ejemplos aquí están ampliando una clase o creando un truco para emular el polimorfismo.

2

polimorfismo puede ser implementado en los métodos siguientes:

  1. method overriding - bastante normal era que el anterior

  2. method overloading

Se puede crear una ilusión de la sobrecarga de métodos por el método mágico __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, que son en realidad working under the hood para proporcionar el comportamiento deseado y dando la sensación basada argumento-of method overloading

6

PHP tiene polimorfismo basado en la clase, pero carece de un mecanismo formal para la implementación polimorfismo.

El polimorfismo basado en clases significa que puede pensar en términos de una clase base, y hacer que los métodos se llamen dependan de la clase final. Por ejemplo, si tiene una matriz de objetos de varias clases como Triángulo y Círculo, y cada una de estas clases extiende la misma Clase de forma, puede considerar su matriz como simplemente una colección de formas. Puede recorrer las formas y llamar al método getArea() de cada forma. El polimorfismo es el fenómeno por el cual el método getArea() que se llama depende de la clase del objeto. Si su forma es un triángulo, se llama a Triangle :: getArea(), si es un círculo, se llama a Circle :: getArea() aunque su código no distinga entre un círculo y un triángulo, sino que considera cada objeto como simplemente una forma. La misma línea de código da como resultado la ejecución de un bloque de código diferente, según la clase del objeto.

El polimorfismo basado en argumentos es una característica de algunos lenguajes fuertemente tipados, en donde se pueden definir múltiples métodos del mismo nombre en una sola clase, siempre que tengan diferentes parámetros; entonces, a qué método se llama depende de los argumentos proporcionados. Puede emular el polimorfismo basado en argumentos en lenguajes de tipo débil como PHP al considerar manualmente los tipos de argumento dentro de su método. Esto es lo que hace jQuery para implementar una API polimórfica a pesar de la falta de JavaScript del polimorfismo nativo basado en argumentos.

Así que si por "apoya el polimorfismo" te refieres específicamente a que proporciona un mecanismo formal para implementar el polimorfismo basado en argumentos, la respuesta es no. Para cualquier interpretación más amplia, la respuesta es sí.Es lógico pensar que el fenómeno del polimorfismo basado en clases ocurre en todos los lenguajes orientados a objetos; y no tiene sentido que un lenguaje que realiza conversión de tipo implícito implemente un polimorfismo basado en argumentos.

3

PHP permite código polimórfico que generaría un error de compilación en otros idiomas. Un simple ilustra esto. El primer código de C++ que genera un error de compilación se esperaba:

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

El compilador de C++ emitirá este mensaje de error para la línea db.whoami()

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

porque la base no tiene un método llamado whoami(). Sin embargo, el código PHP análogo no encuentra tales errores hasta el tiempo de ejecución.

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. 

El bucle foreach funciona con la salida

I am Derived1 
I am Derived2 

No es hasta que llame la prueba ($ b) y pasar una instancia de base será su conseguir un error de tiempo de ejecución. Así que después de la foreach, la salida será

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 

Sobre la única cosa que puede hacer para que el PHP más seguro sería añadir una verificación de tiempo de ejecución para comprobar si $ b es una instancia de la clase tu intención

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

Pero el objetivo del polimorfismo es eliminar tales comprobaciones de tiempo de ejecución.

+0

Realmente no veo tu punto. Usted está diciendo "si invoco un método en una clase que no implementa el método ni implementa o extiende ninguna interfaz o clase que sí tiene el método, recibo un error que no fue detectado en tiempo de compilación". Lo mismo podría decirse del código '$ myVariable =" abc "; $ myVariable-> MyTestMethod(); '. Por supuesto, es lógico que si llama a una función aleatoria en un objeto completamente no relacionado, no se ejecute. El hecho de que no se detecta hasta el tiempo de ejecución es debido a la tipificación dinámica y débil de PHP. Ergo, has demostrado un intento de polimorfismo completamente malconstruido. – Byson

+0

Para demostrar mi punto, aquí está el resultado del código: ' $ myVariable =" abc "; $ myVariable-> MyTestMethod(); ' --- ' Error fatal: Llamar a una función miembro MyTestMethod() en un no objeto en ... \ tests \ test2.php en la línea 5' Así que, No veo lo que es inesperado ... – Byson