La dichiarazione dei metodi dovrebbe essere compatibile con i metodi padre in PHP


107
Standard rigorosi: la dichiarazione di childClass :: customMethod () dovrebbe essere compatibile con quella di parentClass :: customMethod ()

Quali sono le possibili cause di questo errore in PHP? Dove posso trovare informazioni su cosa significa essere compatibili ?


notJim ha esattamente ragione. @ waiwai933, se potessi pubblicare le intestazioni (solo la prima riga function customMethod( ... )
:)

Maggiori dettagli sul messaggio di errore e sulle implicazioni in fase di compilazione PHP: bugs.php.net/bug.php?id=46851
hakre


1
Il mio problema era che un argomento era stato suggerito dal tipo, ma poi non l'avevo aggiunto use Closure;all'inizio della mia classe (poiché il suggerimento del tipo era Closure). Quindi ... assicurati di controllare se ti mancano dipendenze del genere.
Ryan

Risposte:


126

childClass::customMethod()ha argomenti diversi o un livello di accesso diverso (pubblico / privato / protetto) rispetto a parentClass::customMethod().


1
probabilmente è perché la visibilità , la firma dei metodi non è un problema in PHP
Gabriel Sosa

43
Anche avere gli stessi esatti valori predefiniti degli argomenti è importante. Ad esempio, parentClass::customMethod($thing = false)e childClass::customMethod($thing)provocherebbe l'errore, perché il metodo del bambino non ha definito un valore predefinito per il primo argomento.
Charles

1
Credo che la visibilità sia in realtà un errore diverso. A proposito, nel mio negozio non usiamo la modalità rigorosa, per questo motivo (usiamo E_ALL, IIRC).
davidtbernal

12
Questo è cambiato in PHP 5.4, btw: * E_ALL ora include gli errori di livello E_STRICT nella direttiva di configurazione error_reporting. Vedi qui: php.net/manual/en/migration54.other.php
Duncan Lock

1
Anche la mancanza di una e commerciale ( &) negli argomenti può attivare questo errore.
IvanRF

36

Questo messaggio significa che esistono alcune possibili chiamate di metodo che potrebbero non riuscire in fase di esecuzione. Supponi di averlo fatto

class A { public function foo($a = 1) {;}}
class B extends A { public function foo($a) {;}}
function bar(A $a) {$a->foo();}

Il compilatore controlla solo la chiamata $ a-> foo () rispetto ai requisiti di A :: foo () che non richiede parametri. $ a può tuttavia essere un oggetto di classe B che richiede un parametro e quindi la chiamata fallirebbe in fase di esecuzione.

Questo tuttavia non può mai fallire e non fa scattare l'errore

class A { public function foo($a) {;}}
class B extends A { public function foo($a = 1) {;}}
function bar(A $a) {$a->foo();}

Quindi nessun metodo può avere più parametri richiesti del suo metodo genitore.

Lo stesso messaggio viene generato anche quando i suggerimenti sul tipo non corrispondono, ma in questo caso PHP è ancora più restrittivo. Questo dà un errore:

class A { public function foo(StdClass $a) {;}}
class B extends A { public function foo($a) {;}}

come fa questo:

class A { public function foo($a) {;}}
class B extends A { public function foo(StdClass $a) {;}}

Questo sembra più restrittivo di quanto dovrebbe essere e presumo sia dovuto agli interni.

Le differenze di visibilità causano un errore diverso, ma per lo stesso motivo di base. Nessun metodo può essere meno visibile del suo metodo genitore.


2
nel tuo ultimo esempio - non dovrebbe esserci un errore qui perché è legittimo, stdClass $ a è più restrittivo di $ a misto. c'è un modo per aggirare questo? voglio dire in questo caso PHP dovrebbe consentire questo ma dà ancora un errore ...
galchen

2
Il tuo ultimo esempio è indipendente dai tipi, quindi è certamente "più restrittivo di quanto dovrebbe essere". Questo potrebbe essere un caso di programmazione cargo-cult, poiché è in conflitto con il polimorfismo in C ++ e Java en.wikipedia.org/wiki/…
Warbo

