0

Possible Duplicate:
What is the best method for getting a database connection/object into a function in PHP?
Database and OOP Practices in PHP

I am trying to build an OOP shopping cart.

At present, it is half OOP, and half procedural... e.g.

function removeFromCart() { 
    require_once('/.../.../connectPDO.php');
    $db = connectPDO();

    $sql = 'DELETE FROM Quotes WHERE User = :user and ProductId = :pid';
    $stmt = $db->prepare($sql); 
    $stmt->execute(array(':user' => $user, ':pid' => $pid));
}

My problem is that if I wish to add to cart, then in my function addToCart, I will need to require the db connection again.

This seems like a complete waste, considering every function will need to contain the following:

    require_once('/.../.../connectPDO.php');
    $db = connectPDO();

I am aware that this is completely in-efficient, and was wondering if anybody could help me write a skeleton OOP cart class which uses the above connection to connect to the DB?

Does this go in the constructor??? Will this stay alive when a user navigates from one page to another at the front end?

I am new to OOP and am completely lost.

Many thanks in advance.

4

2 回答 2

4

类似以下内容应该可以帮助您入门:

$pdo = new PDO('your dsn');
$cartData = new CartData($pdo);
$cart = new Cart($cartData);

class CartData
{
    private $dbConnection;

    public function __construct(PDO $dbConnection)
    {
        $this->dbConnection = $dbConnection;
    }

    public function removeItem($userId, $productId) { 
        $sql = 'DELETE FROM Quotes WHERE User = :user and ProductId = :pid';

        $stmt = $this->dbConnection->prepare($sql);
        $stmt->execute(array(':user' => $userId, ':pid' => $productId));
    }
}

class Cart
{
    private $cartData;

    public function __construct(CartData $cartData)
    {
        $this->cartData = $cartData;
    }

    public function removeItem($userId, $productId) { 
        $this->cartData->removeItem($userId, $productId);
    }
}

请注意,我已经从实际Cart类中删除了数据库调用,因为这只会在某些时候使交换到另一个数据库引擎变得困难/不可能。或者您可能想引入一种完整的其他存储数据的方式(嗯,单元测试)。另请注意,我已经使用依赖注入来为类提供它们需要能够执行它们所负责的任何事情的对象。

我已经对要注入的类对象使用了类型提示,但是最好对接口进行类型提示,因为这样可以很容易地将类换成其他类。我强烈建议你使用接口(我上面写的只是一个例子来理解这个想法)。这也使得为您的代码创建单元测试变得非常容易。

于 2012-12-29T22:47:06.180 回答
1

在每个页面请求中,您都会建立一个新的数据库连接。您不能在请求之间共享连接。

有几种不同的设计模式(最佳实践)来处理这个问题。对于所有这些,您都需要一个 DB 抽象层(如 PDO、Doctrine DBAL 或其他东西)。

依赖注入(推荐)

处理这个问题最常用的设计模式是依赖注入:

class Foo
{
    /**
     * @var DatabaseAbstractionLayer
     */
    private $dbal;

    public function __construct(DatabaseAbstractionLayer $dbal)
    {
        $this->dbal = $dbal;
    }

    public function methodThatUsesTheDbal()
    {
        $this->dbal->query(...);
    }
}

$db = new DatabaseAbstractionLayer();
$foo = new Foo($db); // constructor injection

$bar = new Bar();
$bar->setDbal($db); // setter injection

$baz = new Baz();
$baz->dbal = $db; // property injection (almost never used)

您可以使用服务容器轻松处理此问题(以pimple为例):

$container = new Pimple();
$container['db'] = $container->share(function ($c) {
    return new DatabaseAbstractionLayer();
});
$container['foo'] = function ($c) {
    return new Foo($c['db']);
};

$foo = $container['foo']->methodThatUsesDbal();

辛格尔顿

class DatabaseAbstractionLayer
{
    private static $_instance;
    // ...

    private function __construct()
    {
        // ...
    }

    // ...

    public static function getInstance()
    {
        if (null === self::$_instance) {
            self::$_instance = new static();
        }

        return self::$_instance;
    }
}

class Foo
{
    public function methodThatUsesDbal()
    {
        $db = DatabaseAbstractionLayer::getInstance();
        // ...
    }
}

注册处

Registery::set('db', new DatabaseAbstractionLayer());

class Foo
{
    public function methodThatUsesRegistery()
    {
        Registery::get('db');
        // ...
    }
}
于 2012-12-29T22:47:30.920 回答