114 votes

Dans un projet PHP, quels modèles existent pour stocker, accéder et d'organiser les objets d'aide?

Comment vous organiser et de gérer vos objets d'assistance comme le moteur de base de données, notification de l'utilisateur, la gestion des erreurs et ainsi de suite dans une en PHP, orienté objet projet?

Dire que j'ai un gros CMS PHP. Le CMS est organisé dans les différentes classes. Quelques exemples:

  • l'objet de base de données
  • gestion des utilisateurs
  • une API pour créer/modifier/supprimer des éléments
  • une messagerie objet pour afficher des messages à l'utilisateur final
  • un gestionnaire de contexte qui vous amène à la page de droite
  • une barre de navigation de la classe qui affiche les boutons
  • un objet connexion
  • éventuellement, une gestion d'erreur personnalisée

etc.

Je fais affaire avec l'éternelle question, comment faire en sorte que ces objets accessibles à chaque partie du système qui en ont besoin.

mon premier apporach, il y a plusieurs années a été de $demande mondiale qui contenait initialisé instances de ces classes.

global $application;
$application->messageHandler->addMessage("Item successfully inserted");

J'ai ensuite changé sur le pattern Singleton et d'une usine de la fonction:

$mh =&factory("messageHandler");
$mh->addMessage("Item successfully inserted");

mais je ne suis pas heureux avec cela. Les tests unitaires et d'encapsulation et deviennent de plus en plus important pour moi, et dans ma compréhension de la logique derrière globals/singletons détruit l'idée de base de la programmation orientée objet.

Ensuite il y a évidemment la possibilité de donner à chaque objet un certain nombre de pointeurs vers les objets d'assistance dont il a besoin, probablement la plus propre, d'économie des ressources et de test de manière conviviale, mais j'ai des doutes sur la facilité de maintenance de ce sur le long terme.

La plupart des frameworks PHP, j'ai cherché à utiliser le pattern singleton, ou des fonctions que l'accès aux objets initialisés. À la fois fine approches, mais comme je l'ai dit, je suis heureux avec aucun des deux.

Je voudrais élargir mon horizon sur quels modèles existent pas ici. Je suis à la recherche d'exemples, des idées et des pointeurs vers des ressources qui traitent de ce de un à long terme, dans le monde réel point de vue.

Aussi, je suis intéressé à entendre parler spécialisés, de niche ou de la plaine bizarre approches de la question.

68voto

koen Points 4770

Je voudrais éviter de le Singleton approche proposée par Flavius. Il existe de nombreuses raisons pour éviter cette approche. Elle viole les bons principes de la programmation orientée objet. Le google blog de tests a quelques bons articles sur le Singleton et comment l'éviter:

http://googletesting.blogspot.com/2008/08/by-miko-hevery-so-you-join-new-project.html http://googletesting.blogspot.com/2008/05/tott-using-dependancy-injection-to.html http://googletesting.blogspot.com/2008/08/where-have-all-singletons-gone.html

Alternatives

  1. un fournisseur de service

    http://java.sun.com/blueprints/corej2eepatterns/Patterns/ServiceLocator.html

  2. l'injection de dépendance

    http://en.wikipedia.org/wiki/Dependency_injection

    et un php explication:

    http://components.symfony-project.org/dependency-injection/trunk/book/01-Dependency-Injection

C'est un bon article sur ces alternatives:

http://martinfowler.com/articles/injection.html

La mise en œuvre de l'injection de dépendance (DI):

Quelques idées sur Flavius de la solution. Je ne veux pas que ce post pour être un anti-post, mais je pense qu'il est important de voir pourquoi l'injection de dépendance est, au moins pour moi, mieux que globales.

Même si ce n'est pas un "vrai" Singleton mise en œuvre, je pense toujours que Flavius eu tort. L'état Global est mauvais. Notez que ces solutions utilisent également difficile de tester des méthodes statiques.

