Table of contents
- How to use
- Re-running specific lines
- Why the reload problem remains largely unsolved
- Code walkthrough
- References
You may have run into the annoying situation of needing to exit and restart your Tinker session each time you modify your code.
In this walkthrough we will look at one way you can easily refresh your Tinker session by using the script below.
01: <?php
02:
03: use Illuminate\Support\Facades\Process;
04:
05: $__tinkerModeDefinedVars__ = get_defined_vars();
06:
07: $_reload = function ($lineStart = null, $endLine = null) use ($__tinkerModeDefinedVars__) {
08:
09: $histFile = '.__tinkerMode__history.php'; //stores executable history
10:
11: $argsIsSet = ($lineStart !== null && $endLine !== null);
12:
13: if ($argsIsSet) {
14: $oldShell = $__tinkerModeDefinedVars__['__psysh__'];
15: $oldShell->runCommand("hist --show $lineStart..$endLine --save $histFile"); //get history from old shell
16:
17: //replace old executable history
18: $rawHistory = file_get_contents($histFile);
19: $formattedHistory = str_replace("\n", ';', $rawHistory);
20: file_put_contents($histFile, '<?php ' . $formattedHistory);
21: }
22:
23: $tinkerMod = __DIR__ . '/tinkerMod.php';
24: $histFile = (($argsIsSet) ? $histFile : '');
25: Process::forever()->tty()->run("clear && php artisan tinker $tinkerMod $histFile"); //start a new shell
26: };
How to use
- Include the
tinkerMod.php
file when starting your session i.e.:php artisan tinker tinkerMod.php
. - To restart your session, call on the
$_reload()
function.
Re-running specific lines
- Once your session is loaded with
tinkerMod.php
type out thehistory
orhist
command to get the history of everything your typed out. - Note the start and end line numbers you would like to run.
- You can now pass this into the reload function to reload your session and replay the desired history i.e.:
$_reload(3,8)
.
- You might want to clear your history from time to time (hist --clear) to make it easy to search through your history log.
- You might want to add tinkerMod.php, .tinkerModehistory.php to your .gitignore file if you do not want to commit them as part of your project.
- The current implementation doesn't handle multiline code very well. Thus if you copy-pasted code into your Tinker session, the script is not able to handle the replay very well.
Example of copy-pasted code
Why the reload problem remains largely unsolved
Starting a new shell within the current shell giving your the reload effect is the easiest part.
The hardest part has to do with the things you create before and after you start that session.
Let's say you are provided with the ideal Tinker session. It automatically reloads when you make changes to your code.
So say you created a class then play with it within Tinker, and you go like oh I should update one of the methods within that class to now return an array instead of a boolean.
You make that change and reload the session, sure, from now on every instance of that class you create will return an array but what about the earlier instance that returns a boolean? Does some code depend on it? If you try using it, it might lead to undesired and most likely confusing results.
There is a quick fix though, which is to instantiate all your old code, this works.
One of the maintainers of the Psysh [↗] (the library Tinker runs on top of) talks about the gymnastics that will be required to go around this in a thread [↗] on GitHub.
Code walkthrough
The script is set to achieve two main goals:
Start a new session
A new Tinker session when the $_reload
function is called without parameters.
It achieves this using the Laravel Process [↗] class on line 25
.
It clears the screen and then starts a new Tinker session whiles loading up tinkerMod.php
in the process so you can keep reloading when you need to.
Rerun code
When a start and end line is provided to the $_reload
function. The function fetches an instance of the old shell session on line 14
i.e.: $__tinkerModeDefinedVars__['__psysh__'];
It then runs the hist --show x..y --save history.php
command (line: 15)
to store the history you will like to run to a PHP file.
This is further cleaned up to make it executable by appending a < ?php
at the beginning of the file and ;
to terminate each line.
Once this is done the file is loaded up and executed during the new shell creation on line 25
.
References
- Psysh [↗] is the REPL powering the Tinker Artisan command.
- Laravel [↗] now provides a wrapper for running external processes [↗] which is used in the above script. This itself is based on a Symfony package [↗].
- This GitHub thread [↗] presents interesting ideas on the subject.
- Since the Tinker implementation is based on the Psysh package, you get access to some useful functionalities that are not mentioned in the Laravel docs. Here are links to some interesting commands:
Here is another article you might like 😊 How to remove new (untracked) files from a git repo