59 votes

Puis-je inclure du code dans une classe PHP?

Je veux faire une classe PHP, permet de dire Myclass.php. Maintenant à l'intérieur de cette classe, je veux définir la classe elle-même et certaines variables d'instance. Mais toutes les méthodes doivent provenir d'une Myclass_methods.php fichier. Puis-je inclure ce fichier dans le corps de la classe?

J'ai de bonnes raisons pourquoi je veux les séparer cette. Bref, je vais avoir un back-end où je peux changer la logique métier d'une classe, alors que toutes les autres choses qui doivent rester intactes. Le système gère toutes les ORM et d'autres choses pour moi.

Mais si c'est une mauvaise idée, il pourrait être préférable de re-générer l'ensemble de la classe fichier après l'édition de la logique métier (donc, les méthodes définies par l'utilisateur dans ce cas).

Les performances de la question: Si lors d'une demande de Myclass.php est inclus qu'une seule fois, en fait, que Myclass_methods.php devraient également être inclus qu'une seule fois. Peut-être tort. Les Experts?

174voto

Gordon Points 156415

Pas de. Vous ne pouvez pas inclure les fichiers dans le corps de la classe.
Dans un fichier de définition d'une classe, vous ne pouvez inclure des fichiers dans un corps de méthode ou à l'extérieur du corps de classe.

À partir de votre description je vous le voulez ce:

<?php // MyClass.php
class MyClass
{
    protected $_prop;
    include 'myclass-methods.php';
}

<?php // myclass-methods.php
public function myMethod()
{
   $this->$_prop = 1;
}

L'exécution de ce code entraînera

Parse error: syntax error, unexpected T_INCLUDE, expecting T_FUNCTION

Ce qui est possible mais est-ce

<?php // MyClass.php
class MyClass
{
    protected $_prop;
    public function __construct() // or any other method
    {
        include 'some-functions.php';
        foo($b); // echoes 'a';
    }
}

<?php // some-functions.php
$b = 'a';
function foo($str)
{
   echo $str;
}

Faisant de cette façon, va importer le contenu d'un fichier à inclure dans la portée de la méthode, pas à la portée de classe. Vous pouvez inclure des fonctions et des variables dans le fichier include, mais pas les méthodes. Vous pourriez, mais ne devrait pas mettre des scripts complets ainsi modifier la méthode est le cas, par exemple,

<?php // MyClass.php
    // ...
    public function __construct($someCondition)
    {
        // No No Code here
        include ($someCondition === 'whatever') ? 'whatever.php' : 'default.php';
    }
    // ...

<?php // whatever.php
    echo 'whatever';

<?php // default.php
    echo 'foo';

Toutefois, l'application de correctifs à la classe de cette façon à exposer les différentes comportement n'est pas la façon dont vous devriez le faire en POO. C'est tout simplement faux et devrait rendre vos yeux saignent.

Puisque vous voulez modifier dynamiquement le comportement, l'extension de la classe est également pas une bonne option (voir ci-dessous pourquoi). Vraiment ce que vous voulez faire est d'écrire une interface et de rendre votre utilisation des objets implémentant cette interface, afin de s'assurer que les méthodes appropriées sont disponibles. Ceci est appelé un Modèle de Stratégie et fonctionne comme ceci:

<?php // Meowing.php 
interface Meowing
{
    public function meow();
}

Maintenant vous avez obtenu le contrat que tous les Miaulements des Comportements doit obéir, à savoir avoir un miaulement méthode. Prochaine définir un Miaulement Comportement:

<?php // RegularMeow.php
class RegularMeow implements Meowing
{
    public function meow()
    {
        return 'meow';
    }
}

Maintenant pour l'utiliser, utilisez:

<?php // Cat.php
class Cat
{
    protected $_meowing;

    public function setMeowing(Meowing $meowing)
    {
        $this->_meowing = $meowing;
    }

    public function meow()
    {
        $this->_meowing->meow()
    }
}

En ajoutant le Miaulement TypeHint à setMeowing, vous assurez-vous que le passé param met en œuvre le Miaulement de l'interface. Nous allons définir un autre Miaulement Comportement:

<?php // LolkatMeow.php
class LolkatMeow implements Meowing
{
    public function meow()
    {
        return 'lolz xD';
    }
}

Maintenant, vous pouvez facilement interchange des comportements comme ceci:

<?php
require_once 'Meowing.php';
require_once 'RegularMeow.php';
require_once 'LolkatMeow.php';
require_once 'Cat.php';

$cat = new Cat;
$cat->setMeowing(new RegularMeow);
echo $cat->meow; // outputs 'meow';
// now to change the behavior
$cat->setMeowing(new LolkatMeow);
echo $cat->meow; // outputs 'lolz xD';

