PHP中的OO麻烦(或任何非持久性环境)

时间:2011-01-13 18:23:14

标签: php oop persistence

除非你小时候算上QBASIC,否则我学会了五年前在大学里以面向对象的方式编程,所以我理解它是如何工作的。但是,我很难在我的大型数据库驱动的PHP应用程序中实现它,因为在每个页面加载时都会重新初始化所有内容。唯一真正的持久性是数据库,但是从数据库中提取所有数据并重建每个页面上的所有对象负载听起来像很多开销而没有太大的好处,因为我只需要在下一次重复操作页面加载。

此外,当我尝试将应用程序(现在第三次尝试)重新分解为OO时,我遇到了这些问题:


存在一个名为“Person”的类,它包含各种属性。该类的一个扩展名“Player”包含“父”属性,类型为“播放器”。最初,没有任何玩家从任何父母开始,所以他们都将被初始化为该字段为NULL。但是,随着时间的推移,父母将被添加到Players属性中,并将引用已存在的其他Player对象。

然而,在PHP中,我不得不重新建立已经拥有父母的玩家的类结构。在这种情况下,如果我实例化一个播放器,该播放器具有尚未实例化的播放器作为父节点 - 我有一个问题。


在处理PHP时是否有必要减少OO编程的范围?

4 个答案:

答案 0 :(得分:2)

您对OOP概念以及有关HTTP和持久性的概念感到困惑。

你的问题实际上并不是关于OOP - 它是关于在多个HTTP请求中持久保存OOP数据。

PHP不会自动在HTTP请求中持久保存对象 - 由你来处理它(在你的情况下,就像你说的那样:“从数据库中提取所有数据并重建每个数据上的所有对象页面加载“)。

答案 1 :(得分:2)

  

在处理PHP时是否有必要减少OO编程的范围?

没有。只有在必要时才需要使用延迟加载来实例化父播放器。

Class Player {

    protected $id;
    protected $name;
    protected $parentId;

    protected $parent;

    public static function getById($id) {
        // fetch row from db where primary key = $id
        // instantiate Player populated with data returned from db
    }

    public function getParentPlayer() {
        if ($this->parentId) {
            $this->parent or $this->parent = Player::getById($this->parentId);
            return $this->parent;
        }
        return new Player(); // or null if you will
    }

}

这样,如果你实例化玩家ID 40:

$john = Player::getById(40);

它没有填充$ parent属性。只有在调用getParentPlayer()时才会加载并存储在该属性下。

$joe = $john->getParentPlayer();

当然,只有$ parentId指向非NULL。

更新:当两个或多个玩家共享单个父级时,可以解决存储在受保护属性中的重复实例的问题,可以使用静态缓存:

    protected static $cache = array();

    public static function getById($id) {
        if (array_key_exists($id, self::$cache)) {
            return self::$cache[$id];
        }
        // fetch row from db where primary key = $id
        // instantiate Player populated with data returned from db
        self::$cache[$id] = ... // newly created instance
        // return instance
    }

如果您希望在每个请求中访问大量父项,则可以一次从数据库中选择所有记录并将它们存储在另一个静态池中。

答案 2 :(得分:1)

不是通过父母创造的物品确实是一件非常棘手的事情。您可以执行ID引用和构建PlayerManager之类的操作,为您执行链接。通过RUID的(运行时唯一ID)。但是,当然,您希望首先创建父母。

因此,当创建类似于数据库的OO结构的东西时,除了打印之外,如果你想对它进行一些额外的操作,我会鼓励这样做。可以从您的数据库创建一个播放器,然后,如果它有一个父节点,就像正常情况一样创建父节点。到达while循环中的父级时。你可以说,没有它已经创建。使用一个Player-manager类来保存你的玩家。所以它可以检查玩家(以及父母)是否已经在那里。

因此,您可以采用不同的方式遍历数据库,而不仅仅是线性化。

至于:是否有必要这样做。其实我自己也不太了解它。就我在网上看到的而言,似乎PHP类主要用于创建一个可以执行智能操作的对象(如DOMDocument)。

但是你真的必须将数据库表转换为对象吗?这取决于您的应用程序类型。如果打印是你想要的,它似乎不合逻辑。如果对对象进行大量调用(或通常是对表)的一些大操作,我可能希望看到一个很好的OO编程结构。

答案 3 :(得分:1)

PHP中的OOP编程对我来说更具有良好的可维护性和良好的架构(组合,工厂,基于组件的编程等)。

当然,您需要重新考虑一些环境中使用的设计模式。对象池等等。当然,一些设计模式在PHP中用于短期模块的PHP仍然非常好:单例,工厂,适配器,接口,延迟加载等。

关于持久性问题,有几种解决方案。当然数据库存储。但您也可以使用会话存储和应用缓存(例如 memcached 或apc)。您可以将序列化对象存储在此类缓存中。您只需要一个好的自动加载器来加载类(以及一个好的操作码,以避免在每次请求时重新解释源代码)。

有些对象加载和构建非常繁重,我们可以考虑一个ACL对象,加载角色,资源,默认策略,异常规则,甚至可能包含一些这些规则。一旦你得到它,每次请求都会重建这个对象。您应该研究在某处存储/加载此完成对象的方法,以限制其加载时间(避免SQL请求和构建时间)。 一旦建成,它肯定是一个可以延长寿命的物体,如1小时。

您无法存储为序列化字符串的唯一对象实际上是很快依赖于并发请求的数据更新。有些网站甚至不需要真正关心它,数据的准确性在公共网站发布新闻和财务会计应用中并不相同。如果您的应用程序可以处理预构建的序列化对象,您可以在框架中看到serialize-storage-load-unserialize作为一个简单的开销:-)但是有效地,不共享,没有对象监听所有并发请求,对与并行请求共享的对象没有写操作,直到该对象(或相关数据)存储在某处(和读取)。 将其视为挑战!