Obtenir le nom d'un enfant de la classe dans la classe parent (contexte statique)
Je suis en train de construire un ORM bibliothèque de la réutilisation et de la simplicité à l'esprit, tout va bien sauf que je me suis coincé par un stupide héritage limitation. Veuillez examiner le code ci-dessous:
class BaseModel {
/*
* Return an instance of a Model from the database.
*/
static public function get (/* varargs */) {
//1. Notice we want an instance of User
$class = get_class(parent); //value: bool(false)
$class = get_class(self); //value: bool(false)
$class = get_class(); //value: string(9) "BaseModel"
$class = __CLASS__; //value: string(9) "BaseModel"
//2. Query the database with id
$row = get_row_from_db_as_array(func_get_args());
//3. Return the filled instance
$obj = new $class();
$obj->data = $row;
return $obj;
}
}
class User extends BaseModel {
protected $table = 'users';
protected $fields = array('id', 'name');
protected $primary_keys = array('id');
}
class Section extends BaseModel {
//[...]
}
$my_user = User::get(3);
$my_user->name = 'Jean';
$other_user = User::get(24);
$other_user->name = 'Paul';
$my_user->save();
$other_user->save();
$my_section = Section::get('apropos');
$my_section->delete();
Évidemment, ce n'est pas le comportement que j'attendais (même si le comportement est également logique).. Donc ma question est de savoir si les gars, vous connaissez un moyen de se le procurer, dans la classe parent, le nom de la classe enfant.
Vous devez vous connecter pour publier un commentaire.
en bref. ce n'est pas possible. en php4 vous pourriez mettre en œuvre une terrible hack (examiner la
debug_backtrace()
), mais cette méthode ne fonctionne pas en PHP5. références:Trente mille quatre cent vingt trois
Trente sept mille six cent quatre vingt quatre
Trente quatre mille quatre cent vingt et un
modifier: un exemple de late static binding en PHP 5.3 (mentionné dans les commentaires). remarque: il existe des problèmes potentiels dans la mise en œuvre (src).
debug_backtrace()
.. Une solution possible serait d'utiliser late static binding à partir de PHP 5.3 mais ce n'est pas une possibilité dans mon cas. Je vous remercie.Vous n'avez pas besoin d'attendre pour PHP 5.3 si vous êtes en mesure de concevoir une façon de le faire en dehors d'un contexte statique. En php 5.2.9, dans une non-méthode statique de la classe parent, vous pouvez faire:
et il sera de retour le nom de l'enfant de la classe comme une chaîne de caractères.
c'est à dire
ce sera de sortie:
doux hein?
$x = new Parent();
devrait être$x = new Child();
.Je sais que cette question est vraiment vieux, mais pour ceux qui recherchent une solution plus pratique que de définir une propriété dans chaque classe contenant le nom de la classe:
Vous pouvez utiliser le
static
mot-clé pour cette.Comme expliqué dans ce contributeur note dans la documentation de php
Exemple:
static()
est le chemin à parcourir!Je sais que son ancien poste, mais souhaitez partager la solution que j'ai trouvé.
Testé avec PHP 7+
Utiliser la fonction
get_class()
lienL'exemple ci-dessus va afficher:
Dans le cas où vous ne souhaitez pas utiliser get_called_class (), vous pouvez utiliser d'autres astuces de late static binding (PHP 5.3+). Mais l'inconvénient dans ce cas, vous avez besoin de la méthode getClass() dans chaque modèle. Ce qui n'est pas une grosse affaire de l'OMI.
Il semble que vous essayez peut-être d'utiliser un pattern singleton comme un modèle de fabrique. Je recommande l'évaluation de vos décisions de conception. Si un singleton est vraiment approprié, je voudrais également recommander uniquement à l'aide de méthodes statiques où l'héritage est pas désiré.
Peut-être que ce n'est pas réellement répondre à la question, mais vous pouvez ajouter un paramètre get() en spécifiant le type. ensuite, vous pouvez appeler
à la place de l'Utilisateur appelant::get(). Vous pouvez ajouter la logique dans BaseModel::get() pour vérifier si une méthode existe dans la sous-classe, et ensuite appeler que si vous voulez permettre à la sous-classe pour le remplacer.
Sinon la seule façon que je peux penser à est de toute évidence en ajoutant des trucs à chaque sous-classe, ce qui est stupide:
Ce serait probablement se briser si vous puis de sous-classé Utilisateur, mais je suppose que vous pourriez remplacer
get_parent_class(__CLASS__)
avec'BaseModel'
dans ce casLe problème n'est pas une restriction de langue, il est de votre conception. Jamais l'esprit que vous avez les classes; les méthodes statiques à l'encontre de la procédure plutôt que de la conception orientée objet. Vous êtes également à l'aide de l'état global dans une certaine forme. (Comment ne
get_row_from_db_as_array()
savoir où trouver la base de données?) Et enfin, il semble très difficile de test de l'unité.Essayer quelque chose le long de ces lignes.
Deux variations sur Preston réponse:
1)
2)
Remarque: à partir d'un nom de propriété avec _ est une convention qui signifie "je sais que j'ai fait ce public, mais il ne devrait vraiment avoir été protégé, mais je ne pouvais pas le faire et à atteindre mon objectif"