2009-04-14 8 views
20

Cercando di capire se il PHP supporta funzioni come overloading dei metodi, ereditarietà e il polimorfismo, ho scoperto:È ciò che sembra il polimorfismo in PHP veramente il polimorfismo?

  • non supporta il metodo di sovraccaricare
  • lo fa supporta l'ereditarietà

ma io sono incerto sul polimorfismo. Ho trovato questo su Google su Google:

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.

Quindi è davvero polimorfismo?

Modifica Proprio non riesco a mettere un sì definitivo o NO accanto PHP supports polymorphism. Sarei riluttante a dire: "PHP non supporta il polimorfismo", quando in realtà lo fa. O vice versa.

+5

"PHP supporta il polimorfismo, ma presenta alcune limitazioni." Tada. :) –

+0

grazie :) ha migliorato la tua risposta. –

+0

Perché la lingua di questa domanda è agnostica? Sembra interamente di PHP per me. – beldaz

risposta

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

È possibile etichettare tutto ciò che si desidera, ma mi sembra un polimorfismo.

+4

sicuro, ma l'interfaccia Animale non specifica che ci sarà un metodo speak(). Così ho potuto costruire un oggetto come il nuovo FPDF(); e quindi aggiungilo alla schiera di animali. Cosa poi? Come direbbe()? –

+0

È possibile specificare un metodo speak nella classe Animale e verrà chiamato se la classe figlio non specifica la propria espressione. E se lo fa, puoi chiamarlo comunque con parent :: speak(); –

+1

Quindi diresti che il polimorfismo è supportato. Sto pensando di chiamarlo "non sicuro" o "debole comportamento polimorfico". qual'è la tua opinione? –

4

È ancora possibile eseguire l'override dei metodi, ma non sovraccaricarli. Sovraccarico (in C++) è dove si utilizza lo stesso nome di metodo per più metodi, differendo solo per numero e tipi di parametri. Questo sarebbe difficile in PHP poiché è tipizzato in modo debole.

L'override è il punto in cui la sottoclasse sostituisce un metodo nella classe base. Quale è davvero la base per il polimorfismo, e puoi farlo in PHP.

+0

scusa, non è esattamente quello che intendevo. Capisco perché l'overloading dei metodi non è supportato in PHP e la differenza tra overloading e override. Ma posso affermare che supporta il polimorfismo? –

+0

Possiamo implementare l'overloading dei metodi in PHP dando un'illusione come ho illustrato nella mia risposta. –

6

__call() e __callStatic() devono supportare il metodo di overloading. Ulteriori informazioni sono disponibili su manual. O cosa stai cercando esattamente?

AGGIORNAMENTO: Ho appena notato le altre risposte.

Per un altro modo per sovraccaricare un metodo, considerare quanto segue:

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

Certamente non bella, ma permette di fare praticamente tutto quello che vuoi.

+1

questo è un bel trucco :) buono da tenere in "scatola tule" :) cassetta degli attrezzi –

+0

? :) Hehe ... sì, ricorda, non usarlo. Inoltre, nel caso tu stia cercando patch per scimmia, guarda in runkit. – Till

+2

"Homer's Tule Box" è ciò che Homer Simpson ha scritto sulla sua cassetta degli attrezzi. :) –

16

sebbene PHP non supporti il ​​metodo di overloading come si è verificato in altri linguaggi, ad esempio Java. ma si può avere un overload di metodi in PHP, ma il metodo di definizione è diverso. se si vuole avere funzionalità diverse per un dato metodo, con diversi set di parametri in PHP, si può fare qualcosa di simile:

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

ci potrebbe essere implementazione più pulito, ma questo è solo un esempio.

PHP supporta l'ereditarietà e le interfacce. così puoi avere il polimorfismo usandoli.si può avere un'interfaccia come questa:

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

ora nella vostra applicazione, è possibile utilizzare in questo modo:

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

hai ragione, PHP non è un linguaggio forte tipizzato, non abbiamo mai detto che qualsiasi dei tuoi $ backupSolutions sarebbe un 'MyBackupAbstract' o 'MyBackupInterface', ma questo non ci impedirebbe di avere la natura del polimorfismo che è una funzionalità diversa rispetto all'uso degli stessi metodi.

+2

+1 per una bella risposta –

1

Per quello che ho visto qui, php non supporta il polimorfismo, né i metodi di sovraccarico. Puoi aprirti la strada per avvicinarti davvero a entrambe queste funzionalità di oop, ma sono lontane dallo scopo originale. Molti degli esempi qui stanno estendendo una classe o creando un hack per polimorfismo emulativo.

