0

I have a terminal application that is currently written in Bash, about 20,000 SLOC. One thing that I like about the way that it's set up is that it is quite modular. Different components are spread across different files, which can be executed at run time. This means that parts of the system can be "hot swapped" or updated during runtime without needing to kill the main program and re-execute it.

The disadvantage is there is a lot of database I/O, which makes it super janky since Bash is really not suited for this. Currently, it interfaces with HTTP APIs which spawn PHP.

I'd like to rewrite it natively in PHP (CLI) to cut out the middleman layer, so the application can communicate directly with the database, making maintenance much easier. One problem I've been pondering though is how to replicate the same modularity with Bash. With Bash, if I call script A, and I make a change to script B, and then I enter script B from script A (assuming it's in a conditional block somewhere, not right at the top of the file), the changes are picked up without needing to re-execute script A, since script B isn't interpreted until it gets executed.

I'm struggling to figure out how to achieve this with PHP. For instance, this will not work:

include('script.php');

The reason is that includes are all executed when the script is interpreted, not when it is executed at run time.

A similar question has been asked already, but it doesn't specifically address this aspect, just how to launch another script in general. I want to basically be able to spawn the script anew at runtime, when the application decides it should be executed. shell_exec and passthru seem to be all that is built into PHP that would be similar, but I'm not sure this is right since that's just spawning another system shell and doing it there, so it's not as "direct" as with Bash.

What would be the proper equivalent in PHP of this in Bash:

if [ "$x" = "3" ]
then
   ./launchscriptnow.sh
fi

The user should now be executing launchscriptnow.sh. Remember that this is an interactive application, so it's not just doing something and returning a value. The user could be here for 2 seconds, 5 minutes, or an hour.

So that ./launchscriptnow.sh is only interpreted when the code gets to that line, not when the parent script itself is interpreted? Is this kind of thing purely a shell construct or is there an equivalent to this?

5
  • Well, you could call the PHP-Script over CLI by using exec ('php YOUR-SCRIPT.php') or something like that. Commented Jun 28, 2021 at 13:06
  • @wayneOS Sorry, I've clarified my question a little bit. It needs to be interactive which I don't think exec fulfills Commented Jun 28, 2021 at 13:14
  • 1
    Instead of exec, could you use proc_open and then do what wayneOS says? Commented Jun 28, 2021 at 13:39
  • 1
    Try passthru. It's effectively exec but with stdin and stdout attached as you'd expect. Commented Jun 28, 2021 at 13:56
  • @msbit Unfortunately, passthru seems to be not be up to it, I get Fatal error: Uncaught PhpSchool\CliMenu\Exception\InvalidTerminalException: Terminal is not interactive (TTY). If I run the PHP script directly from the shell, this doesn't happen, so passthru seems to be limited or filtering stuff out Commented Jul 28, 2021 at 14:55

2 Answers 2

2

I'm don't understand your concern about "when the script is interpreted" vs "when the script is executed"? I have a number of scripts that use a variable name for the script to be included and make that decision right before executing the include statement. $result = include($script_name) will work fine and the decision about which script to include can be made at run time.

The way you describe the problem does not seem to indicate that you want to "launch" another process, but I could be wrong.

Sign up to request clarification or add additional context in comments.

7 Comments

In Bash, doing something like ./launchscriptnow.sh from within a script executes a new Bash instance as a subshell, allowing hotloading, which is not how PHP include/require work (they load the file once only).
msbit has it right, I need to hot load rather than load when the parent script is loaded.
include_once($file_name) includes a file once. `include($file_name)' will load the file again and can indeed be used for hot loading.
include($file_name) will "load" the script when the function is called, not when the parent script is loaded. It is not a 'C' style include.
Huh, very interesting! I just tried this out, simply calling require/include in a loop, and you are right @nusbaum, the required/included file is re-evaluated each time. This goes against how I thought the PHP opcode cache must work; I guess you learn something new every day.
|
1

Against all recommendations you could:

$script = file_get_contents('module_b.php');
$script = str_replace('<' . '?php', '', $script);
$script = str_replace('?' . '>', '', $script);
eval($script);

1 Comment

After a bit of investigation, I'd suggest that @nusbaum's answer would be better for your use-case.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.