2010-10-27 12 views
3

Fondamentalement, ce que j'essaie de réaliser est de faire référence à l'objet d'un autre objet de la même classe - depuis l'intérieur d'une méthode. Ce serait parfait si ce qui suit fonctionnerait:

$this = new self; 

Mais on ne peut pas réattribuer $this en php. Je sais bien sûr, je peux retourner un autre objet de la méthode et l'utiliser, alors s'il vous plaît ne pas conseiller. La question est:

Comment puis-je faire de $this un clone d'un autre objet de la même classe?

ou plus précisément,

Je veux un objet à revenir à un état spécifique qui a été précédemment enregistré.


EDIT: quelques exemples où cela pourrait être utile.

Supposons que vous ayez un objet Url qui accepte le contrôleur, l'action et bien d'autres choses. Vous allez devoir chercher beaucoup de liens avec le même, par exemple, le contrôleur et l'action, mais d'autres propriétés seront différentes. J'instancie l'objet avec les paramètres communs, appelle une méthode pour qu'il sauvegarde son état auquel il retourne après sortie d'un lien (IOW après la méthode __toString).

$defaultPath = Url::factory('controller','action1')->extraParams('status',0)->save(); 

echo $defaultPath->action('action2'); // this has action2 as action and a status 0 as extra params 
echo $defaultPath->extraParams('status',2); // this has action1 as action and 2 as status 

Une autre utilisation est I une table CLMS et je configurer chaque colonne comme un objet je passe à l'objet principal de la table. Après avoir passé la colonne I lancer une méthode de remise à zéro sur la colonne, donc je peux avoir le code comme ce qui suit:

$column->field = 'layouts_id'; 
    $column->value = $layoutId; 
    $dbInput->addColumn($column); 

    $column->field = 'pages_id'; 
    $column->value = $pagesId; 
    $dbInput->addColumn($column); 

Dans les deux cas, j'économiser beaucoup de code et de la confusion, ne pensez-vous pas?

Répondre

3

Je vois un énorme problème avec ce que vous avez l'intention:

Si vous avez trouvé un moyen de réattribuer $this, comment vous assurez-vous que toute personne qui utilise votre classe sait comment se comporte-t-il? Bien que je l'avoue, qu'il est un peu intéressant à faire

$column->field = 'layouts_id'; 
$column->value = $layoutId; 
$dbInput->addColumn($column); 

$column->field = 'pages_id'; 
$column->value = $pagesId; 
$dbInput->addColumn($column); 

Qu'est-ce qui se passe, si j'ai besoin $column deux fois?

$column->field = 'layouts_id'; 
$column->value = $layoutId; 
$dbInput->addColumn($column); 
// log my value 
$logger->log($column); // oops, it's empty 

... 

Vous casser le comportement attendu et à mon avis, il est extrêmement difficile de saisir votre code.


Mais pour donner quelques idées sur la façon d'atteindre encore le comportement mentionné ci-dessus:

// clone when passing on 
$column->field = 'value_id'; 
$column->value = $value; 
$dbInput->addColumn(clone $column); 

// manually (re-)create a new object based on an older 
$column->field = 'value_id'; 
$column->value = $value; 
$dbInput->addColumn(new Column($column)); 


Sinon, la méthode reset() semble également possible:

class Column() { 

    public function reset() { 
     $this->field = 'standard field id'; 
     $this->value = 'standard field value'; 
    } 

    public function __construct() { 
     $this->reset(); 
    } 

} 

De cette façon, vous pouvez l'utiliser comme ceci:

// manually (re-)create a new object based on an older 
$column->field = 'value_id'; 
$column->value = $value; 
$dbInput->addColumn($column); 
$column->reset(); 


Pour résoudre le problème de spécifier les valeurs par défaut deux fois (non testé):

class Column() { 

    public $field = 'standard field id'; 
    public $value = 'standard field value'; 

    // keep a static object for resetting 
    private static $__blueprint = null; 

    public function reset() { 
     foreach (self :: $__blueprint as $k => $v) 
      $this->$k = $v; 
    } 

    public function __construct() { 
     if (!isset(self :: $__blueprint)) 
      self :: $__blueprint = clone $this; 
    } 

} 
+0

on le clonerait avant de le passer au La méthode addColumn, ou l'écrasement peut être rendu facultatif (par exemple, '$ dbInput-> addColumn ($ column, TRUE);' ne réinitialiserait pas la colonne, c'est un snap à implémenter.) – raveren

+0

