我正在为PHP中的Web项目创建一个小框架,所以我不必为每个新网站反复做基础工作。我的目标不是创建第二个CakePHP或Codeigniter,而且我也不打算用任何可用的框架构建我的网站,因为我更喜欢使用我自己创建的东西。
在核心结构,请求处理等部分的设计和编码方面,我没有遇到任何问题,但我已经陷入了为模块设计数据库接口的困境。
我已经考虑过使用MVC模式,但发现对于我这个相当小的项目来说这会有点过分。
所以我面临的确切问题是我的框架模块(viewCustomers
可能是一个模块,例如)应该如何与数据库进行交互。
将SQL直接混合到PHP代码中(仍然)是个好主意吗? (将是“老路”:mysql_query( 'SELECT firstname, lastname(.....)
)?
我如何抽象如下的查询?
SELECT firstname, lastname FROM customers WHERE id=X
MySQL“helper”函数会像
一样 $this->db->customers->getBy( 'id', $x );
是个好主意吗?
我不太确定,因为在处理更复杂的查询时,它们往往变得毫无用处,例如上面几乎无关紧要的查询。
MVC的“模型”模式是解决这个问题的唯一真实选择吗?
您目前使用什么来解决上述问题?
答案 0 :(得分:6)
我相信您只想从您的模块访问您的数据库。我会避免直接从代码中使用mysql_query。相反,使用抽象的数据库访问的简单模型将是简单和直接的。
例如,您可以使用以下代码创建类似models / Customers.php的文件:
<?php
class Customers {
public function getById($id) {
$sql = "SELECT first_name, last_name FROM customers WHERE id='$id'";
$res = $DB::getRow($sql);
return ($res);
}
}
我假设某种DB帮助程序已经实例化并可用作$ DB。 Here是一个使用PDO的简单版本。
现在,您应该在模块中包含它并使用以下方式:
<?php
include_once "models/Customers.php";
$customers = new Customers();
$theCustomer = $customers->getById(intval($_REQUEST['cust_id']));
echo "Hello " . $theCustomer['first_name']
干杯。
答案 1 :(得分:5)
您是否考虑过http://www.doctrine-project.org/或其他php orm框架(想到zend_db)?
答案 2 :(得分:3)
如果您需要速度,请使用原始查询(但您应该将PDO与prepared queries一起使用)。
如果你想要更多的OOP,你可以 - 如你所知 - 用帮助器设计它。
有一次,我设计了类似的东西,它有以下概念:
代码看起来像这样:
$select = new Select('field1', 'field2', );
$result = $select->from('myTable')
->addFilter(SQLFilter::RangeFilter, 'field2')
->match(array(1, 3, 5))
->unmatch(array(15, 34))
->fetchAll();
这是一个如何构建它的简单示例。
您可以更进一步实现表关系的自动处理,字段类型检查(使用表上的内省),表和字段别名支持等。
这似乎是一项漫长而艰苦的工作,但实际上,制作所有这些功能(≈1个月)不会花费你那么多时间。
答案 3 :(得分:2)
三个提示:
CALL NEWS_LIST(?, ?)
答案 4 :(得分:1)
原始SQL仍然是我的赢家,我喜欢控制我发送到服务器的内容(对于索引使用,复杂的JOIN子句等情况),所以我通常远离辅助函数。
您应该使用已经提供了大量功能的PDO,如果这还不够,您可以扩展它(可能使用您自己的功能,例如在实际查询数据库之前检查Memcached / APC上的命中)。您还可以扩展该类以实现您自己的SQL函数,如:
function getUser($user_id) {
return $this->query("SELECT * FROM users WHERE id = " . (int) $user_id);
}
当然,从模型中你仍然可以发送:
$this->db->query("SELECT * FROM users WHERE id = " . (int) $user_id);
得到相同的结果。这些函数应仅仅作为一种捷径,扩展类不应该包含在框架中,因为它将取决于站点。
MVC模式很适合这一点,因为您只能将数据库用作驱动程序,然后您的模型可以将数据转换为您需要的数据。创建一个简单的MVC结构并不难,它会在以后为您带来好处。
答案 5 :(得分:1)
你听起来像我。您是否在http://github.com/Xeoncross/micromvc中看到了http://github.com/Xeoncross/database和一个文件ORM?挖掘我的代码,我想你会找到你想要的东西。
解决方案是使用某些查询的完整原始功能 - 同时仍然允许ORM和查询构建器(如codeigniter的AR)用于其他事情。
两者都很好。
答案 6 :(得分:1)
不是我知道确定的答案(我认为它也不存在),但我想我可以分享我在这里的内容。我使用自己的db'框架',轻量级(当前约1000行)并且易于使用。我的主要目标是简化sql的使用,而不是从程序员(我:)中“隐藏”它。一些例子:
// row() is 'query' + 'fetch' in one
$user = $db->row("select * from users where id=25");
// the same, injection safe
$user = $db->row("select * from users where id=?", $_GET['id']);
// ? placeholders are smart
$someUsers = $db->rows("select * from users where id IN(?)", array(1, 2, 10));
// ...and even smarter
$data = array('name' => 'Joe', 'age' => 50);
$id = 222;
$db->exec("update users set ?a where id=?", $data, $id);
// 'advanced' fetch functions
$topNames = $db->vlist("select name from users order by name limit 10");
$arrayOfIds = $db->nlist("select id from users where age > 90");
// table() returns a Table Gateway
$db->table('users')->delete('where id=?', 25);
// yes, this is safe
$db->table('users')->insert($_POST);
// find() returns a Row Gateway object
$db->table('users')
->find('where name=?', 'Joe')
->set('status', 'confirmed')
->save();
答案 7 :(得分:0)
理解这一点:数据库交互是一个已解决的问题。
所以,除非你真的想要这样做a)体验或b)因为你是强迫症并想知道你将要使用的代码的每个字符,那么我会选择现有的解决方案。
还有很多:PEAR :: MDB2,Zend :: Db,Creole,Doctrine,Propel,仅举几例。
答案 8 :(得分:0)
我刚刚离开了“辅助函数”路径,而且让我感到困惑的一件事就是我继续在一个文件中添加函数,这个文件随着相同或相似或不存在的函数而增长和增长。我认为行数是600,这对于我认为的单个文件来说是很多的。这并没有让我想到这个想法,但我会更有条理地进行下一次艰苦跋涉。我可能会根据db操作将db函数拆分为多个文件(select,insert etc ...)。
所以我的建议是尝试“辅助功能”并尽可能有条理。
另外,我第一次使用PDO并非常喜欢它。它不像mysql()函数那样低技术,也不像我们可以提到的那样膨胀技术,但不会。我将再次使用PDO。
答案 9 :(得分:0)
关于这个话题似乎有很多不同的意见,因为我还没有找到一个真正令人满意的答案而且赏金已经快结束了,我只会写一些我在最后几天出现的内容。试错:
我正在使用单例MySQL类来处理连接和非常基本的查询以及可能发生的错误。
像/users/show/1
这样的单页(使用mod_rewrite)不使用原始SQL,而是使用某种类似于以下示例的轻量级ORM:
$user = $this->db
->users
->getBy( 'id', $id );
$this->db
是具有__get( $tableName )
方法的Database Abstraction类的实例。访问未定义的users
属性然后触发它。其余的解释了自己;查询由传递给getBy( )
的参数组成(SQL转义也由它处理),其结果作为数组返回。
我还没有完成整个想法,但是向数据库添加新用户可能如下所示:
$user = $this->db
->users
->new;
$user->id = 2;
$user->name = 'Joe';
$user->save( );
正如我所说,这个概念并没有真正完成,并且可能存在(巨大的)缺陷。但我认为编写,比普通的MySQL更安全,更容易维护。 整个“事物”的其他一些优点是它很小,因此相当快,也很简单。
我知道这不能与已经存在的极其强大的ORM和框架竞争,但我仍然是出于上述一条评论中提到的某些原因而创建它。
答案 10 :(得分:-4)
如果您计划制作数据库类,可能会考虑将其设为单例,允许您在不声明/创建数据库的情况下使用它,因为...
global $db;
$db = new db;
$db->query ('... sql ...');
当你可以做时,有点多余
db::query ('... sql ...');
我有一组SQL函数,我几乎定期使用这些函数来减少曾经多行转义的SQL到单个调用,例如:
get_element ($table, $element, $value, $column='id');
get_row ($table, $value, $column='id');
因此,如果您只想从id为4的表'customers'获取名称,那么:
$name = db::get_element ('customers', 'name', 4);
还有一些函数query_element和query_row,你只需要传递一个SQL字符串,它就会返回一个元素/行。
与插入/更新功能一起,例如
$array = array (
'name' => 'bob jones',
'age' => 28
);
$insert_id = db::insert_array ('customers', $array);
$customer_details = db::get_row ('customers', $insert_id);
$customer_details['age'] = 30;
db:update_array ('customers, $customer_details);
将创建一个新行,将详细信息拉回来,更新年龄,然后将其重新写入数据库。
基于每个表创建自定义SQL访问模块通常是我一直发现的错误 - 最好只使用合理的函数来查询数据库。
如果你必须使用复杂连接的任何东西,那么总是最好为它创建函数getCustomerInfo(),但是如果你只是想要一个通用的表值查找,那么制作大量的自定义方法只会增加出错的几率其中一个。再加上转义数据非常重要 - 如果您可以尽可能多地使用非sql并通过一些核心功能将其汇集起来,那么您可以确保所有内容都能够相当容易地进行转义。
如果您想查看我的自定义数据库类,请告诉我。