Alors que vous pourriez également avoir résolu le dessus avec de l'héritage par la définition d'un résumé BaseCat et miaou méthode, puis dérivant de béton RegularCat et Lolkat classes de cela, vous devez tenir compte de ce que vous voulez atteindre. Si votre chat ne sera jamais à changer la façon de miauler, aller de l'avant et à l'utilisation de l'héritage, mais si votre RegularCat et Lolkat est censé être capable de faire arbitraire miaule, puis utilisez le modèle de Stratégie.

Pour plus de design patterns en PHP, vérifiez ces ressources:

9voto

middaparka Points 33832

Ne serait-ce pas une idée de créer la classe principale avec les fonctionnalités de base pertinentes, puis de l'étendre avec les méthodes requises - cela semble être une approche plus logique.

6voto

ldrut Points 789

Je vais commencer par dire que je ne suis pas trop clair pourquoi ce problème n'est pas le plus résolu en utilisant une base de classe contenant des méthodes, des sous-classes contenant les données, et de la dynamique de la classe de chargement. Je vais supposer que vous avez une bonne raison.

Une fois que votre fournisseur prend en charge le PHP 5.4, vous pouvez faire ce que vous voulez à l'aide de traits.

Le Fichier De Code:

if ($pet === 'dog') include 'dog.php';
elseif ($pet === 'cat') include 'cat.php';
else die('Unknown pet');

class Pet {
  use PetSounds;
}

$myPet = new Pet();
$myPet->speak();

Fichier cat.php

trait PetSounds {
  function speak() { echo 'meow'; }
}

Fichier dog.php

trait PetSounds {
  function speak() { echo 'woof'; }
}

Vous pouvez faire ce même cleaner en nommant les deux fichiers à inclure les mêmes, en les mettant dans des sous-répertoires différents, et à l'aide de set_include_path() ou la définition d'un __autoload() fonction qui permet de sélectionner entre eux. Comme je l'ai dit, ce problème pourrait être résolu meilleure utilisation de l'héritage. Si vous avez un multi-héritage type de problème, si par exemple vous avez quatre sortes d'animaux de compagnie, avec cinq sortes de couleurs avec trois types de cheveux et vous avez besoin d'une combinaison de méthodes pour chacun des 60 classes différentes, c'est la bonne solution.

5.4 est pour l'instant que d'une version Release Candidate (comme de 2/24/2012) et même une fois libéré la plupart des hôtes de ne pas le soutenir pendant de nombreux mois la mienne a pris 18 mois après 5.3 a été libéré avant qu'ils ne s'y opposeraient pas. Jusqu'alors, vous devez écrire entièrement distincts et complets des fichiers de classe. Vous pouvez cependant le format de vos classes avec un éventuel changement de traits d'esprit.

Maintenant vous pouvez partiellement obtenir ce que vous voulez à l'aide de méthodes magiques et ont une mise à niveau facile à des traits lorsqu'ils sont disponibles.

Le Fichier De Code:

if ($pet === 'dog') include 'dog.php';
elseif ($pet === 'cat') include 'cat.php';
else die('Unknown pet');

class Pet {
  public function __call($name, array $arguments)
  {
    array_unshift($arguments, $this);
    return call_user_func_array("TraitFunc_$name", $arguments);
  }
}

$myPet = new Pet();
$myPet->speak();

Fichier cat.php

function TraitFunc_speak(Pet $that) { echo 'meow'; }

Fichier dog.php

function TraitFunc_speak(Pet $that) { echo 'woof'; }

Vous êtes cependant limité dans vos fonctions ne peuvent pas accès privé et protégé de la classe des propriétés et des méthodes, et vous ne pouvez pas utiliser cette méthode pour donner de la magie à des méthodes telles que l' __get(). Les Traits de résoudre ces deux limitations.

6voto

Thomas Smart Points 76

Que penser de l'utilisation des traits pour cela? Serait-ce une option acceptable? C'est quelque chose que je suis actuellement à l'essai avec et il semble fonctionner assez bien que.

Une version simplifiée de ce que je fais c'est un peu comme cela. J'ai une application avec partage de fichiers de base et de multiples projets. Au sein de ces projets, j'ai des modules. Je veux avoir les fonctions qui sont disponibles pour l'ensemble du projet à un niveau de base, mais seulement pour ce projet spécifique.

Mon contrôleur de projet

if(is_file(PROJECT_PATH.'/project_extensions.trait.php')){
  // additional functions for this specific project
  require_once(PROJECT_PATH.'/project_extensions.trait.php');
}else{
  // no additional functions
  trait Extensions{};
}


Class Project{
  USE Extensions;

  // default functions shared between all projects
  function shared_stuff(){

  }
}

Les Extensions de fichier

trait Extensions{
  // project-specific extensions
  function this_project_only(){
    echo 'Project Only';
  }
}

Le fichier du Module dans le projet

class MyModule extends Modules{ // modules extends projects in a different class not relevant here

  function do_something(){
    echo $this->project_only();
  }
}

1voto

Sev Points 6532

Puis-je simplement inclure ce fichier dans le corps de la classe?

Non.

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