Estoy construyendo una biblioteca ORM con la reutilización y la simplicidad en mente; todo va bien, excepto que me quedé atrapado por una estúpida limitación de herencia. Tenga en cuenta el siguiente código:
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();
Obviamente, este no es el comportamiento que esperaba (aunque el comportamiento real también tiene sentido). Así que mi pregunta es si conocen un medio para obtener, en la clase principal, el nombre de la clase secundaria.
fuente
debug_backtrace()
... Una posible solución sería utilizar un enlace estático tardío de PHP 5.3, pero esa no es una posibilidad en mi caso. Gracias.No necesita esperar PHP 5.3 si puede concebir una forma de hacerlo fuera de un contexto estático. En php 5.2.9, en un método no estático de la clase principal, puede hacer:
y devolverá el nombre de la clase secundaria como una cadena.
es decir
esto dará como resultado:
dulce eh?
fuente
$x = new Parent();
debería serlo$x = new Child();
.Sé que esta pregunta es realmente antigua, pero para aquellos que buscan una solución más práctica que definir una propiedad en cada clase que contiene el nombre de la clase:
Puede utilizar la
static
palabra clave para esto.Como se explica en esta nota de colaborador en la documentación de php
Ejemplo:
fuente
static()
es el camino a seguir!Sé que es una publicación anterior, pero quiero compartir la solución que encontré.
Probado con PHP 7+ Use el enlace de función
get_class()
El ejemplo anterior dará como resultado:
fuente
En caso de que no desee utilizar get_called_class (), puede utilizar otros trucos de enlace estático tardío (PHP 5.3+). Pero la desventaja en este caso es que debe tener el método getClass () en cada modelo. Lo cual no es gran cosa en mi opinión.
fuente
Parece que está intentando utilizar un patrón singleton como patrón de fábrica. Recomendaría evaluar sus decisiones de diseño. Si un singleton realmente es apropiado, también recomendaría usar solo métodos estáticos donde no se desee la herencia .
fuente
Tal vez esto en realidad no esté respondiendo a la pregunta, pero podría agregar un parámetro para get () especificando el tipo. entonces puedes llamar
en lugar de llamar a User :: get (). Puede agregar lógica en BaseModel :: get () para verificar si existe un método get en la subclase y luego llamarlo si desea permitir que la subclase lo anule.
De lo contrario, la única forma en que puedo pensar, obviamente, es agregando cosas a cada subclase, lo cual es estúpido:
Esto probablemente se rompería si luego subclasificara Usuario, pero supongo que podría reemplazarlo
get_parent_class(__CLASS__)
con'BaseModel'
en ese casofuente
El problema no es una limitación de idioma, es tu diseño. No importa que tengas clases; los métodos estáticos desmienten un diseño procedimental más que orientado a objetos. También estás usando el estado global de alguna forma. (¿Cómo
get_row_from_db_as_array()
sabe dónde encontrar la base de datos?) Y finalmente parece muy difícil realizar pruebas unitarias.Intente algo en este sentido.
fuente
Dos variaciones de la respuesta de Preston:
1)
2)
Nota: comenzar el nombre de una propiedad con _ es una convención que básicamente significa "sé que hice esto público, pero realmente debería haber estado protegido, pero no pude hacer eso y lograr mi objetivo".
fuente