我正在尝试在我构建的轻型框架中改进我用于数据库事务的方法。
这是我编写的一个类(其中connect.php
加载数据库凭据; PHP PDO的包装器,存储在$db
;以及Base.php
):
<?php
require_once('connect.php');
class Advertiser extends Base
{
public static function getByID($id)
{
global $db;
$sql = "SELECT * FROM advertiser WHERE advertiserid=?";
$values = array($id);
$res = $db->qwv($sql, $values);
return Advertiser::wrap($res);
}
public static function add($name)
{
$adv = new Advertiser(null, $name);
$res = $adv->save();
return $res;
}
public static function wrap($advs)
{
$advList = array();
foreach( $advs as $adv )
{
array_push($advList, new Advertiser($adv['advertiserid'], $adv['name']));
}
return Advertiser::sendback($advList);
}
private $advertiserid;
private $name;
public function __construct($advertiserid, $name)
{
$this->advertiserid = $advertiserid;
$this->name = $name;
}
public function __get($var)
{
return $this->$var;
}
public function save()
{
global $db;
if( !isset($this->advertiserid) )
{
$sql = "INSERT INTO advertisers (name) VALUES(?)";
$values = array($this->name);
$db->qwv($sql, $values);
if( $db->stat() )
{
$this->advertiserid = $db->last();
return $this;
}
else
{
return false;
}
}
else
{
$sql = "UPDATE advertisers SET name=? WHERE advertiserid=?";
$values = array ($this->name, $this->advertiserid);
$db->qwv($sql, $values);
return $db->stat();
}
}
}
?>
正如您所看到的,它具有相当标准的CRUD功能(编辑:好的,所以在此实现中只有CRU)。有时,我会通过添加更多函数来扩展这样的类,这就是这些类的用途。例如,我可能会将以下函数添加到此类中(假设我向数据库添加了一个列isBanned
):
public static function getBanned()
{
global $db;
$sql = "SELECT * FROM advertiser WHERE isBanned=1";
$res = $db->q($sql);
return Advertiser::wrap($res);
}
如何创建一个catchall类,它还会在存在且必要时加载自定义模型类?
例如,如果我编写以下代码:
$model = new Catchall();
$banned = $model->Advertiser::getByID(4);
我希望我的catchall类可以修改它的查询,以便对表/列的所有引用都是我选择的名称(在这种情况下为Advertiser
),但是小写。
另外,如果我想创建一个像我上面写的那样的自定义函数,我希望我的catchall类能够确定一个文件存在于其路径中(当然是先前定义的),其名称是我的指定(在这种情况下为Advertisers.php
)并加载它。
Advertisers.php
将extends Catchall
并且仅包含我的自定义函数。
通过这种方式,我可以拥有一个适用于所有CRUD函数的Catchall类,并且可以根据需要轻松扩展任意类。
答案 0 :(得分:3)
一般资料:我会查看Doctrine2有关如何在PHP中创建ORM的示例。他们使用标记语言中的映射来表示:此表包含此类型的这些列。此外,虽然不是在PHP中,Django ORM非常易于使用和理解,并且通过该教程大约20分钟左右,这将真正让您看到一些简洁的可能性。 (它对我有用)
快速搜索“php active record lightweight”返回了几个有趣的例子,可能会让你走上正确的道路。
PHP创意:我会调查php,__ GET和__SET中的魔术getter和setter,它可以让你在对象上设置值,而不必为每个字段设置一个getter / setter表。您可以创建一个__SET,以确保set字段是该表中的字段,并在下次保存该对象时将其添加到“要更新的字段”列表中。但是,从长远来看,这不是一个好主意,因为它很快失控,而且很脆弱。
建议:最后,我在一家使用看起来几乎完全相同的系统的公司工作,我可以毫不含糊地说,你不想尝试扩展这个长期。像这样的系统(活动记录模式)可以预先节省大量的时间,不必编写查询和事物,但如果您想要开始单元测试业务逻辑,可能会花费很多时间。 对象类。
例如,不可能模拟/依赖注入静态GetById方法(它基本上是一个全局方法),因此每次在代码中调用时,代码将转到真实数据库并返回一个真实对象。这样的编码并不需要太多,以使系统几乎不可能测试,咆哮并紧密耦合到数据库。
虽然它们的执行速度可能比上面的代码慢一些,但如果您计划在相当长的时间内使用它,请尝试查看ORM工具。
编辑这称为活动记录。
答案 1 :(得分:1)
您尝试做的事情有几种不同的设计模式。查看Data Mapper和Active Record。
答案 2 :(得分:0)
使用PHP的“魔术方法”__get
,当您通过以下方式访问它时,可以生成此功能:
$model = new Catchall();
$banned = $model->Advertiser->getByID(4);
...它将a)检查是否已定义类Advertiser
,b)检查名为Advertiser.php
的文件并包含它,或c)返回一个新的实例泛类。
您在::
示例中使用的语法假定返回的类是静态的。我没有编写这个代码来解决这个问题,但这样做应该是微不足道的。
请参阅文档:http://www.php.net/manual/en/language.oop5.overloading.php#language.oop5.overloading.methods
快速而肮脏的例子:
public function __get($name) {
$instance = false;
// see if there is already a class with the requested name
if (class_exists($name)) {
$instance = new $name();
}
// check to see if there is an object def for the requested object
if ($instance === false && file_exists(PATH_TO_OBJECTS.$name.'.php')) {
require_once(PATH_TO_OBJECTS.$name.'.php');
$instance = new $name();
}
// if instace is still not found, load up a generic
if ($instance === false)
$instance = new Catchall($name);
return $instance;
}