【问题标题】:Assistance with OOP, PDO Shopping Cart Class [duplicate]协助 OOP、PDO 购物车类 [重复]
【发布时间】:2012-12-29 22:31:40
【问题描述】:

可能重复:
What is the best method for getting a database connection/object into a function in PHP?
Database and OOP Practices in PHP

我正在尝试构建一个 OOP 购物车。

目前,它是一半 OOP,一半是程序性的......例如

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));
}

我的问题是,如果我想添加到购物车,那么在我的函数 addToCart 中,我需要再次要求数据库连接。

这似乎完全是浪费,考虑到每个函数都需要包含以下内容:

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

我知道这完全是低效的,并且想知道是否有人可以帮助我编写一个使用上述连接连接到数据库的骨架 OOP 购物车类?

这在构造函数中吗???当用户在前端从一个页面导航到另一个页面时,这会保持活跃吗?

我是 OOP 的新手,完全迷路了。

非常感谢。

【问题讨论】:

标签: php oop pdo


【解决方案1】:

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

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

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

【讨论】:

  • 为什么将CartData注入Cart?拥有CartDataHAS_A Cart 关系而不是CartHAS_A CartData 不是更好吗?
  • 购物车需要一个存储机制。不是相反。
【解决方案2】:

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

有几种不同的设计模式(最佳实践)来处理这个问题。对于所有这些,您都需要一个 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');
        // ...
    }
}

【讨论】:

  • 在我的世界里只有一种可能性:DI ;)
  • 我完全同意你们的观点,但我想概述一下 PHP 世界中最常用的方法。 Zend Framework 2 仍然使用单例,我认为 Laravel 使用 Registeries。
  • a) 同意@PeeHaa,并非框架所做的一切都是好的。 b) ZF2 和单例,到目前为止我在 2.0.5 中还没有找到。 c) Laravel 还使用了大量的静态调用 afaim,到目前为止我还没有真正了解 Laravel hipe。
  • @markus-tharkun ZF2 有单例,例如 GobalSharedEventManager。
猜你喜欢
  • 1970-01-01
  • 2013-02-21
  • 1970-01-01
  • 2015-05-17
  • 2020-11-25
  • 2023-03-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多