Je sais que beaucoup de gens le font, de les approuver et de les utiliser. Mais la lecture de Misko Heverys articles de blog (google testabilité d'experts), de la relecture et à digérer lentement ce qu'il dit ne modifie pas la façon dont je vois le design d'un lot.

Si vous voulez être en mesure de vous tester l'application, vous aurez besoin d'adopter une approche différente de la conception de votre application. Lorsque vous faites le test-première de la programmation, vous aurez de la difficulté avec ce genre de choses: "la prochaine je veux mettre en œuvre l'exploitation forestière dans ce morceau de code; écrivons un test de la première qui enregistre un message de base" et viennent ensuite avec un test qui vous oblige à écrire et utiliser un mondial enregistreur de frappe qui ne peut pas être remplacé.

Je suis toujours du mal avec toutes les informations que j'ai obtenu à partir de ce blog, et il n'est pas toujours facile à mettre en œuvre, et j'ai beaucoup de questions. Mais il n'y a aucun moyen que je peux revenir à ce que j'ai fait avant (oui, l'état global et les Singletons (grand S)) après que j'ai compris ce que Misko Hevery disait :-)

16voto

Flavius Points 6115
class Application {
    protected static $_singletonFoo=NULL;

    public static function foo() {
        if(NULL === self::$_singletonFoo) {
            self::$_singletonFoo = new Foo;
        }
        return self::$_singletonFoo;
    }

}

C'est la façon dont je le ferais. Il crée l'objet à la demande:

Application::foo()->bar();

C'est la façon dont je le fais, il respecte les principes de la programmation orientée objet, c'est moins de code que de la façon dont vous le faites maintenant,et l'objet est créé uniquement lorsque le code a besoin d'elle pour la première fois.

Note: ce que j'ai présenté n'est même pas un vrai pattern singleton. Un singleton serait de n'autoriser qu'une seule instance de lui-même en définissant le constructeur (Foo::__constructor()) comme privé. Il est seulement un "global" variable disponible pour tous "Demande" en cas. C'est pourquoi je pense que son utilisation est valable qu'elle ne fait PAS abstraction de bons principes de la programmation orientée objet. Bien sûr, comme n'importe quoi dans le monde, ce "modèle" ne doit pas être galvaudé!!!!

Je l'ai vu utilisé dans de nombreux frameworks PHP, Zend Framework et Yii entre eux. Et vous devez utiliser un framework. Je ne vais pas vous dire lequel.

Addendum Pour ceux d'entre vous soucier de TDD, vous pouvez toujours faire un peu de câblage de la dépendance à l'injecter. Il pourrait ressembler à ceci:

class Application {
        protected static $_singletonFoo=NULL;
        protected static $_helperName = 'Foo';

        public static function setDefaultHelperName($helperName='Foo') {
                if(is_string($helperName)) {
                        self::$_helperName = $helperName;
                }
                elseif(is_object($helperName)) {
                        self::$_singletonFoo = $helperName;
                }
                else {
                        return FALSE;
                }
                return TRUE;
        }
        public static function foo() {
                if(NULL === self::$_singletonFoo) {
                        self::$_singletonFoo = new self::$_helperName;
                }
                return self::$_singletonFoo;
        }
}

Il y a assez de place pour l'amélioration. C'est juste un PoC, utilisez votre imagination.

Pourquoi le faire comme ça? Eh bien, la plupart du temps, l'application ne sera pas de l'unité testée, il va être exécuté, nous l'espérons, dans un environnement de production. La force de PHP est sa vitesse. PHP n'est PAS et ne sera jamais un "nettoyage de la programmation orientée objet du langage", comme Java.

Au sein d'une application, il y a une seule classe d'Application et une seule occurrence de chacun de ses assistants, tout au plus (comme par chargement paresseux comme ci-dessus). Bien sûr, les singletons sont mauvais, mais là encore, seulement s'ils n'adhèrent pas au monde réel. Dans mon exemple, ils le font.

Stéréotypés "règles" comme "les singletons sont des mauvais" sont la source du mal, ils sont pour les gens paresseux ne veulent pas penser par eux-mêmes.

