1

我有一个在命令行上运行的 PHP 守护程序脚本,可以通过 telnet 等连接并接收命令。

它对命令的作用取决于加载了哪些模块,当前在开始时已完成。(为简洁起见,下面的伪代码)

$modules = LoadModules();
StartConnection();

while(true){
  ListenForCommands();
}

function LoadModules(){
  $modules = Array();
  $dir = scandir("modules");
  foreach($dir as $folder){
    include("modules/".$folder."/".$folder.".php");
    $modules[$folder] = new $folder;
  }
}

function ListenForCommands(){
  if(($command = GetData())!==false){
    if(isset($modules[$command])){
      $modules[$command]->run();
    }
  }
}

因此,一个名为“bustimes”的示例模块将是一个名为 bustimes 的类,位于 /modules/bustimes/bustimes.php

这工作正常。但是,我想让它可以即时更新模块,因此作为 ListenForCommands 的一部分,它会查看模块的文件时间,确定它是否已更改,如果是,则有效地重新加载该类。

这就是问题所在,显然如果我再次包含类文件,它会出错,因为类已经存在。

到目前为止,我对如何解决这个问题的所有想法都很恶心,我想避免这样做。

到目前为止,我有一些潜在的解决方案,但我对它们都不满意。

  1. 当模块更新时,将其放在新的命名空间中并将引用指向那里

    我不喜欢这个选项,我也不确定它是否可以完成(好像我是对的,命名空间必须在文件顶部定义?这绝对可以使用 file_get_contents() 解决,但我更喜欢避免它)

  2. 解析 PHP 文件,然后使用 runkit-method-redefine 重新定义所有方法。

    任何涉及这种解析的事情都是一个糟糕的计划。

  3. 不要包含该文件,而是使用相同的所有内容制作文件的副本,但将 str_replace 类名替换为末尾带有 rand() 或类似名称的内容以使其唯一。

是否有人对如何 a) 解决此问题或 b) 重组模块系统以使此问题不发生有任何更好的想法?

非常欢迎任何建议/想法/建设性批评!

4

2 回答 2

2

您可能应该在分叉的进程中按需加载文件。

您收到一个请求 => fork 主进程,包含该模块并运行它。

这也将允许您一次运行多个命令,而不必等待每个命令运行后再启动下一个命令。

在 php 中分叉:http: //php.net/manual/en/function.pcntl-fork.php

于 2013-09-13T13:18:50.127 回答
0

如果模块使用外部类(在命名空间中具有相对路径),则使用命名空间的技巧将失败。解析技巧非常危险 - 如果模块应该保持状态怎么办?如果不仅方法发生了变化,而且,例如,实现的接口的名称发生了变化,该怎么办?如果它们链接到重新加载的类的实例,它将如何影响其他对象?

我认为@Kethryweryn 是您可以尝试的。

于 2013-09-13T13:20:28.563 回答