2 votes

En PHP, est-il possible de retourner une fonction constructeur d'une classe ?

Je me suis retrouvé dans une situation en PHP où j'ai besoin d'accéder au constructeur d'une classe sans savoir quelle est la classe. Je pourrais aborder cela d'un mauvais point de vue de conception, donc voici la situation - Je travaille dans Drupal, en écrivant une légère couche OO autour de leur manipulation de données sans classe pour permettre à certains développeurs non-Drupal de se joindre à moi sur un projet.

Dans Drupal, tout le contenu est considéré comme un nœud. J'ai donc créé une classe abstraite - Node. Tout contenu doit avoir un type de contenu spécifique. Avec l'OO, c'est facile - Je crée une classe Personne qui étend Node, ou une classe Événement qui étend Node, etc. Maintenant vient la partie délicate - une partie de mon projet permet à ces nœuds d'être "inclus" dans d'autres nœuds. C'est-à-dire que si le Nœud A inclut le Nœud B, alors chaque fois que A est affiché, les données de B sont affichées. Cela signifie que chaque fois que le Nœud A est instancié, il doit instancier également le Nœud B. MAIS... Node est une classe abstraite. Je ne peux donc pas instancier un Node brut. Je dois instancier l'une de ses classes implémentantes. Donc, autant que je puisse le dire, je dois soit écrire une fonction abstraite et statique que toutes les classes étendues doivent implémenter qui renvoie le constructeur...SOIT, je dois utiliser la réflexion d'une certaine manière pour déterminer le type, et appeler en quelque sorte le constructeur de classe approprié?

Sans tenir compte de Drupal, quelle est la manière la plus appropriée de gérer ce problème d'un point de vue de programmation PHP/OO?

Voici mon code:

title = $node->title;
        $this->body = $node->body['und'][0]['safe_value'];

        ##
        ## Définir l'URL propre si aliassée
        if (drupal_lookup_path('alias', 'node/'.$node->nid)) {
            $this->uri = '/'.drupal_lookup_path('alias', 'node/'.$node->nid);
        } else {
            $this->uri = '/node/'.$node->nid;
        }

        ##
        ## Définir le résumé court s'il existe, sinon forme courte du texte du corps
        if(strlen($node->body['und'][0]['safe_summary'])) {
            $this->short_summary = $node->body['und'][0]['safe_summary'];
        } else {
            $this->short_summary = text_summary($node->body['und'][0]['safe_value'], NULL, 100);
        }

        ##
        ## Définir le résumé complet à la concaténation du corps
        $this->full_summary = text_summary($node->body['und'][0]['safe_value'], NULL, 600);

        ##
        ## Ajouter le contenu inclus si le module est activé
        if (module_exists('content_inclusion')) {
            // est-ce possible? Existe-t-il un meilleur motif de conception disponible?
            $this->included_content = Node::get_constructor(node_load($node->content_inclusion['und'][0]['value']));
        }

    }

    public static abstract function get_all_published();
    public static abstract function get_by_nid($nid);
    public static abstract function get_constructor();
}

?>

2voto

mmmshuddup Points 5497

Est-ce que tu veux dire ceci ?

class MySubClass extends Node
{
    public static function get_constructor()
    {
        return new self();
    }
}

// ...

$object = MySubClass::get_constructor();

Ou si tu as PHP 5.3, tu peux utiliser late static binding avec lequel tu pourrais utiliser return new static(); ou $class = get_called_class(); return new $class();. Etc.

Exemple complet :

abstract class Node 
{
    public $test;

    public function __construct()
    {
        $this->test = 'Node';
    }

    public static function get_constructor()
    {
        return new static();
    }
}

class MySubClass extends Node
{
    public function __construct()
    {
        $this->test = __CLASS__ . PHP_EOL;
    }
}

// ...

$object = MySubClass::get_constructor();
echo $object->test; // affiche "MySubClass"

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X