2010-09-17 6 views
0

Cela peut être impossible, mais je pensais que je demande avant que je retravaille le tout ...:Protéger une propriété d'objet sans connaître son nom à l'avance

J'ai une classe d'objet qui peut recevoir des « morceaux », qui sont aussi des objets. Il fonctionne essentiellement comme ceci:

class myObject { 
    //Receives an associative array of "Piece" objects 
    function __construct($objects) { 
     foreach($objects as $k=>$v) { 
      $this->{$k} = $v; 
     } 
    } 
} 

J'omettant beaucoup de code évidemment, mais j'espère que cela vous donne l'idée. Fondamentalement, j'ai une tonne d'objets "pièce" différents qui font des choses différentes, et si je passe un tableau d'entre eux en myObject puis myObject devient une classe très flexible et utile pour faire toutes sortes de choses différentes. Donc, je pourrais utiliser ceci pour créer un objet Book et avoir des pièces qui comprenaient une "pièce d'auteur" et une "pièce d'ISBN", et ces pièces sauraient comment valider des données etc. Donc je pourrais avoir $book avec des objets définir les variables membres author et isbn.

C'est grand parce que je peux faire des choses comme:

echo $book->author; //all Pieces have a __toString() method. 
echo $book->author->firstName; 
$book->author->showBio(); 
$book->author->contactForm(); 

... et ainsi de suite.

Maintenant, au point. Ce système fonctionne très bien, et l'une des choses qui le rend génial est que je peux choisir n'importe laquelle de ces pièces que j'aime et les coller dans un objet pour les lier ensemble.

Mais le problème est, je ne veux pas que quelqu'un d'autre qui pourrait utiliser le code plus tard pour essayer:

$book->author = "John Doe"; 

... parce qu'alors ils avaient tout simplement avoir une valeur au lieu de l'objet auteur. Je voudrais que pour leur donner une erreur et leur demander de le faire à la place:

$book->author->setName("John Doe"); 

parce que je ne sais pas à l'avance quelles pièces pourraient être dans un objet individuel (et le point entier doit être capable d'avoir la liberté d'assembler instantanément tout type d'objet), je ne peux pas simplement mettre private $author dans la déclaration de classe.

J'ai essayé un peu avec __get() et __set() un peu, mais je ne pouvais pas le faire fonctionner sans compromettre la fonctionnalité des objets comme ils le sont maintenant. Donc, comme je l'ai dit, je sais que c'est peut-être impossible, mais avant que j'abandonne, j'ai pensé que je demanderais. Y at-il un moyen de protéger la propriété d'un objet après qu'il a été créé sans le déclarer dans la définition de la classe?

+0

Pour ajouter quelques précisions, je voudrais particulièrement savoir s'il y a un moyen de laisser les objets là où ils sont (comme propriétés du objet liant) et les protéger sans savoir à l'avance quel ensemble particulier d'objets sera dans un classeur particulier. – Andrew

Répondre

3

Ce n'est absolument pas impossible. Vous devez remplacer les fonctions magiques __get et __set

Comme ceci:

class myObject { 
    protected $data = array(); 

    public function __construct($objects) { 
    foreach($objects as $k=>$v) { 
     $this->data[$k] = $v; 
    } 
    } 

    /* your code */ 

    public function __get($name) { 
    if(array_key_exists($name, $this->data)) { 
     return $this->data[$name]; 
    } 
    return null; 
    } 
+0

Ok, mais le problème est d'éviter que quelqu'un essaie de définir une valeur en utilisant $ object-> value = 'foo'; Dans votre exemple, ils retourneront l'objet "piece" si quelqu'un a demandé à l'obtenir, au lieu de déclencher la méthode __toString().Ils devraient également utiliser $ object-> data-> someProperty-> doSomething() pour accéder aux méthodes au lieu de $ object-> someProperty-> doSomething(). Je vois comment coller les objets dans une propriété $ data protégée pourrait résoudre certains des problèmes, mais cela signifierait retravailler beaucoup d'autres codes qui dépendent de toutes les propriétés de l'objet conteneur étant eux-mêmes des objets .... – Andrew

+0

Merci pour la suggestion , bien que! (désolé pour deux messages, limite de caractères!) – Andrew

+0

@Andrew, '$ object-> data' ne serait pas accessible car il est protégé. Les clients feraient '$ object-> someProperty-> doSomething().' Aussi, '$ object-> value = 'foo'' ne déclencherait pas' __get' mais plutôt '__set'. Dans votre fonction '__set', placez une vérification' is_string'. – webbiedave

Questions connexes