質問

再利用とシンプルさを念頭に置いて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ではひどいハックを実装できます( debug_backtrace()を調べます)が、そのメソッドはPHP5では機能しません。参照:

編集:PHP 5.3の遅延静的バインディングの例(コメントで言及)。現在の実装には潜在的な問題があることに注意してください( 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"

他のヒント

静的コンテキストの外でこれを行う方法が考えられる場合、PHP 5.3を待つ必要はありません。 php 5.2.9では、親クラスの非静的メソッドで次のことができます。

get_class($this);

そして子クラスの名前を文字列として返します。

i.e。

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

甘いね?

この質問は本当に古いことを知っていますが、クラス名を含むすべてのクラスでプロパティを定義するよりも実用的な解決策を探している人には:

これには static キーワードを使用できます。

PHPドキュメントのこの寄稿者メモで説明されているとおり

  

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

以前の投稿を知っているが、見つけた解決策を共有したい。

PHP 7以降でテスト済み 関数 get_class() link <を使用します。 / p>

<?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()メソッドが必要になることです。これは大したIMOではありません。

<?php

class Base 
{
    public static function find($id)
    {
        $table = static::

get_called_class()を使用したくない場合は、遅延静的バインディング(PHP 5.3以降)の他のトリックを使用できます。ただし、この場合の欠点は、すべてのモデルにgetClass()メソッドが必要になることです。これは大したIMOではありません。

<*>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

get_called_class()を使用したくない場合は、遅延静的バインディング(PHP 5.3以降)の他のトリックを使用できます。ただし、この場合の欠点は、すべてのモデルにgetClass()メソッドが必要になることです。これは大したIMOではありません。

<*>table = 'users'; public static function getClass() { return __CLASS__; } } class Image extends Base { protected static

get_called_class()を使用したくない場合は、遅延静的バインディング(PHP 5.3以降)の他のトリックを使用できます。ただし、この場合の欠点は、すべてのモデルにgetClass()メソッドが必要になることです。これは大したIMOではありません。

<*>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);

Userをサブクラス化するとおそらく壊れるでしょうが、その場合は 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);

プレストンの答えの2つのバリエーション:

1)

class Base 
{
    public static function find($id)
    {
        $table = static::

プレストンの答えの2つのバリエーション:

1)

class Base 
{
    public static function _find($class, $id)
    {
        $table = static::

プレストンの答えの2つのバリエーション:

1)

class Base 
{
    public static function find($id)
    {
        $table = static::

プレストンの答えの2つのバリエーション:

1)

<*>

2)

<*>

注:_でプロパティ名を開始することは、基本的に&quot; iを公開したことを意味しますが、実際には保護する必要がありますが、それを実行できず、目標を達成できませんでしたを意味します。table; $class = static::

プレストンの答えの2つのバリエーション:

1)

<*>

2)

<*>

注:_でプロパティ名を開始することは、基本的に&quot; iを公開したことを意味しますが、実際には保護する必要がありますが、それを実行できず、目標を達成できませんでしたを意味します。class; $data = array('table' => $table, 'id' => $id); return new $class($data); } } class User extends Base { public static

プレストンの答えの2つのバリエーション:

1)

<*>

2)

<*>

注:_でプロパティ名を開始することは、基本的に&quot; iを公開したことを意味しますが、実際には保護する必要がありますが、それを実行できず、目標を達成できませんでしたを意味します。class = 'User'; }

2)

<*>

注:_でプロパティ名を開始することは、基本的に&quot; iを公開したことを意味しますが、実際には保護する必要がありますが、それを実行できず、目標を達成できませんでしたを意味します。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); } }

2)

<*>

注:_でプロパティ名を開始することは、基本的に&quot; iを公開したことを意味しますが、実際には保護する必要がありますが、それを実行できず、目標を達成できませんでしたを意味します。table; $class = static::

プレストンの答えの2つのバリエーション:

1)

<*>

2)

<*>

注:_でプロパティ名を開始することは、基本的に&quot; iを公開したことを意味しますが、実際には保護する必要がありますが、それを実行できず、目標を達成できませんでしたを意味します。class; $data = array('table' => $table, 'id' => $id); return new $class($data); } } class User extends Base { public static

プレストンの答えの2つのバリエーション:

1)

<*>

2)

<*>

注:_でプロパティ名を開始することは、基本的に&quot; iを公開したことを意味しますが、実際には保護する必要がありますが、それを実行できず、目標を達成できませんでしたを意味します。class = 'User'; }

2)

<*>

注:_でプロパティ名を開始することは、基本的に&quot; iを公開したことを意味しますが、実際には保護する必要がありますが、それを実行できず、目標を達成できませんでしたを意味します。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top