查看是否有任何方法可以实现__get()
魔术方法的功能,但在尝试实例化新类时。
我的目标是
$foo = new Cat();
最终导致创建通用对象,即
new Mammal('Cat');
这样$foo
将是类Mammal
的一个实例,被调用的类名('Cat'
)作为参数传递给Mammal
的构造函数。 / p>
注意: 对于熟悉Lithium或CakePHP的人来说,我想到的最终游戏是避免为每个不同的数据库表定义一大堆类。如果我这样做,大多数只是空的,基本的CRUD操作就是必要的。另外,所有这些包含和类定义都不能很好地用于开销。我的想法是使用单个“Model”类来处理大多数泛型函数,如果我需要针对特定数据库表的更多高级功能,我总是可以创建子类。
答案 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);
}
}
});
?>
基类可以有更多功能。我还有一些函数可以覆盖孩子在加载和保存之前和之后做的事情,并检查具有相同数据的重复记录。