Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/286.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 获取父类中的子类的名称(静态上下文)_Php_Inheritance_Static Methods - Fatal编程技术网

Php 获取父类中的子类的名称(静态上下文)

Php 获取父类中的子类的名称(静态上下文),php,inheritance,static-methods,Php,Inheritance,Static Methods,我正在构建一个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

我正在构建一个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();

显然,这不是我所期望的行为(尽管实际的行为也有道理)。。所以我的问题是,你们是否知道在父类中获取子类名称的方法。

简而言之。这是不可能的。在php4中,您可以实现一个可怕的hack(检查
debug\u backtrace()
),但该方法在PHP5中不起作用。参考资料:

编辑:PHP5.3中后期静态绑定的一个示例(在注释中提到)。注意,它的当前实现()中存在潜在问题


看起来您可能正在尝试使用单例模式作为工厂模式。我建议您评估您的设计决策。如果单例确实合适,我还建议只使用不需要继承的静态方法


也许这实际上并没有回答这个问题,但是您可以添加一个参数来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);

如果您将User子类化,这可能会中断,但我想您可以用
'BaseModel'
替换
get\u parent\u class(\uu class\uu)
,在这种情况下

问题不是语言限制,而是您的设计。别介意你有课;静态方法掩盖了过程设计而非面向对象设计。您还以某种形式使用全局状态。(如何
从\u db\u获取\u row\u作为\u array()
知道在哪里找到数据库?)最后,单元测试看起来非常困难

试着用这些方法

$db = new DatabaseConnection('dsn to database...');
$userTable = new UserTable($db);
$user = $userTable->get(24);

如果您能够想出一种在静态上下文之外实现这一点的方法,就不需要等待PHP5.3。在php 5.2.9中,在父类的非静态方法中,可以执行以下操作:

get_class($this);
它将以字符串形式返回子类的名称

i、 e

这将输出:

Parent class: Parent
Child class: Child
string(3) "foo"
string(3) "bar"

好极了吧?

如果您不想使用get_called_class(),您可以使用其他后期静态绑定技巧(PHP5.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)

普雷斯顿的答案有两种变化:

(一)

(二)


注意:以u开头的属性名称是一种约定,基本上意味着“我知道我公开了这个名称,但它确实应该受到保护,但我无法做到这一点并实现我的目标”

我知道这个问题很老,但对于那些寻找比在每个包含类名的类中定义属性更实用的解决方案的人来说:

您可以使用
静态
关键字进行此操作。

如中所述

static
关键字可以在超类中使用,以访问从中调用方法的子类

示例:

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

我知道它的老帖子,但想分享我找到的解决方案

使用PHP7进行测试+ 使用函数
get\u class()


是的,我刚读到关于调试回溯()的内容。。一个可能的解决方案是使用PHP5.3中的后期静态绑定,但在我的例子中不可能。非常感谢。不,你不明白我想说什么,但那是因为我没有解释清楚:)。实际上,我只是想提供一个静态方法(在BaseModel中实现)来获取给定模型的实例(可能是用户、角色或其他)。我会更新问题……好的,更新。当然,BaseModel类有更多的方法,包括一些跟踪对象中更改的内容和只更新更改的内容等。。。不过还是要谢谢你:)。事实上,是的。这种PHP限制有很大的优势,迫使我重新审视我的设计。它看起来更像$connection->get('User',24);因为它允许同时进行多个连接,并且在语义上更为正确。但是你有一点:)。数组的移位似乎很慢,因为它必须更改数组的每个键。。。只需$args[0]即可;如果您使用的是抽象类,这是必须知道的应该是
$x=new Child()。就是这样!子类可能没有构造函数谢谢!正在努力使用ReflectionClass,但调用
static()
才是最好的选择!
<?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 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';
}
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);
    }
}
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
<?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"