【问题标题】:Is it possible to dynamically reload PHP code while script is running?是否可以在脚本运行时动态重新加载 PHP 代码?
【发布时间】:2012-06-09 21:44:26
【问题描述】:

我有一个使用 PHPSockets 的多人服务器,因此完全用 PHP 编写。

目前,每当我对 PHP 服务器脚本进行任何更改时,我都必须终止该脚本,然后重新启动它。这意味着任何在线用户都已断开连接(通常不是问题,因为目前没有这么多)。

现在我正在重写服务器脚本以使用自定义 PHP 类并稍微整理一下(你不想知道它今天看起来有多讨厌)。今天我在想:“不应该重新启动整个脚本就可以对php源进行更改吗?”。

例如,我计划创建一个包含user.phpmain.php 文件,其中包含MyUser 类和包含MyGame 类的game.php现在假设我想对user.php 进行更改并“重新加载”服务器,以便对user.php 的更改生效,而不会断开任何在线用户?

我试图找到其他回答这个问题的问题,我得到的最接近的是这个问题:Modifying a running script and having it reload without killing it (php),但这似乎并没有解决在线用户断开连接的问题。

更新

我自己的解决方案是:

  1. 在特殊情况下,包含文件 external.php,它可以访问一些变量并根据需要使用它们。执行此操作时,我必须确保代码中没有错误,因为如果我尝试访问不存在的方法,整个服务器将会崩溃。
  2. 用 Java 重写整个事情,这让我有可能使用动态类重新加载添加插件系统。奇迹般有效。再见 PHP。

【问题讨论】:

  • 我通常会将可修改的“配置”信息以与语言无关的格式(如 XML 文件)存储并对其进行修改。然后它应该是一个简单的方法调用来重新加载配置文件,并且用 Java 或 Python(例如)编写的资产也可以轻松地从外部操作服务器。至于动态更改程序的源代码?首先,这似乎是个坏主意……
  • 我认为你真正应该关注的是你是否真的需要每个玩家一个插槽,或者你是否可以让游戏变得更有状态。因此,客户端可以发送正常的 Web 请求,而不是从客户端到服务器的开放连接。但我知道这可能意味着完全重写,此时不是一个选项?此外,php 不支持“取消定义”类,因此如果您已经定义了“Test”类,则无法重新包含文件以再次定义“Test”类。
  • 我认为对于我所知道的所有网络游戏来说,当管理员想要对游戏文件应用更新时,服务器会重新加载并且人们会断开连接。也许最好有一个所有用户都可以连接的在线版本和一个只有您(或少数选定的人)可以连接的测试版本。当您希望更改生效时,请将它们保存到在线版本并重新启动服务器。这意味着您不必为要进行的每一个小改动都重新启动在线版本。
  • 这是不可能的。但是,您可以通过修改设计来完全避免这种情况。
  • 它不是为了改变配置,主要是添加新功能/修复错误(例如新命令,修复用户登录时发生的情况等)@Mike我实际上已经有多个可能的服务器所以绝对可以做到。我喜欢这样。

标签: php reload multiplayer


【解决方案1】:

简单的解决方案使用 $MyUser 而不是 MyUser

require MyUserV1.php;
$MyUser = 'MyUserV1';
$oldUser = new $MyUser('your name');
//Some time after
require MyUserV2.php;
$MyUser = 'MyUserV2';
$newUser = new $MyUser('your name');

每个声明的类都保留在内存中,但在最后一次 MyUserV1 注销时变为未使用
您可以让它们继承自抽象类 MyUser 以使用 is_a

