Well, I attempted to create a guard/grunt prototype for php. I attempted and failed. Why did I fail? The technology just isn’t there yet. I am going to have to re-think the architecture if I go any further.
I was using pcntl_signal to determine when an application shuts down, so that I could terminate any external processes that had been spawned by guard. One such process event handler was the livereload-protocol I implemented in php which via web sockets notifies any connected clients when files were changed on the server. Similar to how grunt watch works with livereload.
The problem is that pcntl_signal
doesn’t work in Windows. Thus, I stopped working on this.
Why not just use grunt?
Great question. There is no reason why you can’t use grunt. You’ll have to setup node, npm install grunt-cli and configure a Gruntfile. This isn’t that bad. I guess I’m crazy mad and wanted to toy around with asynchronous php.
Also think about how interesting it could be to setup an event handler to watch files on a disk space and asynchronously add rows in your database anytime those files changed?
class CrazyEloquentGuardEvent implements EventInterface
{
public function start($watcher)
{
// nothing to do here when guard firsts starts up
}
public function stop()
{
// nothing to do here when guard first stops
}
public function listen($event)
{
CrazyGuardLogModel::create([
'resource' => $event->getResource(),
'change_type' => $event->getTypeString(),
]);
}
}
Reactive Programming
Programming to an event loop in php is wild. It is also extremely powerful. I love the asynchronous aspect of node.js but it has drawbacks too. One drawback is the complexity. Anyone who has worked in both express and Laravel would likely tell you that Laravel is easier to use - I certainly would.
However, the benefits of an event loop frees us from waiting on things. Here is how I handled an event loop in React for the LiveReload server. I also used Ratchet for the WebSockets server which piggy backs off React. The only reason I am tampering with the React server here is so that I can have more control over what goes into the Event Loop.
public function start()
{
$config = $this->config;
$loop = \React\EventLoop\Factory::create();
$app = new \Ratchet\App($config['host'], $config['port'], $config['host'], $loop);
foreach ($config['routes'] as $route)
{
call_user_func_array(array($app, 'route'), $route);
}
$loop->addTimer($config['timeout'], array($this, 'watchTempFile'));
$app->run();
}
If you’d really like to dig in, you can see the full extent of the code in the codesleeve/guard-livereload repository. I may change this eventually, but I think I’ll re-architect the entire thing if I do. Basically the react event loop cannot be an external process fired by codesleeve/guard, instead it guard needs to become itself an event loop and I will have to compartmentalize all the different events and configs together so that it is easy to drop in new event handlers. It’s do-able I believe but right now isn’t any where on my priority list of todos.