0

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

我的目标是拥有

$foo = new Cat();

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

new Mammal('Cat');

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


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

4

4 回答 4

2

我认为没有任何直接的非hacky方法可以通过类实例化机制来实现您想要的。

我建议使用工厂:

$tableFactory->createTable('Cat');

然后,这将弄清楚幕后需要做什么。如果你决定 Cat 需要它自己的类,这还有一个好处,你可以简单地修改工厂,你可能不需要修改使用它的代码。

于 2010-07-08T21:22:14.393 回答
0

好吧,这有点hacky,但你可以滥用类自动加载器......

因此,劫持加载程序以检查“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');......我发现更具可读性(即使它是更多的字符)...

于 2010-07-08T22:23:56.107 回答
0

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

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

每次调用不存在的属性时,您的类都会检查属性名称是否存在于数组 $uses 中,如果存在,则假定 $prop 是类名并将其实例化。您将希望将实例存储在某处,以避免每次获取它时都重新实例化。

这比到处写要干净一些new Klass,因为这使得很难将 Klass 换成其他东西。然后将其硬接线到控制器中。这是您要避免的依赖项。话虽如此,您可能想看看Symfony 依赖注入框架

于 2010-07-08T22:26:11.040 回答
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";
        }
    }
?>

等等

使用 和 autoloader 自动加载类并在表不存在类时进行处理:

<?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);
            }
        }
    });
?>

基类可以有更多的功能。我还有一些函数可以覆盖子项,以便在加载和保存之前和之后执行操作,例如检查具有相同数据的重复记录。

于 2016-10-11T10:38:43.567 回答