是否有一个__get魔术方法等效于实例化类?

时间:2010-07-08 21:14:59

标签: php oop dynamic magic-methods

查看是否有任何方法可以实现__get()魔术方法的功能,但在尝试实例化新类时。

我的目标是

$foo = new Cat();

最终导致创建通用对象,即

new Mammal('Cat');

这样$foo将是类Mammal的一个实例,被调用的类名('Cat')作为参数传递给Mammal的构造函数。 / p>


注意: 对于熟悉Lithium或CakePHP的人来说,我想到的最终游戏是避免为每个不同的数据库表定义一大堆类。如果我这样做,大多数只是空的,基本的CRUD操作就是必要的。另外,所有这些包含和类定义都不能很好地用于开销。我的想法是使用单个“Model”类来处理大多数泛型函数,如果我需要针对特定​​数据库表的更多高级功能,我总是可以创建子类。

4 个答案:

答案 0 :(得分:2)

我不认为有任何直接的非hacky方式来实现你想要的类实例化机制。

我建议使用工厂:

$tableFactory->createTable('Cat');

然后可以找出幕后需要做的事情。这也有好处,如果您决定Cat需要自己的类,您可以简单地修改工厂,您可能不需要修改使用它的代码。

答案 1 :(得分:0)

嗯,这有点hacky,但你可以滥用class autoloader ...

所以,劫持加载程序以检查类“Cat”,如果它不存在,则将其评估为存在...

if (!$foundClass) {

    $code = 'Class '.$class.' extends Mammal { 
        public function __construct() { parent::__construct("'.$class.'");}
    }';
    eval($code);
}

我说它很hacky ......但是你总是可以列出你想要这样做的类... ...另外,它有一个好处,如果你想修改类,只需创建一个坚实的实例它

但话说回来,我个人会找到另一种解决方案。对我来说,new Cat()根本不可读。这是因为有两个原因,首先没有关于它是什么的背景线索,其次我找不到类Cat ...我会做的与Jani建议的类似:$table = DatabaseTable::getInstance('cat'); ...我发现那更具可读性(即使它是更多的字符)......

答案 2 :(得分:0)

我从Cake记住它的方式是你在控制器类之上定义模型,然后简单地使用$ this-> Modelname。这应该像实现一样简单:

public function __get($prop)
{
    if(in_array($prop, $this->uses)) {
        return new $prop;
    }
}

每次调用不存在的属性时,您的类将检查数组$ uses中是否存在属性名称,如果是,则假定$ prop为classname并将其设置为instaniates。您需要将实例存储在某个位置,以避免每次获取时重新实例化。

这比在整个地方写new Klass要简单一些,因为这使得很难与其他人交换Klass。然后你将它硬连接到控制器中。这是你想要避免的依赖。话虽如此,您可能需要查看Symfony Dependency Injection framework

答案 3 :(得分:0)

我知道这是一个古老的问题,但今天仍然适用于很多人。

我克服这个确切场景的方法是拥有一个基础建模器,它可以保存所有基本的表交互:

<?php
    class base {

        /**
         * @name        $table_values
         * @description This holds all data about the table including the field names and data for the record loaded.
         * @example     {
         *                  "primary_keys"  :   [],
         *                  "table_data"    :   {
         *                                          "name"  :   "value",
         *                                          "name"  :   "value"
         *                                      }
         *              }
         */
        private $table_values = array();

        /**
         * @name        __get
         * @param       $name   The name of the property to return.
         * @description The PHP magic getter.
         */
        public function __get($name) {
            $keys = array_keys($this->table_values['table_data']);
            if (in_array($name, $keys)) {
                return $this->table_values['table_data'][$name];
            }
        }

        /**
         * @name        __set
         * @param       $name   The name of the property to set.
         * @param       $value  The value to assign to the property.
         * @description The PHP magic setter.
         */
        public function __set($name, $value) {
            $this->table_values['table_data'][$name] = $value
        }

        /**
         * @name        table_name
         * @description Must override in child class. Should return the name of the table to use.
         */
        public function table_name() {}

        /**
         * @name        load
         * @param       $ids    int|array   Can be a single primary key or an assoc array of primary keys depending on the table with the keys for the array being the field names.
         * @description This method handles loading a single record from the table and storing it as a PHP object.
         */
        public function load($ids) {
            // Use the primary key(s) to find and load the record into $table_values from the database.
        }

        /**
         * @name        save
         * @description Saves the record in the database
        public function save() {
            // Use the primary key(s) to find and either insert or update the database table record.
        }
    }
?>

将基类用作:

<?php
    class person extends base {
        public function table_name() {
            return "person";
        }
    }

    class car extends base {
        public function table_name() {
            return "car";
        }
    }
?>

使用和自动加载器自动加载类并在表格不存在时处理:

<?php
    spl_autoload_register(function($class_name) {
        $filename = "/path/to/class/{$class_name}.php";
        if (class_exists($class_name)) {
            // Do nothing.
        } elesif (file_exists($filename)) {
            require_once($filename);
        } else {
            // Check if the class name exists in the database as a table.
            if ($database->table_exists($class_name)) {
                $class_def = "
class {$class_name} extends base {
    public function table_name() {
        return \"{$class_name}\";
    }
}";
                eval($class_def);
            }
        }
    });
?>

基类可以有更多功能。我还有一些函数可以覆盖孩子在加载和保存之前和之后做的事情,并检查具有相同数据的重复记录。