2010-01-11 7 views
22

En utilisant PHP 5.3, je rencontre un comportement bizarre/non-intuitif lorsque j'applique empty() aux propriétés d'objets dynamiques récupérées via la fonction de surcharge __get(). Considérons l'extrait de code suivant:PHP empty() sur __get accessor

<?php 

class Test { 

    protected $_data= array(
    'id'=> 23, 
    'name'=> 'my string' 
); 

    function __get($k) { 
    return $this->_data[$k]; 
    } 

} 

$test= new Test(); 
var_dump("Accessing directly:"); 
var_dump($test->name); 
var_dump($test->id); 
var_dump(empty($test->name)); 
var_dump(empty($test->id)); 

var_dump("Accessing after variable assignment:"); 
$name= $test->name; 
$id= $test->id; 
var_dump($name); 
var_dump($id); 
var_dump(empty($name)); 
var_dump(empty($id)); 

?> 

La sortie de cette fonction est la suivante. Comparez les résultats des empty() contrôles sur les premier et second ensembles de résultats:

Set # 1, résultat inattendu:

string(19) "Accessing directly:" 
string(9) "my string" 
int(23) 
bool(true) 
bool(true) 

Expecting Set # 1 pour retourner le Set # 2:

string(36) "Accessing after variable assignment:" 
string(9) "my string" 
int(23) 
bool(false) 
bool(false) 

Ceci est vraiment déroutant et non intuitif. Les propriétés de l'objet produisent des chaînes non vides, mais empty() les considère comme des chaînes vides. Que se passe t-il ici?

+2

Cela semble vraiment étrange. Mon seul point de vue est que empty(), étant une construction de langage, contourne en quelque sorte la fonction getter. Mais ce serait un énorme bug dans ma compréhension - il doit y avoir une meilleure explication. Intéressé de voir ce qui arrive. –

+0

intéressant, 'isset()' renvoie vrai lors de l'accès directement. – nickf

+0

Alan Storm a bien compris, il y a une fonction magique __isset qui est appelée quand un membre est vérifié par empty(). –

Répondre

28

Sur la base de la lecture de la page de manuel d » empty et commentaires (Ctrl-F pour isset et/ou double underscores), il semble que ce comportement est connu, et si vous voulez que vos méthodes __set et __get et empty à jouer sympa ensemble, il y a une supposition implicite que vous implémentez une méthode magique __isset ainsi.

C'est un peu inintéressant et déroutant, mais cela a tendance à se produire avec la plupart des méta-programmations, en particulier dans un système comme PHP.

+0

Vous me battez de soixante secondes :) Je pense que cela résout la question, bien qu'il soit extrêmement contre-intuitif que la méthode magique __isset renvoie false par défaut. –

+0

donc '__isset' est invoqué quand vous appelez' empty() 'mais pas quand vous appelez' isset() '?? – nickf

+2

Par le manuel, __isset doit être invoqué lors de l'utilisation de l'une ou l'autre fonction. L'implication de ce que j'ai lu est qu'il n'y a pas de comportement défini pour appeler isset ou vide avec des méthodes magiques quand il n'y a pas de fonction __isset. –

3

Dans cet exemple, empty() appelle la fonction de surcharge __isset(), et non la fonction de surcharge __get(). Essayez ceci:

class Test { 

    protected $_data= array(
    'id'=> 23, 
    'name'=> 'my string' 
); 

    function __get($k) { 
    return $this->_data[$k]; 
    } 

    function __isset($k) { 
    return isset($this->_data[$k]); 
    } 

} 
Questions connexes