代码之家  ›  专栏  ›  技术社区  ›  Doug

重新加载类

  •  1
  • Doug  · 技术社区  · 11 年前

    我有一个在命令行上运行的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/sustimes.php中

    这很好用。然而,我想让它可以动态更新模块,因此作为ListenForCommands的一部分,它会查看模块的filemtime,确定它是否发生了更改,如果发生了更改则有效地重新加载类。

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

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

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

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

      我不喜欢这个选项,也不确定它是否可以实现(好像我是对的,名称空间必须在文件的顶部定义?使用file_get_contents()肯定是可行的,但我更愿意避免它)

    2. 分析PHP文件,然后使用runkit方法重新定义来重新定义所有方法。

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

    3. 不包括该文件,而是用所有相同的东西复制该文件,但str_replacement将类名放在末尾带有rand()或类似的东西上,以使其唯一。

    有人对如何a)解决这个问题或b)重组模块系统以避免这个问题有更好的想法吗?

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

    2 回复  |  直到 11 年前
        1
  •  2
  •   Kethryweryn    11 年前

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

    您收到一个请求 =>分叉主进程,包括模块并运行它。

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

    php中的Fork: http://php.net/manual/en/function.pcntl-fork.php

        2
  •  0
  •   OZ_    11 年前

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

    我认为@Kethryweryn是你可以尝试的东西。