Я создаю библиотеку ORM с учетом повторного использования и простоты; все идет нормально, за исключением того, что я застрял из-за дурацкого ограничения наследования. Обратите внимание на приведенный ниже код:
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();
Очевидно, это не то поведение, которого я ожидал (хотя фактическое поведение также имеет смысл). Итак, мой вопрос, знаете ли вы, ребята, способ получить в родительском классе имя дочернего класса.
php
inheritance
static-methods
Saalaa
источник
источник
debug_backtrace()
... Возможным решением было бы использование позднего статического связывания из PHP 5.3, но в моем случае это невозможно. Спасибо.Вам не нужно ждать выхода PHP 5.3, если вы можете придумать способ сделать это вне статического контекста. В php 5.2.9 в нестатическом методе родительского класса вы можете:
get_class($this);
и он вернет имя дочернего класса в виде строки.
т.е.
class Parent() { function __construct() { echo 'Parent class: ' . get_class() . "\n" . 'Child class: ' . get_class($this); } } class Child() { function __construct() { parent::construct(); } } $x = new Child();
это выведет:
Parent class: Parent Child class: Child
милая да?
источник
$x = new Parent();
должно быть$x = new Child();
.Я знаю, что этот вопрос действительно старый, но для тех, кто ищет более практичное решение, чем определение свойства в каждом классе, содержащем имя класса:
Вы можете использовать
static
для этого ключевое слово.Как объясняется в этом примечании для участника в документации php
Пример:
class Base { public static function init() // Initializes a new instance of the static class { return new static(); } public static function getClass() // Get static class { return static::class; } public function getStaticClass() // Non-static function to get static class { return static::class; } } class Child extends Base { } $child = Child::init(); // Initializes a new instance of the Child class // Output: var_dump($child); // object(Child)#1 (0) {} echo $child->getStaticClass(); // Child echo Child::getClass(); // Child
источник
static()
- это путь!Я знаю его старую публикацию, но хочу поделиться найденным решением.
Протестировано с PHP 7+ Используйте ссылку на функцию
get_class()
<?php abstract class bar { public function __construct() { var_dump(get_class($this)); var_dump(get_class()); } } class foo extends bar { } new foo; ?>
Приведенный выше пример выведет:
string(3) "foo" string(3) "bar"
источник
Если вы не хотите использовать get_called_class (), вы можете использовать другие приемы позднего статического связывания (PHP 5.3+). Но обратная сторона: в этом случае вам нужно иметь метод getClass () в каждой модели. ИМО, это не имеет большого значения.
<?php class Base { public static function find($id) { $table = static::$_table; $class = static::getClass(); // $data = find_row_data_somehow($table, $id); $data = array('table' => $table, 'id' => $id); return new $class($data); } public function __construct($data) { echo get_class($this) . ': ' . print_r($data, true) . PHP_EOL; } } class User extends Base { protected static $_table = 'users'; public static function getClass() { return __CLASS__; } } class Image extends Base { protected static $_table = 'images'; public static function getClass() { return __CLASS__; } } $user = User::find(1); // User: Array ([table] => users [id] => 1) $image = Image::find(5); // Image: Array ([table] => images [id] => 5)
источник
Похоже, вы, возможно, пытаетесь использовать одноэлементный шаблон в качестве заводского. Я бы рекомендовал оценить ваши дизайнерские решения. Если одноэлементно действительно подходит, я также рекомендовал бы только с помощью статических метод , где наследование не желательные.
class BaseModel { public function get () { echo get_class($this); } public static function instance () { static $Instance; if ($Instance === null) { $Instance = new self; } return $Instance; } } class User extends BaseModel { public static function instance () { static $Instance; if ($Instance === null) { $Instance = new self; } return $Instance; } } class SpecialUser extends User { public static function instance () { static $Instance; if ($Instance === null) { $Instance = new self; } return $Instance; } } BaseModel::instance()->get(); // value: BaseModel User::instance()->get(); // value: User SpecialUser::instance()->get(); // value: SpecialUser
источник
Возможно, это на самом деле не отвечает на вопрос, но вы могли бы добавить параметр для get (), определяющий тип. тогда ты можешь позвонить
BaseModel::get('User', 1);
вместо вызова User :: get (). Вы можете добавить логику в BaseModel :: get (), чтобы проверить, существует ли метод get в подклассе, а затем вызвать его, если вы хотите разрешить подклассу переопределить его.
В противном случае единственный способ, о котором я могу думать, очевидно, - это добавлять что-то в каждый подкласс, что глупо:
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);
Это, вероятно , сломаться , если вы тогда подклассы пользователя, но я полагаю , вы могли бы заменить
get_parent_class(__CLASS__)
с'BaseModel'
в том случае ,источник
Проблема не в языковом ограничении, а в вашем дизайне. Неважно, что у вас есть классы; статические методы противоречат процедурному, а не объектно-ориентированному дизайну. Вы также в какой-то форме используете глобальное состояние. (Как
get_row_from_db_as_array()
узнать, где найти базу данных?) И, наконец, модульное тестирование выглядит очень сложным.Попробуйте что-нибудь в этом роде.
$db = new DatabaseConnection('dsn to database...'); $userTable = new UserTable($db); $user = $userTable->get(24);
источник
Два варианта ответа Престона:
1)
class Base { public static function find($id) { $table = static::$_table; $class = static::$_class; $data = array('table' => $table, 'id' => $id); return new $class($data); } } class User extends Base { public static $_class = 'User'; }
2)
class Base { public static function _find($class, $id) { $table = static::$_table; $data = array('table' => $table, 'id' => $id); return new $class($data); } } class User extends Base { public static function find($id) { return self::_find(get_class($this), $id); } }
Примечание: начало имени свойства с _ - это соглашение, которое в основном означает: «Я знаю, что сделал это общедоступным, но оно действительно должно было быть защищено, но я не смог этого сделать и достичь своей цели»
источник