1

I have a PHP daemon script running on the command line that can be connected to via telnet etc and be fed commands.

What it does with the command is based on what modules are loaded, which is currently done at the start. (psuedocode below for brevity)

$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();
    }
  }
}

So, an example module called "bustimes" would be a class called bustimes, living in /modules/bustimes/bustimes.php

This works fine. However, I'd like to make it so modules can be updated on the fly, so as part of ListenForCommands it looks at the filemtime of the module, works out if it's changed, and if so, effectively reloads the class.

This is where the problem comes in, obviously if I include the class file again, it'll error as the class already exists.

All of the ideas I have of how to get around this problem so far are pretty sick and I'd like to avoid doing.

I have a few potential solutions so far, but I'm happy with none of them.

  1. when a module updates, make it in a new namespace and point the reference there

    I don't like this option, nor am I sure it can be done (as if I'm right, namespaces have to be defined at the top of the file? That's definitely workaroundable with a file_get_contents(), but I'd prefer to avoid it)

  2. Parsing the PHP file then using runkit-method-redefine to redefine all of the methods.

    Anything that involves that kind of parsing is a bad plan.

  3. Instead of including the file, make a copy of the file with everything the same but str_replacing the class name to something with a rand() on the end or similar to make it unique.

Does anyone have any better ideas about how to either a) get around this problem or b) restructure the module system so this problem doesn't occur?

Any advice/ideas/constructive criticism would be extremely welcome!

tereško
  • 58,060
  • 25
  • 98
  • 150
Doug
  • 3,312
  • 1
  • 24
  • 31

2 Answers2

2

You should probably load the files on demand in a forked process.

You receive a request => fork the main process, include the module and run it.

This will also allow you to run several commands at once, instead of having to wait for each one to run before launching the next.

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

Kethryweryn
  • 639
  • 4
  • 11
0

Tricks with namespaces will fail if module uses external classes (with relative paths in namespace). Trick with parsing is very dangerous - what if module should keep state? What if not only methods changed, but, for example, name of implemented interface? How it will affect other objects if they have link to instance of reloaded class?

I think @Kethryweryn is something you can try.

OZ_
  • 12,492
  • 7
  • 50
  • 68