【讨论】:

    【解决方案2】:

    如何将您的用户对象存储到APC 缓存中,同时您的主脚本从缓存中加载并经常检查新的操作码。

    要在缓存中包含函数,您必须包含SuperClosure Class。一个例子是:

    if (!apc_exists('area')) {
      // simple closure
      // calculates area given length and width
      $area = new SuperClosure(
        function($length, $width) {
          return $length * $width;
        }
      );
      apc_store('area', $area);
      echo 'Added closure to cache.';
    } else {
      $func = apc_fetch('area');
      echo 'Retrieved closure from cache. ';
      echo 'The area of a 6x5 polygon is: ' . $func(6,5);
    }
    

    See here for a tutorial on APC.

    【讨论】:

    • 好吧,现在你完全失去了我……APC??刚刚在php.net/manual/en/book.apc.php 上检查了一下,它看起来确实很强大。我怀疑我会使用它,但我认为在我的情况下不会有很多人推荐它..
    • 好像只存储数据,不明白怎么改代码的?
    • 查看这个链接:devzone.zend.com/1812/using-apc-with-php 转到它说动态定义函数的部分。
    【解决方案3】:

    您不能再次include 使用相同的class 文件,但您可以使用array 这样做。如果您确实需要,也可以将 array 转换为 class。不过,这仅适用于数据,不适用于行为(方法)。

    【讨论】:

    • 是的,不使用eval 很难将代码写入数组,这将是非常愚蠢的。 :)
    【解决方案4】:

    Runkit 将允许您在运行时添加、删除和重新定义方法(除其他外)。虽然您无法更改类或其现有实例的已定义属性,但它允许您更改这些对象的行为。

    我不建议将此作为永久解决方案,但它可能在开发过程中很有用。最终,您需要将游戏状态存储到文件、数据库、Memcache 等中。

    【讨论】:

      【解决方案5】:

      我对 PC 游戏中的这些东西了解不多,但您可以尝试从数据库中为用户获取所有变量,然后使用这些变量更新文本字段或按钮

      在web中使用的是AJAX(改变数据而不刷新页面)。不就是用来编程的吗?

      【讨论】:

        【解决方案6】:

        我对 PHP 不太熟悉,但我假设创建了一个进程来运行脚本,这样做时它会复制运行程序所需的指令并开始在 CPU 上执行,在此期间,如果您要“更新”说明,您需要最终终止进程并重新启动它。包含是一种将您的类和文件链接在一起的奇特方式,但最终处理器会将这些信息与它们的文件存储位置分开,并且在您重新启动进程之前它最终会有所不同。

        我不知道有任何系统可以在其中创建代码并主动编辑它并在代码运行时查看更改。大多数活动程序需要重新启动才能重新加载新的源代码。

        【讨论】:

        • 查看 Erlang 的语言和运行时支持在运行程序中热加载代码。
        • 这个视频也出现在我的脑海中,不确定它是如何工作的,但它很酷:wimp.com/videogames
        • @EmilVikström:这很酷,我刚刚研究了热插拔。这是一个有趣的想法,但它仍然需要重新加载,但我想知道它对于服务器来说有多复杂。谢谢我会继续阅读! (在西蒙:)是的,我已经看到了,实际上我之前参加过他的演讲,但我认为框架的结构需要重放东西,从而重新加载代码或在程序中做一些花哨的抽象这被用来进行编辑,并且预计变量会发生变化,因此已经针对这种可变性进行了编程,但确实很棒。
        【解决方案7】:

        难道不用重启整个脚本就可以修改php源码吗?

        [...]

        我打算拥有一个包含 user.php 的 main.php 文件 其中包含类 MyUser

        在你的情况下,你不能。类只能在运行脚本中定义一次。您需要重新启动脚本才能重新定义这些类。

        【讨论】:

        • 非常感谢。只是出于好奇:是否有可能重新定义一个函数?
        • @SimonAndréForsberg:您可以在运行时重新定义 lambda。这就是我在关于基于原型的编程的评论中所指的内容。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2023-01-11
        • 1970-01-01
        • 2014-03-10
        • 1970-01-01
        • 1970-01-01
        • 2020-10-22
        • 1970-01-01
        相关资源
        最近更新 更多