Ouais, je sais, le PHP manifeste est MAUVAIS, techniquement parlant. Pourtant, c'est une réussite de la langue, dans son hackish.

Addendum

Une fonction du style:

function app($class) {
    static $refs = array();

    //> Dependency injection in case of unit test
    if (is_object($class)) {
        $refs[get_class($class)] = $class;
        $class = get_class($class);
    }

    if (!isset($refs[$class]))
        $refs[$class] = new $class();

    return $refs[$class];
}

//> usage: app('Logger')->doWhatever();

15voto

Thomas Points 1159

J'aime le concept de l'Injection de Dépendance:

"L'Injection de dépendance est l'endroit où les composants sont donné leurs dépendances, grâce à leurs constructeurs, méthodes, ou directement dans les champs. (À Partir De Pico Conteneur De Site Web)"

Fabien Potencier a écrit une très belle série d'articles sur l'Injection de Dépendance et le besoin de les utiliser. Il offre également une belle et petite Conteneur d'Injection de Dépendance nommé Bourgeon qui j'ai vraiment beaucoup (plus d'infos sur github).

Comme indiqué ci-dessus, je n'aime pas l'utilisation de Singletons. Un bon résumé sur pourquoi les Singletons ne sont pas une bonne conception peut être trouvé ici, dans Steve Yegge du blog.

9voto

takeshin Points 16579

La meilleure approche est d'avoir une sorte de conteneur pour ces ressources. Certains des façons les plus courantes pour mettre en œuvre ce conteneur:

Singleton

Pas recommandé, car il est difficile de tester et implique un état global. (Singletonitis)

Registre

Élimine singletonitis, bug je n'avais pas recommander de registre aussi, parce que c'est une sorte de singleton. (Dure de test de l'unité)

L'héritage

Dommage, il n'y a pas d'héritage multiple en PHP, ce qui limite l'ensemble de la chaîne.

L'injection de dépendance

C'est une meilleure approche, mais une question importante.

Traditionnelle

La façon la plus simple de le faire est d'utiliser le constructeur ou l'injection par mutateur (passer de la dépendance de l'objet à l'aide de setter ou dans le constructeur de la classe).

Cadres

Vous pouvez rouler votre propre dépendance de l'injecteur, ou à l'aide de certains de l'injection de dépendance des cadres, par exemple. Yadif

Demande de ressources

Vous pouvez initialiser chacun de vos ressources dans l'application de bootstrap (qui agit comme un conteneur), et d'y accéder de n'importe où dans l'application accédant à l'amorçage de l'objet.

C'est la démarche mise en œuvre dans le Zend Framework 1.x

Chargeur de ressources

Un type d'un objet statique qui charge (crée) les ressources nécessaires uniquement lorsque cela est nécessaire. C'est une approche très intelligente. Vous pouvez la voir en action par exemple, la mise en œuvre de Symfony composant d'Injection de Dépendance

L'Injection de couche spécifique

Les ressources ne sont pas toujours nécessaires, n'importe où dans l'application. Parfois, vous avez juste besoin par exemple dans les contrôleurs (MV C ). Ensuite, vous pouvez injecter des ressources uniquement.

L'approche commune de ce qui est à l'aide de docblock des commentaires à ajouter injection de métadonnées.

Voir mon approche de ce sujet ici:

Comment utiliser l'injection de dépendance dans le Zend Framework? - Débordement De Pile

En fin de compte, je voudrais ajouter une remarque à propos de quelque chose de très important ici de la mise en cache.
En général, malgré la technique que vous choisissez, vous devriez penser à la façon dont les ressources seront mises en cache. Le cache sera la ressource elle-même.

Les applications peuvent être très gros, et le chargement de toutes les ressources sur chaque demande est très cher. Il existe de nombreuses approches, notamment en ce appserver-en-php - Projet d'Hébergement sur Google Code.

6voto

Felix Kling Points 247451

Si vous voulez faire des objets disponibles dans le monde, le registre de modèle pourrait être intéressant pour vous. Pour l'inspiration, jetez un oeil à Zend Registre.

De même le Registre contre Singleton question.

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