2010-06-24 9 views
6

Ho eseguito alcuni test (per sostituire il vecchio codice) con il metodo magico __invoke e non sono sicuro che si tratti di un bug o meno:PHP5.3: Errore "Chiamata a metodo non definito" quando si chiama invoke dalla variabile di classe

Lascia supponiamo di avere una classe:

class Calc { 
    function __invoke($a,$b){ 
     return $a*$b; 
    } 
} 

quello che segue è possibile e funziona senza alcun problema:

$c = new Calc; 
$k = $c; 
echo $k(4,5); //outputs 20 

Tuttavia, se voglio avere un'altra classe per memorizzare un'istanza di quell'oggetto , questo non funziona:

class Test { 
    public $k; 
    function __construct() { 
     $c = new Calc; 
     $this->k = $c; //Just to show a similar situation than before 
     // $this-k = new Calc; produces the same error. 
    } 
} 

L'errore si verifica quando cerchiamo di chiamarlo come:

$t = new Test; 
echo $t->k(4,5); //Error: Call to undefined method Test::k() 

So che una "soluzione" potrebbe essere quella di avere una funzione all'interno della classe Test (chiamato k) per "inoltrare" la chiamata usando call_user_func_array ma non è elegante.

Ho bisogno di mantenere quell'istanza all'interno di una classe comune (per scopi di progettazione) ed essere in grado di chiamarla come funzione da altre classi ... qualche suggerimento?

Aggiornamento:

ho trovato qualcosa di interessante (almeno per i miei scopi):

Se si assegna il "variabile di classe" in una variabile locale funziona:

$t = new Test; 
$m = $t->k; 
echo $m(4,5); 
+0

Fornire un esempio di codice completo che mostra il problema. L'esempio di codice che dici funziona non funziona e l'esempio di codice che dici che un problema funziona. – Sjoerd

+0

Sì, mi dispiace, mio ​​male ... Lo aggiorno. Sjoerd: questo esempio ha funzionato per te? strano: S – lepe

risposta

5

Quando si do $test->k(), PHP pensa di chiamare un metodo sull'istanza $test. Poiché non esiste un metodo denominato k(), PHP genera un'eccezione. Quello che stai cercando di fare è rendere PHP restituire la proprietà pubblica k e invocarla, ma per farlo devi prima assegnare a k una variabile. È una questione di dereferenziazione.

Si potrebbe aggiungere il metodo magico __call alla classe Test per verificare se v'è una proprietà con la chiamata nome del metodo e invocare che invece se:

public function __call($method, $args) { 
    if(property_exists($this, $method)) { 
     $prop = $this->$method; 
     return $prop(); 
    } 
} 

lascio aggiungendo gli argomenti per l'invocazione a voi . Si potrebbe anche voler verificare se la proprietà is_callable.

Ma in ogni caso, allora si può fare

$test->k(); 
+0

Abbiamo pubblicato allo stesso tempo ... Sì, forse questo potrebbe aiutare ... Se non trovo altre alternative migliori segnerò la tua risposta come buona. – lepe

6

PHP pensa che si desidera chiamare un metodo k su istanza $ t quando si esegue:

$t->k(4, 5) 

che è perfettamente ragionevole. È possibile utilizzare una variabile intermedia per chiamare l'oggetto:

$b = $t->k; 
$b(4, 5); 

Vedi anche bug #50029, che descrive il problema.

+0

+1 per trovare il bug – Gordon

+0

(+1). Ora sta diventando chiaro per me. Grazie per il link. – lepe

2

Non è possibile utilizzare la sintassi del metodo (come $ foo-> bar()) per chiamare le chiusure o gli oggetti con __invoke, poiché il motore pensa sempre che si tratti di una chiamata di metodo. Puoi simularlo tramite __call:

function __call($name, $params) { 
    if(is_callable($this->$name)) { 
    call_user_func_array($this->$name, $params); 
    } 
} 

ma non funzionerebbe così com'è.

Problemi correlati