在PHP中的对象持久化

20

我是一个新手网页程序员,之前主要使用Java创建桌面应用程序。

我正在尝试找出如何在PHP中创建持久对象。也许“persistent”不是正确的词,我不希望该对象对每个客户端都是唯一的,就像将其序列化在会话变量中一样。我想在服务器上创建该对象,并使该对象始终可访问。该对象将查询数据库并存储一些数据。这样,每个页面加载时,PHP代码将从同一持久性对象获取数据,而无需每次查询数据库。

我目前正在使用单例模式进行对象创建,因为我最初的理解是它将允许我实现所需的功能。对象的一部分是数组,当我执行添加值到数组的PHP页面时,并在同一页上访问该值时,它是正常的。但是,当我向数组添加一个值,然后加载另一个访问该值的页面时,该数组又变为空。

这可能吗?我是否过度反应,认为频繁查询数据库是不好的?在任何一秒钟内,可能会有多达20个用户请求数据,我觉得每次查询数据库都太荒谬了。

谢谢


2
每秒20个用户请求并不算多。 - Ben
即使每个页面加载超过20个查询的用户数量再多,也不算什么。这并不是关键点。主要问题在于当数据结构发生变化时如何维护数据库。 - Tarion
简短回答:通过 session_start() 和全局变量 $_SESSION 数组,持久性可以在 HTTP 请求之间实现。这两个是开始阅读的东西(https://php.net)。 - theking2
7个回答

14

与 Java 不同,PHP 没有持久性的概念:JVM 允许 Java 应用在 HTTP 请求之间在内存中保持不变;而每次服务新的 HTTP 请求时,Web 服务器都会分叉出一个新的 PHP 进程,因此,一个对象的静态变量将无法为您在请求之间保持数据。

使用数据库来存储持久数据。Web 编程注重并发,所以不必担心数据库查询——20 次/秒很少。如果达到了数据库的极限,可以选择添加缓存层或通过添加只读从节点来扩展硬件。


1
PHP确实具有在HTTP请求之间存储数据的能力。https://www.php.net/manual/en/function.shmop-write.php - Thoracius Appotite
很遗憾,这不是正确的答案。会话允许跨请求持久性。 - theking2

12

通常情况下,您可以通过使用数据库来获得持久性。如果这是瓶颈,您可以开始缓存数据,例如在memcached中或者可能是在您的Web服务器上使用序列化数组保存在本地文件中。


3
对于简单的查询,是重复查询数据库以获取相同数据更快,还是缓存对象更快?假设查询本身需要0.1秒。通常来说,文件+序列化对象和数据库+对象填充哪个更快? - Keyne Viana
直到你真正遇到性能问题之前,你应该不太关心性能。 - Tarion
6
你应该始终关注性能。这可以节省大量时间,避免一开始就学习正确的方法。我曾经不得不修改一个由他人用PHP制作且存在性能问题的项目。解决它花费了我很长时间,比他一开始就做对要花更长的时间。 - Bart Burg
@KeyneON 数据库使用文件。有些数据库与它们所在的服务器分开。因此,从技术上讲,直接文件访问始终会更快。数据库始终更方便。 - mAsT3RpEE
关注性能的时间问题仍然是一个深受争议的话题。 - Camille Goudeseune

1

虽然这可能不是最美观的解决方案,但您可以使用SESSIONS来解决此问题。

class SomeObject{

    public function __costructor{
        $_SESSION['object'] = serialize($this);
    }

}

在另一个页面上,你可以简单地调用该对象:
$object = unserialize($_SESSION['object']);

虽然这种方法似乎最简单,但应该非常小心:

  1. 要知道,会话的大小取决于服务器的流量,因为许多用户同时请求每个会话。请自行谨慎地缩放大小。

  2. 始终对会话进行序列化和反序列化,否则会话将出现问题

无论你选择哪种方式,请在自己的深思熟虑下进行。祝好运。


0
Web编程中的数据持久化是通过使用cookie/session和在Web页面调用之间传递cookie/session变量来完成的。理论上,任何类型的数据都可以存储在这些变量中,但对于大多数实际目的而言,只有更重要的数据(更像令牌)需要传输到服务器和浏览器以识别/重构所需的对象(带或不带数据库)。

0
我建议你好好看看memcached。当你谈论服务器负载和性能能力时,一个有用的指标通常是每秒页面数。如果你有一台专用服务器并且正在进行未经优化但非常密集的工作,你可能只能提供5个页面/秒。利用数据缓存是增加这个数字3到10倍的好方法。然而,它总是一个权衡,就数据可以变得多陈旧而言。你真的需要测试你的网站来正确理解(量化)其他可能限制性能的因素,比如每页的其他连接(图像、CSS等)、文件I/O、其他网络活动,最后但并非最不重要的是实际的


PS:Memcached支持多个服务器,是一个经过充分测试和稳定的扩展。APC在单个服务器上表现出色,并支持自定义使用,但当涉及到分布式应用时,Memcached仍然胜出。但是,您需要使用增量作为“锁”逻辑来进行一些有趣的工作,因为另一个页面可能已经修改了该值。依赖于Memcached将运行良好,但在编写此接口时要小心,以免假设它没有更改并覆盖更新的数据。http://www.php.net/manual/en/memcache.increment.php - zanlok

0

可以将对象存储在当前会话中。现在只需创建一个能够存储和重新创建对象本身的基类。任何派生对象也将是持久的。

您可能想阅读这里:持久化基类和示例

据我所知,会话存储在RAM中,因此应该比将对象序列化到磁盘以实现持久性更快。


此页面的链接不可用。 - Blip

-1

停止使用单例模式,改用依赖注入。

最好的方法是使用数据映射器(http://www.martinfowler.com/eaaCatalog/dataMapper.html),并通过动态属性将其附加到对象上。让数据映射器处理持久性。

$CS = new CookieStorage();
$SS = new SessionStorage();
$FS = new FileStorage('config/object.db');

$DM = new ObjectDataMapper($FS);

$O  = new Object($DM);

$Object->DynamicProperty = 1;

现在,DynamicProperty 将自动持久化,并将自动从文件 object.db 中加载。下面是类定义:
class Object
{
    public function __construct(MapperInstance $Storage = NULL)
    {
        $this->setMapper($Storage?: new ObjectDataMapper(new FileStorage('config/object.db')));
    }

    public function __get($name)
    {
        $this->_Mapper->getProperty($name);
    }

    public function __isset($name)
    {
        $this->_Mapper->isProperty($name);
    }

    public function __set($name, $value)
    {
        $this->Mapper->setProperty($name, $value);
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接