Mais encore, ce n'est pas ce à quoi quelqu'un s'attendrait . Quand j'utilise un objet, je veux y faire face. Je ne voudrais pas d'une méthode de lecture d'une classe non apparentée pour effacer mon objet. C'est comme si vous prêtiez votre livre à quelqu'un qui efface les lettres quand il a fini de lire. (Et je ne voudrais pas lui dire explicitement, qu'il ne devrait pas les effacer.Comme je l'ai dit, ce n'est pas un comportement que vous attendez normalement) –

+0

pour refléter vos modifications: Je ne voudrais pas d'étapes supplémentaires dans l'initialisation de la table CRUD, même si elles sont valides (donc, +1). Cependant, la méthode de réinitialisation ne conserve pas le code DRY, vous devez synchroniser les valeurs initiales à deux endroits et c'est juste une bombe à retardement. – raveren

1

Ce que vous demandez n'a pas de sens dans OOP. La variable this (ou tout autre équivalent dans la langue OOP de votre choix) doit toujours pointer vers l'instance en cours et ne doit jamais être modifiée. C'est ce pour quoi il est conçu.

+0

modifié la question afin de refléter les utilisations possibles, OMI sensibles pour ce modèle. – raveren

1

Vous ne pouvez pas affecter une valeur à $this en PHP. Il contiendra toujours l'objet actuel, et cela ne peut pas être changé.

Il semble que vous essayez de modifier toutes les références à la classe actuelle pour qu'elles pointent vers une classe différente. Il n'y a aucun moyen d'accomplir cela.

Le meilleur travail auquel je puisse penser est d'avoir une variable membre $copy dans votre classe. Vous pouvez ensuite vérifier si $copy n'est pas nul et passer toutes les méthodes à cet objet à la place. Cependant, cela vous laissera toujours avec votre objet original en mémoire. Si votre exemple hypothétique $this = new self; fonctionnait, il serait vraisemblablement destiné à réinitialiser efficacement l'objet à un état propre.

2

Vous ne pouvez pas réaliser cela comme vous l'avez demandé, mais vous pouvez certainement le faire assez facilement en écrivant une méthode reset() qui définit toutes les propriétés à leur état initial, puis appelle la méthode __constructor().

Si vous voulez aller plus loin et cloner une autre instance de la classe depuis l'objet qui deviendra le clone (selon la dernière partie de votre question), cela sera beaucoup plus difficile. Vous ne serez certainement pas capable de le faire d'une manière agréable. Vous pourriez être en mesure de le truquer en écrivant une méthode qui prend l'objet à cloner comme un paramètre et définit par référence toutes les propriétés de l'objet actuel aux propriétés de l'autre objet. Ce serait seulement possible bien sûr si toutes les propriétés étaient publiques, mais vous pourriez l'essayer. Certainement pas idéal cependant. Il est de loin préférable de le faire de l'extérieur de l'un ou l'autre des objets ... mais vous avez dit de ne pas suggérer que ...;)

+0

[..] méthode reset() qui initialise toutes les propriétés à leur état initial, puis appelle la méthode __constructor(). raveren

+0

$ cela ne devrait jamais changer - et PHP est construit de cette façon, donc vous aurez des problèmes avec la conception du noyau PHP. 'function reset() {foreach ((tableau) $ this comme $ k => $ v) unset ($ this -> $ k);}' – Xeoncross

+0

@Xeoncross, en ce qui concerne la suggestion de méthode, et si certains champs sont instanciés avec un valeur? 'class A {public $ b = 'c';}' – raveren

1

Ce que je pense que vous obtenez est fondamentalement le Flyweight Design Pattern. Vous ne le faites pas par re-mapping $this, mais vous créez vos objets de telle manière qu'ils puissent être réutilisés sans avoir besoin de construire sans cesse et détruire les ...

Couple qui avec le motif de conception Object Pool , et vous devriez être en or ...

+0

Non, ce n'est pas ça, mais le motif est en effet intéressant, je vais le garder à l'esprit. La question est-elle trop vague? – raveren

+0

Eh bien, ce n'est pas ** ce que ** vous essayez de faire, mais cela résout le même problème (si je comprends votre question en premier lieu). Rendre les objets bon marché et réutilisables. Bien sûr, il le fait d'une manière différente, mais il est toujours applicable.(Oh, et je ne vais même pas répondre à la question "Vous ne pouvez pas attribuer une valeur à' $ this' ", puisque d'autres personnes y ont déjà répondu très bien) ... – ircmaxell