Getting Started

Getting started with Labrador should be simple out-of-the-box. Extend the AbstractApplication class and implement the AbstractApplication::doStart method. This method should return a Amp\Promise that resolves when your app has finished running. If you've already read the Quick Start on the README some code below may look familiar to you. However, there are some important additions in this documentation compared to the README so review the code carefully.


// app.php in your project's root directory

require_once __DIR__ . '/vendor/autoload.php';

use Cspray\Labrador\AbstractApplication;
use Cspray\Labrador\DependencyGraph;
use Cspray\Labrador\Engine;
use Amp\Promise;
use Amp\Delayed;
use Amp\Log\StreamHandler;
use Monolog\Logger;
use function Amp\call;
use function Amp\ByteStream\getStdout;

class HelloWorldApplication extends AbstractApplication {

    protected function doStart() : Promise {
        return call(function() {
            yield new Delayed(1);  // just to show that we are running on the Loop
            $this->logger->info('Hello Labrador!');

    public function handleException(Throwable $throwable) : void{
        parent::handleException($throwable);  // the AbstractApplication will log the $throwable as an error 
        // If you need to do something special when an exception is thrown in your app other than logging it


// Be sure to customize the logger to be appropriate for your needs!
$logger = new Logger('labrador.hello-world');
$logger->pushHandler(new StreamHandler(getStdout()));

// More information about how to create your own DependencyGraph can be found in /docs/how-tos/creating-your-dependency-graph
$injector = (new DependencyGraph($logger))->wireObjectGraph();

// We want to make sure that the dependencies required by AbstractApplication are autowired using the $injector
$app = $injector->make(HelloWorldApplication::class);

// Note we are making an _interface_ and not an implementation. By default this will return an AmpEngine instance
$engine = $injector->make(Engine::class);


Important Concepts

Based on the simple boilerplate above there's some important concepts to take into consideration when it comes to creating Labrador applications that we believe should be important in your own applications.

Logging is mission-critical

You'll notice that our example doesn't just echo out "Hello Labrador!" but goes so far as to log the information out. If you were to actually run this example you'd see even more information logged. If you registered Plugins you'd see even more detailed information logged about exactly what is happening during the Plugin loading process. Real life experience has proved that proper logging can make an application easier to maintain.

You should treat logging the same in your own application. If there's anything meaningful that occurs in your app you should log it. Gaining access to the Logger is simple. Implement the Psr\Log\LoggerAwareInterface; the Application interface extends this. Next, use the Psr\Log\LoggerAwareTrait; the AbstractApplication implementation uses this. As long as the $injector from the DependencyGraph above create your object then that object will automatically have the $logger property set.

Dependency Injection is important

The $injector in the code above plays a highly critical role in the running of a Labrador application. We make use of Dependency Injection with simple interfaces at code boundaries to make code easy to test and easy to replace. The Auryn injector helps make the pain of Dependency Injection go away. Some cool things the $injector is doing for us includes taking care of the dependency that is required by the AbstractApplication interface and allowing us to create our Engine instance using the Engine interface. Different libraries can define their own implementation to use for the Engine. The $injector is also how we take care of ensuring that Psr\Log\LoggerAwareInterface instances have the Logger set on object creation.

If you have not done so yet check out Labrador's DependencyGraph source code. It gives a good baseline for the functionality provided by Auryn. After that you should definitely check out the Auryn documentation and learn to embrace Inversion of Control.

Next Steps

The real power of Labrador comes with its concept of "plugins". It is highly recommended you check out the Plugins: Overview next.