2010-08-13 6 views
2

J'écrivais une classe qui utilise __get() et __set() pour stocker et récupérer des éléments de tableau dans un tableau maître. J'ai fait un chèque pour rendre certains éléments inoubliables, essentiellement pour recréer des propriétés privées. J'ai remarqué qu'il semblait que __get intercepte tous les appels aux propriétés de classe. Ça craint pour moi, parce que je voulais avoir une variable privée vers le monde extérieur (indisponible via get), mais j'essayais d'y accéder en référençant directement le tableau principal depuis l'intérieur de la classe. Bien sûr, le tableau de maître n'est pas dans la liste blanche des propriétés getTable :(Emule les propriétés publiques/privées avec __get() et __set()?

Est-il possible que je peux imiter les propriétés publiques et privées dans une classe php qui utilise __get() et __set()?

Exemple :

<? 

abstract class abstraction { 

    private $arrSettables; 
    private $arrGettables; 
    private $arrPropertyValues; 
    private $arrProperties; 

    private $blnExists = FALSE; 

    public function __construct($arrPropertyValues, $arrSettables, $arrGettables) { 

     $this->arrProperties = array_keys($arrPropertyValues); 
     $this->arrPropertyValues = $arrPropertyValues; 
     $this->arrSettables = $arrSettables; 
     $this->arrGettables = $arrGettables; 
    } 

    public function __get($var) { 
     echo "__get()ing:\n"; 
     if (! in_array($var, $this->arrGettables)) { 
      throw new Exception("$var is not accessible."); 
     } 

     return $this->arrPropertyValues[$var]; 
    } 

    public function __set($val, $var) { 
     echo "__set()ing:\n"; 
     if (! in_array($this->arrSettables, $var)) { 
      throw new Exception("$var is not settable."); 
     } 

     return $this->arrPropertyValues[$var]; 
    } 

} // end class declaration 

class concrete extends abstraction { 

    public function __construct($arrPropertyValues, $arrSettables, $arrGettables) { 
     parent::__construct($arrPropertyValues, $arrSettables, $arrGettables); 
    } 

    public function runTest() { 

     echo "Accessing array directly:\n"; 
     $this->arrPropertyValues['color'] = "red"; 
     echo "Color is {$this->arrPropertyValues['color']}.\n"; 

     echo "Referencing property:\n"; 
     echo "Color is {$this->color}.\n"; 
     $this->color = "blue"; 
     echo "Color is {$this->color}.\n"; 

     $rand = "a" . mt_rand(0,10000000); 
     $this->$rand = "Here is a random value"; 
     echo "'$rand' is {$this->$rand}.\n"; 

    } 
} 

try { 
    $objBlock = & new concrete(array("color"=>"green"), array("color"), array("color")); 
    $objBlock->runTest(); 
} catch (exception $e) { 
    echo "Caught Exeption $e./n/n"; 
} 

// no terminating delimiter 

$ php test.php 
Accessing array directly: 
__get()ing: 
Caught Exeption exception 'Exception' with message 'arrPropertyValues is not accessible.' in /var/www/test.php:23 
Stack trace: 
#0 /var/www/test.php(50): abstraction->__get('arrPropertyValu...') 
#1 /var/www//test.php(68): concrete->runTest() 
#2 {main}. 

Répondre

1

Est-il possible que je peux imiter les propriétés publiques et privées dans une classe php qui utilise __get() et __set()

Non dIrEC? Tly (si vous rabais debug_backtrace).

Mais vous pouvez avoir une méthode privée getPriv qui fait tout le travail que votre __get fait. Ensuite, __get n'envelopperait que cette méthode privée et vérifierait l'accessibilité.

function __get($name) { 
    if (in_array($name), $this->privateProperties) 
     throw new Exception("The property ". __CLASS__ . "::$name is private".); 
    return $this->getPriv($name); 
} 

l'intérieur de votre classe, vous appelleriez getPriv, contournant ainsi __get.

+0

Mais il y a encore un problème - puisque je suis stocker tout un tableau, 'getPriv()' a faire référence à la valeur dans la propriété de classe '$ arrPropertyValues', qui est interceptée par' __get() '... boucle infinie? – user151841

+0

Je serai sacrée! Ça marche! Mais pourquoi? Est-ce parce que '__get()' n'intercepte pas dans la classe d'origine? – user151841

+1

@user Il intercepte dans la classe d'origine - donc à l'intérieur de la classe vous devriez appeler 'getPriv'. Je ne suis pas sûr de vous avoir compris, mais '__get' n'intercepte pas les appels de méthode ou l'accès aux propriétés si les propriétés sont explicitement déclarées. – Artefacto

1

Protéger ou faire ce qu'Artefacto a écrit (si vous avez besoin de vérifications supplémentaires), sauf que abstraction::getPriv() doit être protégé.

+0

Protégé fait l'affaire! – user151841

1

Plutôt que enrôlant manuellement les propriétés privées/protégées, vous pouvez utiliser phps méthodes de réflexion encombrantes:

function __get($name) { 

    $reflect = new ReflectionObject($this); 
    $publics = $reflect->getProperties(ReflectionProperty::IS_PUBLIC); 

    if (in_array($name, $publics)) { 
     return $this->{$name}; 
    } 
} 
+0

Yummmm ... encombrant! :) – user151841

+1

cucumbersome pour être précis – mario

+0

Mmmmm .. cummerbunds .... – user151841

Questions connexes