110 votes

Obtenir le nom d'une classe enfant dans la classe parent (contexte statique)

Je construis une bibliothèque ORM dans un esprit de réutilisation et de simplicité; tout se passe bien sauf que je suis coincé par une stupide limitation d'héritage. Veuillez considérer 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 (bien que le comportement lui-même ait également un sens). Ma question est donc de savoir si vous connaissez un moyen d’obtenir, dans la classe parent, le nom de la classe enfant.

110voto

Owen Points 36009

en bref. ce n'est pas possible. en php4 vous pourriez mettre en œuvre une terrible hack (examiner l' debug_backtrace()), mais cette méthode ne fonctionne pas en PHP5. références:

edit: 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).

class Base {
    public static function whoAmI() {
        return get_called_class();
    }
}

class User extends Base {}

print Base::whoAmI(); // prints "Base"
print User::whoAmI(); // prints "User"

2voto

Tom Haigh Points 32314

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

BaseModel::get('User', 1);

au lieu 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:

class BaseModel {
    public static function get() {
        $args = func_get_args();
        $className = array_shift($args);

        //do stuff
        echo $className;
        print_r($args);
    }
}

class User extends BaseModel {
    public static function get() { 
        $params = func_get_args();
        array_unshift($params, __CLASS__);
        return call_user_func_array( array(get_parent_class(__CLASS__), 'get'), $params); 
    }
}


User::get(1);

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 cas

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