在PHP中,我有两个类:数据库和项目。
数据库包含连接属性和方法。例如,数据库::查询可用于传递查询字符串等。
项目是一个通用项目标识符。它是通过向它传递itemID来构建的,然后用于查询数据库中的其余项目信息。
在这种情况下,如果Item对象需要数据库访问,那么创建Item对象的最佳做法是什么?使用以下语法创建每一个是否正常:
$item = new Item(12345, $db);
或者,创建Database对象并将其用于应用程序中创建的每个Item,这样调用就可以变成:
$item = new Item(12345);
第二个似乎干净多了(可以扩展,这样类似类型的对象就不需要$db插件了),但我正在寻找那些比我更有经验的人的建议!谢谢
我建议大多数经验丰富的开发人员倾向于依赖注入方法,如您的第一个示例所示。
为什么?
这在很大程度上是因为这允许您将依赖项注入的类与依赖项的实现解耦。
因此,考虑这个依赖注入示例:
Class some_class {
protected $db;
__construct($db) {
if($db instanceof some_db_class === false) {
throw new Exception('Improper parameter passed.');
}
$this->db = $db;
}
}
在这里,您可以传递任何类型的对象,只要它是some_db_class
的实例,它就可以是该对象的子类,实现该类使用的相同方法。只要实现了方法,这对这个类来说就无关紧要了(当然,除了检查其实例类型之外,您还可以检查传递的对象是否实现了特定的接口)。
这意味着,例如,您可以传递一个mock DB对象进行测试或类似的操作。只要方法实现了,类就不在乎。
现在考虑singleton方法(或类似的DB与类的实例化):
Class some_class {
protected $db;
__construct() {
$this->db = some_db_class::get_instance();
}
}
在这里,您已经将您的类紧密耦合到一个特定的数据库类。如果你想用一个mock DB实现来测试这个类,那么你需要修改这个类,这会变得非常痛苦
我甚至不会讨论使用global
,因为这只是一种糟糕的做法,根本不应该考虑。
我建议使用Singleton模式进行数据库连接。这实际上是最好的做法。因为你真的不需要实例的数据库连接。
class Database_Instance
{
private static $database;
public static function getDatabaseObject() {
if (!self::$db) {
self::$db = new PDO( );
}
return self::$db;
}
}
function callWhatSoEver()
{
$connection = Database_Instance::getDatabaseObject();
}
有关singleton模式的更多信息,请参阅:http://en.wikipedia.org/wiki/Singleton_pattern
通常,数据库连接对象是全局的,或者可以全局访问。这适用于绝大多数应用程序。
我做了这样的事情(为了示例的目的而简化):
$db = connect_to_db();
function GetDB()
{
global $db;
return $db
}
//inside the item object
function Load( $id)
{
$db = GetDB();
$db->query(..);
}
当然,在某些情况下,这不是最佳路线。和往常一样,它取决于应用程序的特定需求。