2010-12-30 4 views
13

Penso che sarà molto più facile vedere il problema in un esempio di codice che scrivere la domanda in primo luogo. Ecco il mio codice php:Suggerimento di php che non va d'accordo con le interfacce e le classi astratte?

<?php 

interface AnInterface 
{ 
     public function method(); 
}  

class AClass implements AnInterface 
{ 
     public function method() 
     { 
       echo __METHOD__; 
     } 
}  

abstract class AnAbstractClass 
{ 
     abstract public function method(AnInterface $Object); 
} 

class ConcreteClass extends AnAbstractClass 
{ 
     public function method(AClass $Object) 
     { 
       $Object->method(); 
     } 
} 

$Object1 = new ConcreteClass(); 
$Object2 = new AClass(); 

$Object1->method($Object2); 

Il codice sopra provoca il seguente errore:

Fatal error: Declaration of ConcreteClass::method() must be compatible with that of AnAbstractClass::method()

Il problema è che il PHP non sembra essere riconoscere le firme dei AnAbstractClass :: metodo e ConcreteClass: : metodo come compatibile. Sto facendo qualcosa di sbagliato? Grazie!

+4

Per favore, * per favore * abituarsi a pubblicare il messaggio di errore che il codice sta generando. Inviare codice senza pubblicare l'output (o errore) è inutile. – meagar

risposta

24

php doesn't seem to be recognizing the signatures of AnAbstractClass::method and ConcreteClass::method as compatible.

PHP è corretto, sono non compatibile. Consentendo solo le istanze di AClass (o dei suoi figli) da passare al ConcreteClass::method, si sta rompendo il contratto che AnAbstractClass dispone: Qualsiasi delle sue sottoclassi deve accettare AnInterface come argomento per la sua method().

Se il vostro esempio funzionato, e ho avuto un'altra classe BClass attuazione AnInterface, avremmo una situazione in cui in base al AnAbstractClass, method() dovrebbe accettare le istanze di BClass, mentre secondo ConcreteClass, non dovrebbe.

Modificare la firma per ConcreteClass::method in modo che corrisponda a quella di AnAbstractClass::method.

+3

Dopo aver riflettuto, sono giunto alla conclusione che hai ragione. Credo che stavo cercando di perdere un motivo. Grazie mille. – Muc

+0

posso sovrascriverlo in phpdoc per l'autocompletamento nel mio IDE (phpStorm)? Perché ora non mi dà quell'abilità – Crusader

2

Non calcola. Abbiamo avuto la stessa discussione di ieri:
Can parameter types be specialized in PHP

tutte le classi derivate devono implementare le firme del metodo in modo identico.

Questo è qualcosa che idealmente dovrebbe essere controllato in fase di esecuzione. Ma in PHP fa il parser. (. Per compensare, PHP non controlla l'accesso attributo private/protetta al momento di analisi, ma lasciate che uno piuttosto saltare in aria in fase di esecuzione)

Se si desidera applicare un tipo più stringenti, vorrei consigliare:

assert(is_a($Object, "AClass")); 
+5

Dato che si tratta di PHP 5, tale affermazione dovrebbe leggere 'assert ($ Object instanceof AClass);' – BoltClock

+0

Sì, che potrebbe funzionare, ma in realtà non è il modo in cui si suppone che sia, credo di aver avuto un equivoco, in primo luogo , vedere la risposta di @meagar – Muc

+0

I casi come l'ereditarietà di ArrayObject sarebbero ISTM buoni candidati per eseguire un'asserzione o un lancio di tipo se fosse stato ricevuto il tipo sbagliato. Ma non è possibile modificare l'interfaccia di base (ad esempio ArrayAccess :: offsetSet assumerà sempre un parametro misto per il valore). –

2

Ecco un esempio che mostra, perché questo non è consentito:

<?php 
class BClass implements AnInterface { } 

function moo(AnAbstractClass $abstract) 
{ 
    $b = new BClass(); 
    $abstract->method($b); 
} 

questo sarebbe un codice valido, ma sarebbe fallire, se si passa un ConcreteClass a MOO, perché il suo metodo di ConcreteClass::method non consente BClass.

E 'complicato, ma è più facile da capire, se vedete un esempio.