grazie per la spiegazione, nel mio caso il primo esempio che hai fornito era esattamente quello che ha innescato il mio errore.
billynoah

Grazie per questo, signore.
Eldoïr

22

se vuoi mantenere la forma OOP senza disattivare alcun errore, puoi anche:

class A
{
    public function foo() {
        ;
    }
}
class B extends A
{
    /*instead of : 
    public function foo($a, $b, $c) {*/
    public function foo() {
        list($a, $b, $c) = func_get_args();
        // ...

    }
}

Mi piacerebbe usare questo trucco per aggirare questi errori. Temo che ci possa essere una penalità nelle prestazioni a questo approccio? Cercherò questo, ma se hai delle risorse per rispondere a questa domanda, sarebbe fantastico.
Adam Friedman

Dipende dalla situazione immagino. Ancora sì, forse un po 'hacky, ma è php? già, a volte può essere una bella soluzione, grazie! <@
Master James,

mi hai salvato la giornata! questa era l'unica opzione per avviare il progetto php5 legacy sul server con php7 senza dolore
vladkras

Per questo caso è possibile utilizzare i valori di default al posto di func_get_args(), vale a dire, in B, public function foo($a = null, $b = null, $c = null), in quanto questo non si rompe il contratto promesso da A.
Jake

1

Solo per espandere questo errore nel contesto di un'interfaccia, se stai scrivendo suggerendo i parametri della tua funzione in questo modo:

interfaccia A

use Bar;

interface A
{
    public function foo(Bar $b);
}

Classe B

class B implements A
{
    public function foo(Bar $b);
}

Se hai dimenticato di includere l' useistruzione nella tua classe di implementazione (Classe B), riceverai anche questo errore anche se i parametri del metodo sono identici.


0

Ho affrontato questo problema mentre cercavo di estendere una classe esistente da GitHub. Proverò a spiegarmi, prima scrivendo la classe come pensavo che dovrebbe essere, e poi la classe come è adesso.

Quello che ho pensato

namespace mycompany\CutreApi;

use mycompany\CutreApi\ClassOfVendor;

class CutreApi extends \vendor\AwesomeApi\AwesomeApi
{
   public function whatever(): ClassOfVendor
   {
        return new ClassOfVendor();
   }
}

Quello che ho finalmente fatto

namespace mycompany\CutreApi;

use \vendor\AwesomeApi\ClassOfVendor;

class CutreApi extends \vendor\AwesomeApi\AwesomeApi
{
   public function whatever(): ClassOfVendor
   {
        return new \mycompany\CutreApi\ClassOfVendor();
   }
}

Quindi sembra che questo errore venga generato anche quando si utilizza un metodo che restituisce una classe con spazio dei nomi e si tenta di restituire la stessa classe ma con un altro spazio dei nomi. Fortunatamente ho trovato questa soluzione, ma non comprendo appieno i vantaggi di questa funzionalità in php 7.2, per me è normale riscrivere i metodi delle classi esistenti quando ne hai bisogno, inclusa la ridefinizione dei parametri di input e / o anche il comportamento del metodo.

Uno svantaggio del precedente approccio è che gli IDE non sono stati in grado di riconoscere i nuovi metodi implementati in \ mycompany \ CutreApi \ ClassOfVendor (). Quindi, per ora, seguirò questa implementazione.

Attualmente fatto

namespace mycompany\CutreApi;

use mycompany\CutreApi\ClassOfVendor;

class CutreApi extends \vendor\AwesomeApi\AwesomeApi
{
   public function getWhatever(): ClassOfVendor
   {
        return new ClassOfVendor();
   }
}

Quindi, invece di provare a usare il metodo "qualunque", ne ho scritto uno nuovo chiamato "getWwhat". In realtà entrambi stanno facendo lo stesso, restituendo solo una classe, ma con spazi dei nomi diversi come ho descritto prima.

Spero che questo possa aiutare qualcuno.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.