2

polimorfismo può essere implementata nei seguenti metodi:

  1. method overriding - normale piuttosto era come sopra

  2. method overloading

È possibile creare l'illusione di overloading dei metodi da parte del 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, ci sono in realtà working under the hood che invia il comportamento desiderato e dando la sensazione of method overloading PHP ha polimorfismo di classe, ma manca un meccanismo formale per l'attuazione argomento basato-

6

polimorfismo.

Il polimorfismo basato sulla classe significa che è possibile pensare in termini di una classe base e che i metodi da chiamare dipendono dalla classe finale. Ad esempio, se hai una matrice di oggetti di varie classi come Triangolo e Cerchio, e ognuna di queste classi estende la stessa classe, puoi considerare la tua matrice semplicemente come una collezione di forme. Puoi scorrere le forme e chiamare il metodo getArea() di ogni forma. Il polimorfismo è il fenomeno per cui il metodo getArea() chiamato dipende dalla classe dell'oggetto. Se la tua forma è un triangolo, viene chiamato Triangle :: getArea(), se viene chiamato un cerchio, quindi Circle :: getArea(), anche se il tuo codice non fa distinzione tra un cerchio e un triangolo, ma considera ogni oggetto come semplicemente una forma. La stessa riga di codice si traduce in un diverso blocco di codice in esecuzione, a seconda della classe dell'oggetto.

Il polimorfismo basato su argomenti è una funzionalità di alcuni linguaggi fortemente tipizzati, in cui più metodi con lo stesso nome possono essere definiti in una singola classe, purché abbiano parametri diversi; allora quale metodo viene chiamato dipende dagli argomenti forniti. È possibile emulare il polimorfismo basato su argomenti in linguaggi tipizzati debolmente come PHP, considerando manualmente i tipi di argomento nel metodo. Questo è ciò che jQuery fa per implementare un'API polimorfico nonostante la mancanza di JavaScript di polimorfismo basato su argomenti nativi.

Quindi se con "supporta il polimorfismo" si intende specificamente che fornisce un meccanismo formale per implementare il polimorfismo basato su argomenti, la risposta è no. Per qualsiasi interpretazione più ampia, la risposta è sì.È ovvio che il fenomeno del polimorfismo di classe si verifica in ogni linguaggio orientato agli oggetti; e non ha senso per un linguaggio che esegue la conversione di tipo implicita per implementare il polimorfismo basato su argomenti.

3

PHP consente il codice polimorfico che genera un errore di compilazione in altre lingue. Un semplice illustra questo. Primo codice C++ che genera un errore di compilazione previsto:

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

Il compilatore C++ emetterà questo messaggio di errore per la linea db.whoami()

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

perché Base non dispone di un metodo chiamato whoami(). Tuttavia, l'analogo codice PHP non trova tali errori fino al tempo di esecuzione.

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. 

Il ciclo foreach funziona con l'uscita

I am Derived1 
I am Derived2 

Non fino a quando si chiama prova ($ b) e passare un'istanza di base sarà il tuo ottenere un errore di tempo di esecuzione. Così, dopo il foreach, l'uscita sarà

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 

L'unica cosa che si può fare per rendere il PHP più sicura sarebbe quella di aggiungere un controllo di fase di esecuzione per verificare se $ b è un'istanza della classe hai inteso.

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

Ma il punto principale del polimorfismo è eliminare tali controlli del tempo di esecuzione.

+0

Non vedo davvero il tuo punto. Stai dicendo "se chiamo un metodo su una classe che non implementa il metodo né implementa o estende alcuna interfaccia o classe che ha il metodo, ricevo un errore che non è stato rilevato al momento della compilazione". Lo stesso identico si può dire del codice '$ myVariable =" abc "; $ MyVariable-> MyTestMethod(); '. Naturalmente è logico che se si chiama una funzione casuale su un oggetto completamente indipendente non viene eseguito. Il fatto che non venga individuato fino al runtime è dovuto alla digitazione dinamica e debole di PHP. Ergo, hai dimostrato un tentativo di polimorfismo completamente errato. – Byson

+0

Per dimostrare il mio punto, ecco il risultato del codice: ' $ myVariable =" abc "; $ myVariable-> MyTestMethod(); ' --- ' Errore irreversibile: chiamata a una funzione membro MyTestMethod() su un oggetto non in ... \ tests \ test2.php sulla riga 5' Quindi sì, Non vedo cosa sia inaspettato ... – Byson