I’ve bought Tinkerwell a while back but I could never seem to find the time to set it up and start using it.
During a weekend with more free time than usual I finally decided to set it up.
Writing a custom driver
As I needed custom support for the project I’m currently working on, I’ve quickly started writing a custom driver for it. Writing a driver is a quick and painless process, however it wasn’t long until I ran into an issue.
The way drivers are designed in Tinkerwell, there’s a method called bootstrap where you can load all your application specific start-up code.
The issue I ran into is around global variables. The PHP documentation mentions that:
When a file is included, the code it contains inherits the variable scope of the line on which the include occurs. Any variables available at that line in the calling file will be available within the called file, from that point forward.
This means that all variables defined in the included files are available inside the bootstrap function scope. However, trying to use any of those variables using global ends up resulting in those variables not being found, as they don’t exist in the global scope.
Variable scope and include
There is an work-around available, if you can extract all the variables that are used globally, you can declare them as global before including the bootstrapping files. This way assigning values to those variables ends up updating them in the global scope and further global calls work as expected. That is however tedious, as I couldn’t find an easy way to extract the variables used globally in the project.
As the PHP code that Tinkerwell runs is available in .phar format, I’ve ended up modifying the code to have the driver provide a list of files for inclusion and directly include them in the global scope. I’ve also created an issue to hopefully add support for this use-case in Tinkerwell.
Hopefully this provides a bit of insight into how variable scoping works with including files as this puzzled me for a second or 5 when I ran into it.
The official website calls Redux “a predictable state container for JS Apps”. The main benefit of Redux is that it shines a light on your global application state, allowing you to trace when, where, why, and how your application’s state changed.
The idea that global state is bad is drilled into programmers since the beginning of their programming career. One thing that isn’t clearly explained however is why.
There are several issues with global state, but the most important problem is that not only can anyone change the application state, but also that there’s no way you can tell who changed the state.
If your first contact with Redux comes in the context of a React Redux application, the Redux side of things will feel like magic.
As I usually try to understand the tools I’m using, the following tries to be a toy implementation of Redux in PHP, in the hopes of gaining a deeper understanding of the concepts behind Redux.
The most important realization was that Redux is mostly convention, with a bit of library code to tie it all together. As you could probably tell from the title, the language we’re gonna use is PHP, so consider yourself warned.
Great. Let’s go ahead and start with the simple state we’re going to manage:
$initialState = [
'count' => [
'count' => 1
Simple enough. As per the Redux convention, we don’t modify the state directly:
We’re just generating a new state array by incrementing / decrementing the previous value. Reducers receive part of the initial state array, based on their key, but more on that later when we’re going to introduce combineReducers. For now, let’s imagine countReducer receives the value in $initialState['count']:
'count' => 1
We still haven’t written any kind of library code yet, so far it’s all been convention.
If we take a look at the Redux API, we start by using the createStore method. We can then use the dispatch and subscribe methods to dispatch actions and subscribe to state change updates.
Translating that to PHP, let’s create a Store class. How would that look:
protected array $state;
protected Closure $reducer;
public function __construct(callable $reducer, array $initialState)
$this->state = $initialState;
$this->reducer = Closure::fromCallable($reducer);
The class now accepts an initial state and a reducer function. In Redux you can combine multiple reducers into one and pass that combined result to the createStore method, later on we’ll discuss how we can achieve that.
Great, how about dispatch and subscribe? Let’s start by adding a method to fetch the store’s state and then the subscribe method:
protected array $listeners = ;
public function getState()
public function subscribe(callable $listener)
$this->listeners = Closure::fromCallable($listener);
Subscribing to the store means adding a callback function which will be called when the state updates. How would we use the subscribe method?
Awesome. The only problem now is that our store accepts only one reducer. That’s also the case for the createStore Redux function. The way they solve this problem is by providing a combineReducers method: