2017-09-01 2 views
6

J'ai une question sur un comportement étrange.Appeler __call au lieu de __callstatic dans la même classe, pas si appeler une autre classe

Regardez ce code:

class User 
{ 
    public function can($name) { 
     return call_user_func(array($name, 'test')); 
    } 

    public static function __callStatic($name, $args) { 
     return 'User::__callStatic'; 
    } 

    public function __call($name, $args) { 
     return 'User::__call'; 
    } 
} 

class Foo 
{ 
    public static function __callStatic($name, $args) { 
     return 'Foo::__callStatic'; 
    } 

    public function __call($name, $args) { 
     return 'Foo::__call?'; 
    } 
} 

$u = new User(); 
var_dump($u->can('User')); 
var_dump($u->can('Foo')); 

Les résultats de la première décharge var est: "User :: __ appeler" Et le second: "Foo :: __ callStatic"

Pourquoi le premier n'appelle pas la fonction __callStatic? PS: Je regarde d'autres sujets, mais je n'ai trouvé aucune explication.

Merci

+0

ce code fonctionne: https://3v4l.org/E1gKl – Edwin

+0

@Edwin I savoir :) Ce n'est pas ma question, je m'attends à avoir "User :: __ callStatic" pour le premier var vidage –

+0

J'ai posté en réponse à d'autres commentaires qui sont maintenant supprimés – Edwin

Répondre

1

Ceci est juste un problème de portée lorsque vous appelez la call_user_func. Lorsque vous appelez la fonction can pour la première fois, vous êtes dans le contexte de la classe User et il faut __call. Dans le deuxième appel, votre contexte est de l'extérieur de la deuxième classe, donc il prend le __callStatic. Vérifiez callback manual et call-user-func.

Par exemple code:

<?php 

class User 
{ 
    public function can($name) { 
     return call_user_func(array($name, 'test')); 
    } 

    public static function __callStatic($name, $args) { 
     return 'User::__callStatic'; 
    } 

    public function __call($name, $args) { 
     return 'User::__call'; 
    } 
} 

class Foo 
{ 
    public function can($name) { 
     return call_user_func(array($name, 'test')); 
    } 

    public static function __callStatic($name, $args) { 
     return 'Foo::__callStatic'; 
    } 

    public function __call($name, $args) { 
     return 'Foo::__call?'; 
    } 
} 

    function can($name) { 
     return call_user_func(array($name, 'test')); 
} 

$u = new User(); 
$f = new Foo(); 
var_dump($u->can('User')); 
var_dump($u->can('Foo')); 
var_dump($f->can('User')); 
var_dump($f->can('Foo')); 
var_dump(can('User')); 
var_dump(can('Foo')); 

retournera:

string(12) "User::__call" 
string(17) "Foo::__callStatic" 
string(18) "User::__callStatic" 
string(12) "Foo::__call?" 
string(18) "User::__callStatic" 
string(17) "Foo::__callStatic" 
+2

Portée est le mauvais mot, * contexte * est ce que vous cherchez. La question est de savoir pourquoi PHP décide que 'call_user_func (['User', ...])' dans un contexte 'User' est un appel d'instance, alors que dans un autre contexte, il est statique. – deceze

+0

oui le contexte est meilleur. Si vous voulez rendre la fonction 'can' statique, cela retournera le' __callStatic', donc je pense que php essaie de trouver d'abord les fonctions au même niveau (si cela a du sens). – Edwin

0

Merci tous les deux.

Oui cela est dû à contexte, est-ce un bug de PHP (correctif dans la version ultérieure, pas dans 7.2, donc ...;)) ou est-ce juste un comportement étrange.

@Edwin Je sais si je transforme la fonction can() en statique, cela fonctionnera, mais je ne veux pas. Pour résoudre le « problème », j'appelle la fonction __callStatic() dans ma fonction can() que dans le cas d'appeler auto classe:

if($name instanceof User) return self::__callStatic($functionName, $args);