是否存在一个用于实例化类的__get魔术方法?
看看是否有任何方法来实现魔术方法的功能类型,但试图实例化一个新类时。是否存在一个用于实例化类的__get魔术方法?
我的目标是有
$foo = new Cat();
最终导致创建一个通用对象,即
new Mammal('Cat');
这样$foo
将是类Mammal
的一个实例,与被调用的类名称('Cat'
)作为参数传递给Mammal
的构造函数。
注: 游戏结束我心目中,对于熟悉锂或CakePHP的,是避免定义一大堆类为每个不同的数据库表。如果我这样做了,大部分都是空的,基本的CRUD操作就是必要的。此外,所有这些包括和类定义不能用于开销。我的想法是使用单个“Model”类来处理大多数泛型函数,如果我需要某个特定数据库表的更高级功能,我总是可以创建子类。
我不认为有什么简单的非hacky方式来实现你想要的类实例化机制。
我会建议使用工厂:
$tableFactory->createTable('Cat');
然后将计算出需要在幕后做什么。如果您决定Cat需要自己的类,这也有好处,您可以简单地修改工厂,并且您可能不需要修改正在使用它的代码。
嗯,这是一个有点哈克,但你可以滥用class autoloader ...
所以,劫持装载器检查类“猫”,如果不存在的话,那么它的eval到所有脑干...
if (!$foundClass) {
$code = 'Class '.$class.' extends Mammal {
public function __construct() { parent::__construct("'.$class.'");}
}';
eval($code);
}
我说,这是哈克......但你总是白名单,你想为......加上做到这一点的类,它具有的好处,如果你想修改类,只是创建一个公司的实例。
但是再次,我会亲自找到另一种解决方案。对我而言,new Cat()
根本不可读。这是因为两个原因,首先是没有上下文的线索,第二我找不到类Cat ...我会做什么类似于Jani建议的:$table = DatabaseTable::getInstance('cat');
...我发现更多的可读性(尽管它是更多的字符)...
我记得它从Cake的方式是,你在控制器类的顶部定义模型,然后简单地使用$ this-> Modelname。这应该是简单实施,因为:每次你调用一个不存在的属性
public function __get($prop)
{
if(in_array($prop, $this->uses)) {
return new $prop;
}
}
,如果属性名称在数组$用途,如果是存在于您的类会检查,假定$道具类名和立即它。您将希望将该实例存储在某处以避免每次获取时重新实例化。
这比在各处编写new Klass
更清洁一些,因为这使得很难将Klass换成别的东西。然后将其硬连线到控制器中。这是你想避免的依赖。有了这个说法,你可能想看看Symfony Dependency Injection framework。
我知道这是一个古老的问题,但对于很多人来说今天依然相关。
我克服这个确切情况的办法是有一个基础建模它包含所有基本表的互动:
<?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);
}
}
});
?>
基类可以有更多的功能。我还有一些函数可以在子节点覆盖,以便在加载和保存之前和之后执行操作,并且可以检查具有相同数据的重复记录。
这绝对有效,可能是我唯一的解决方案。我有点想能够写下“新猫()”;“为了可读性,但它不是必需的。这将是很好,虽然... – 2010-07-08 21:25:37
应该可能是静态 - 例如'TableFactory :: CREATETABLE( '猫');'。否则回答良好,工厂模式是在这里使用的。 – Pete 2010-07-08 23:10:37