Binding Objects as Laravel Services

Like this article? Frustrated by Magento? Then you’ll love Commerce Bug, the must have debugging extension for anyone using Magento. Whether you’re just starting out or you’re a seasoned pro, Commerce Bug will save you and your team hours everyday. Grab a copy and start working with Magento instead of against it.

Last time we discussed instantiating objects in Laravel using the make method. Today we’re going to talk about services, service containers, and binding objects into service containers.

Before we do that, we should briefly discuss service oriented architecture.

This article, and series, is focused on exploring Laravel’s internals. Many of the code samples are optimized to help you understand how Laravel is built, and may not be a best practice for day-to-day application development.

Service Oriented Architecture

Wikipedia defines Service Oriented Architecture as

Service-oriented architecture (SOA) is a software design and software architecture design pattern based on distinct pieces of software providing application functionality as services to other applications. This is known as service-orientation. It is independent of any vendor, product or technology

This is as good a definition as any. There may have been a time when “Service Oriented” refereed to a specific set of technologies, but at this point it’s a generic term that applies to a general approach to application development and/or code organization in a single application.

The best way to think about services is as an approach to programming where a service is some code that does a thing that’s not directly related to your application. A very basic example is a database querying service. If you’re writing an application to show cute cat pictures on the internet, your objects that describe a cat’s cuteness shouldn’t contain code for connecting to the database, parameterizing query strings, etc. Keeping your code for talking with a database hidden behind a service means you can concentrate on cat logic, and leave the tricky programming problems involved with talking to a database to the database service developers.

The current fashion in PHP framework development is heavily based on SOA ideas, and if you want to start thinking like a Laravel core developer you’ll want to start adopting the mindset of someone who implements services (as opposed to someone who uses services to build cute cat websites).

Service Containers

Like all abstract concepts, eventually you need to create an implementation for your service based system. The Symfony 2 project is a driving force behind popularizing the service container approach, although the idea’s been floating in the air for several years now.

A service container is an object that’s either globally available or easily “fetch-able” via anywhere you’d need to use services. A service container contains key/value pairs where the key is a service name, and the value is an object that implements a service.

If you’ve ever used Symfony 2, you’re likely familiar with service calls that look something like this

$this->get('my_mailer');

$this->getContainer()->get('my_mailer');

$this->container->get('my_mailer');

As the service user (or “client programmer”), you fetch a reference to the service container object, and then tell the service container object you want a named service (my_mailer above).

Laravel also uses a service container, but with a few opinionated differences. First, in Laravel, the global Application object is the server container. If Laravel had a my_mailer service, you could access it by getting an application object reference

$app = app();

And then using PHP’s ArrayAccess syntax on the application object to fetch the service by name.

$mailer = $app['my_mailer'];

After last week’s primer you’re probably chomping at the bit to checkout Laravel’s ArrayAccess implementation. We’ll get there eventually, but for now just treat it as the magic syntactic sugar that makes code for fetching a service object more compact.

Let’s look at a real service. A stock Laravel 4.2 system comes with a db service. If you use this service, you can run SQL queries against a database. Assuming you’ve setup Laravel to connect to a MySQL database, you can use the following code to run a SHOW TABLES query against the database.

$app = app();
$result = $app['db']->select('SHOW TABLES');
var_dump($result);

If you use var_dump to look at the db service object.

var_dump($app['db']);

you’ll see the service container returns an Illuminate\Database\DatabaseManager object

object(Illuminate\Database\DatabaseManager)[93]
  protected 'app' => 
  ...

This object is an implementation of the db service. One advantage of services is they’re another way to implement an “inversion of control” system. While Illuminate\Database\DatabaseManager is the current service implementation, a future version of Laravel, or a specific Laravel application, may use a different db service.

If you’re an experienced Laravel developer, you know there’s other ways to access services that don’t involve calling the app function. We’re working up to those methods, we will get there eventually, but for today we’re sticking with calls to app.

Creating a new Service

So, the question that’s likely on many of your lips is

How do services get inside the application container

This is where binding enters the story. Binding is one of those overloaded terms that means a variety of different things on different platforms. In Laravel, you bind a service to the Application. Binding a service to the application means other developers can access your service via the application object’s $app['service_name'] syntax.

From a high level that’s the only thing binding accomplishes. It’s nothing more complicated than that. Any first level magic user can cast this spell, no components needed. To prove it, we’re going to create a helloworld service. Our end goal will be the ability to run code that looks like the following

$app['helloworld']->sayHello();

and have it echo out the ancient and ubiquitous text Hello, World!.

The high level steps you need to take when creating a service are

  1. Pick a name (in our case, helloworld)

  2. Create an implementation class

  3. Bind the implementation class into the application container

Laravel has a lot of built-in classes and systems for creating packages and service providers — but in this tutorial we’re going to skip all that and concentrate on the most dead simple way to bind a service into the application container. You might use our techniques below to add a service to a single application, but you’d never use it to distribute your service to other Laravel systems.

If you’re interested in learning the right way to distribute your Laravel code, you’ll want to investigate Laravel Service Providers. Service Providers are outside of our scope for this series.

Creating the Implementation Class

We’ve already picked a name for our service (helloworld). The next step is to create an implementation class. You can name this class anything you’d like, and place is anywhere that Laravel will autoload classes from. We’re going to name our class Pulsestorm\Example, and to make things simple we’ll drop it in the app/models folder. If you’re new to Laravel, app/models is one of the default folders the autoloader will load classes from.

Create the following file in the following folder

#File: app/models/Pulsestorm/Example.php
<?php
namespace Pulsestorm;
class Example
{
    protected $_times = 0;
    public $message = "Hello World!  We've met %d times!";
    public function sayHello()
    {        
        echo sprintf($this->message, $this->_times);
        $this->_times++;
    }
}

Here we have a simple class. This class implements a hello world service. There’s no special classes to inherit from or interfaces to implement — any class can be a service class. It’s good OOP practice to have service classes implement interfaces or extend from abstract classes, but Laravel doesn’t require it.

Before we bind our class as a service, let’s test it out. Add the following simple route configuration to the end of app/routes.php.

#File: app/routes.php
Route::get('/service-tutorial', function()
{
    $object = new Pulsestorm\Example;    

    $object->sayHello();    
    echo "\n<br>\n";
    $object->sayHello();    
});

And then load the route in your web browser (using your own application URL, of course)

http://laravel.example.com/service-tutorial

You should see output something like this

Hello World! We've met 0 times! 
Hello World! We've met 1 times!

That is, the sayHello method outputs the Hello World text, and also keeps track of how many times we’ve called the sayHello method.

With our class working, we’re ready to move on to the service binding.

Binding the Service

As a reminder, binding a service means we’re making it available to users in the application service container. All binding a service requires us to do is call the Application object’s bind method. We’re going to bind our service in the app/start/global.php file. This file runs during the application bootstrap process (although this might change in Laravel 5). By binding our service here it will be available to the rest of the application.

After all this buildup, binding a class is relatively anti-climatic. Just add the following line to the end of your app/start/global.php file

#File: app/start/global.php

$app = app();
$app->bind('helloworld', 'Pulsestorm\Example');

That’s it. The first argument to bind is the name you picked for your service. The second is the name of your implementation class (passed as a string).

With the above in place, let’s try calling our service from a route. Change your service-tutorial route so it matches the following.

#File: app/routes.php
Route::get('/service-tutorial', function(){           
    $app = app();
    $app['helloworld']->sayHello();
    echo "<br>";
    $app['helloworld']->sayHello();
});

And then load your route in your browser.

http://laravel.example.com/service-tutorial

If you’ve set things up correctly, you should see the following output

Hello World! We've met 0 times!
Hello World! We've met 0 times!

Success! You’ve just created your first Laravel service.

Shared Services

Let’s take another look at our output from above

Hello World! We've met 0 times!
Hello World! We've met 0 times!

You may have noticed one difference from before — the We've met n times string didn’t increment. It echoed zero both times. That’s because whenever you ask the service container for this service ($object = $app['helloworld']), Laravel will instantiate a new object for you. This makes sense as the default behavior, as it discourages developers for using services to store application state.

Sometimes though, as a service developer, you don’t want to instantiate a new object. The database service we used earlier is a classic example of this. If we instantiated a new database service every time we asked the application for a service, that would mean a new database connection would be instantiated every time we ran a query. A page with ten queries would try to connect to the database 10 times, and with a database connection being such an expensive operation, you’d quickly hit scaling or performance problems.

Fortunately, Laravel has the concept of “shared” services. If a service is a shared service, it means Laravel will always return the same instance whenever you ask for the service. In some object systems this concept is called a singleton.

If you didn’t follow that, an example should clear it up. To tell Laravel you want your service to be a shared service, you simply pass in a third parameter at bind time. Change your application binding so it looks like the following.

#File: app/start/global.php

$app = app();
$app->bind('helloworld', 'Pulsestorm\Example', true);

See that third parameter? The boolean true? If you look at bind’s method prototype

#File: vendor/laravel/framework/src/Illuminate/Container/Container.php
public function bind($abstract, $concrete = null, $shared = false)
{       
    //...
}

You can see the third parameter is named $shared. This parameter tells bind we want a shared service.

With the above parameter added to the bind method call, try reloading your page. You should see the following

Hello World! We've met 0 times!
Hello World! We've met 1 times!

As you can see, the service is keeping track of state between requests, and correctly incrementing the “times met” property.

Important: Having our hello world service track state like this would be a bad implementation of service oriented architecture — in general the only state a service should track is state it needs to do its job, not state to implement application functionality.

There’s no hard and fast rules as to when you should use a shared service. The services Laravel itself ships with are a combination of shared and unshared. You’ll need to use your best judgment when creating your own service. If you need an algorithmic methodology, stick to not using shared services until you start noticing performance problems with your service. Then, consider a shared service to solve your performance problems.

Binding Closures

If we take another look at our bind call

#File: app/start/global.php
$app = app();
$app->bind('helloworld', 'Pulsestorm\Example', true);

Another, more subtle, problem pops out. Because we’re passing our class name in as a string, there’s no chance for us to do any initialization of our service object. Fortunately, Laravel has a solution for this. In addition to accepting a string, the bind method also accepts a PHP anonymous function as an argument. Try replacing your binding code with the following.

#File: app/start/global.php
$callback = function(){
    $implementation = new Pulsestorm\Example;
    $implementation->message = 'Hello world, we meet again (time number %d)';
    return $implementation;
};

$app = app();
$app->bind('helloworld', $callback);

If you reload your page you should see the following text.

Hello world, we meet again (time number 0)
Hello world, we meet again (time number 0)    

That is, we’ve successfully bound a service with an anonymous function. Here’s how the above code works. First, and most importantly, we define an anonymous function

#File: app/start/global.php
$callback = function(){
    $implementation = new Pulsestorm\Example;
    $implementation->message = 'Hello world, we meet again (time number %d)';
    return $implementation;
};

This function should return an instance of our service implementation. Since we’re instantiating the object ourselves, this gives us a chance to perform a number of initializations steps. (i.e. setting the messages property).

Once we’ve created this anonymous function, we pass it into bind

#File: app/start/global.php
$app = app();
$app->bind('helloworld', $callback);

Once we’ve done this, the next time we request the helloworld service, Laravel will invoke/call the anonymous function — whatever the anonymous function returns is what our request for a service will return.

Shared Service Bindings with Closures

In our example above we omitted the third parameter from bind. This meant our service was an un-shared service, and returned new objects each time we requested a service from the application object. Services created with anonymous functions are eligible to be marked as shared, same as any other service. If we wanted a shared service, providing the third method parameter would work

#File: app/start/global.php
$app->bind('helloworld', $callback, true);

However, if you’re binding anonymous functions as services, you have another option for creating a shared service, and that’s the bindShared method. Replace your binding code with the following

#File: app/start/global.php
$callback = function(){
    $implementation = new Pulsestorm\Example;
    $implementation->message = 'Hello world, we meet again (time number %d)';
    return $implementation;
};

$app = app();
$app->bindShared('helloworld', $callback);

All we’ve done here is changed the call to the $app->bind method into a call to the $app->bindShared method. Reload with the above in place, and we’ve got our shared/singleton behavior back

Hello world, we meet again (time number 0)
Hello world, we meet again (time number 1)    

The bindShared method is the preferred way of assigning a shared service to the container, and the Laravel core code uses it extensively. As a quick example, take a look at this service provider code where Laravel binds the database service

#File: vendor/laravel/framework/src/Illuminate/Database/DatabaseServiceProvider.php
//...
    $this->app->bindShared('db', function($app)
    {
        return new DatabaseManager($app, $app['db.factory']);
    });    
//...

Here the Laravel core users bindShare to bind a DatabaseManager object as the db service.

Non-Object Services

There’s one curious side effect to Laravel’s anonymous function service providers. Consider a service bound like this

#File: app/global/start.php
$app->bindShared('curious', function(){
    return 'Curious Service is Curious';
});    

and used like this

#File: app/routes.php
Route::get('/service-tutorial', function(){           
    $app = app();
    $curious = $app['curious'];

    var_dump($curious);
});

The above code will output the text

string 'Curious Service is Curious' (length=26)

That is, despite us requesting a service object, the service container returns a string. It’d be easy to write this “string service” off as an unintended side effect of Laravel’s anonymous function implementation, but the core application code itself relies on this behavior. Give the following a try

#File: app/routes.php
Route::get('/service-tutorial', function(){           
    $app = app();
    var_dump($app['env']);
});

Loading the tutorial route in a browser with the above code results in output something like the following

string 'local' (length=5)

Your system may output the text production, or development, or something else. This env service is how Laravel keeps track of the current environment, and knows which configuration files to load. It’s also why the resolving listener in our last article received a string instead of an object.

The takeaway here is that despite being billed as a service object container, Laravel’s service container will sometimes return a scaler value (boolean, string, int, etc). In other words, you can’t assume it will always return an object. You’ll want to be defensive in your resolvingCallbacks, or anywhere you’re not familiar with the behavior of a particular service.

Laravel Services, make, and ArrayAccess

There’s one last thing we’ll want to cover about services before we finish up for today. In the first article of this series, we covered using the application object’s make factory to create objects. What we didn’t mention in that tutorial was that make, in addition to accepting class names, also accepts service names.

Assuming you’ve bound a service to helloworld, give the following a try.

#File: app/routes.php
Route::get('/service-tutorial', function(){           
    $app = app();
    $app->make('helloworld')->sayHello();
    echo "<br>\n";
    $app->make('helloworld')->sayHello();
});

This will produce the exact same results as asking the application container for the service

Hello world, we meet again (time number 0)
Hello world, we meet again (time number 1)

The call to make also obeys any shared binding. Put another way, you can use make to create a Laravel object from a PHP class, or from a service container alias.

This is more than side effect behavior. So far we’ve accessed services via the app container’s ArrayAccess syntax.

$app['helloworld'];

When you try to get a value from an object with array syntax, PHP calls the object’s offsetGet method. If we take a look at the Container class’s offsetGet method (the Application class extends from the Container class), we see the following.

#File: vendor/laravel/framework/src/Illuminate/Container/Container.php    
public function offsetGet($key)
{
    return $this->make($key);
}

If it’s not immediately obvious to you — what the code above means is whenever we’ve called $app['helloworld'], behind the scenes Laravel’s just called $app->make('helloworld');
While interesting to systems developers, this creates a lot of confusion as to what “the right” way to access a Laravel service is, or how a service package developer should tell their users to access the service. We’ll cover this, and more, in our next article, when we talk about (cue nerd fight) Laravel Facades.

Originally published September 21, 2014

PHP ArrayAccess

This week’s a quick remedial primer on PHP’s ArrayAccess interface. We’ll be back to Laravel next time, and promise you’ll see why we needed the primer.

First, some background and context. PHP has a native language type called an array. This isn’t a C array, where each element points to a specific memory location. Instead, a PHP array is an implementation of an ordered map. You can add any variable to an array. If you want to treat an array as an ordered list, you can add items with the following syntax

$array = [];
$array[]  = 'abc';
$array[]  = 123;
$array[2] = 'science';    

You can also treat an array as a hash-map/dictionary

$array = [];
$array['foo'] = 'bar';
$array['baz'] = 42;    

PHP also has a native language type called an object. To create an object, a user programmer must first define a class with the class keyword

class Foo
{
}

and then use the new keyword to create an object from the class

$object = new Foo;

PHP also includes a built in class called stdClass. A user programmer can use this class to create stand-alone objects without defining a class.

$object = new stdClass;

Finally, more modern versions of php include a shortcut for creating stdClass objects

$object = {};

Array vs. Object

Objects and arrays are different things in PHP, although they share some functionality. You can use an array as a dictionary like data structure

$array = [];
$array['foo'] = 'bar';
$array['baz-bar'] = 'science';

echo $array['foo'];

You can also use an object as a dictionary like data structure

$object = {};
$object->foo = 'bar';
$object->{'baz-bar'} = 'science'

echo $object->foo;

The only difference is the syntax. Arrays use the bracket characters [], while objects use the “arrow” operator (->). If you try to use array brackets to access the values on on object, PHP will issue a fatal error

Fatal error: Cannot use object of type stdClass as array …

So far, most of this is common knowledge to working PHP programmers. What’s less commonly known is PHP allows end-user-programmers to define what should happen when a programmer tries to access object properties with array syntax. Put another way, you can give your objects the ability to work with array brackets ($o[])

Array Access

PHP ships with a number of built in classes and interfaces. These classes and interfaces allow a PHP developer to add features to the language that would normally be reserved for a PHP core developer. The one we’re interested in today is ArrayAccess.

If you want to give your object the ability to act like an array, all you need to do is implement the built-in ArrayAccess interface. Give the following simple program a try

<?php
class Foo implements ArrayAccess
{
}

$object = new Foo;
$object['foo'] = 'bar';        

echo $object['foo'],"\n";

In our class declaration statement we’ve included implements ArrayAccess. If we run this program, we’ll see the following error.

PHP Fatal error: Class Foo contains 4 abstract methods and must therefore be declared abstract or implement the remaining methods (ArrayAccess::offsetExists, ArrayAccess::offsetGet, ArrayAccess::offsetSet, …) in

Simply implementing an interface isn’t enough — we actually need to write the methods that are part of the interface synopsis. For a user defined interface, this would mean looking at the interface definition — for a built-in interface, we need to rely on the PHP manual. If you look at the manual, you’ll see the interface is defined as

ArrayAccess {
    /* Methods */
    abstract public boolean offsetExists ( mixed $offset )
    abstract public mixed offsetGet ( mixed $offset )
    abstract public void offsetSet ( mixed $offset , mixed $value )
    abstract public void offsetUnset ( mixed $offset )
}

That is, we need to define the 4 methods ArrayAccess::offsetExists, ArrayAccess::offsetGet, ArrayAccess::offsetSet, ArrayAccess::offsetUnset. Unfortunately, the help stops there. Interfaces are great for telling you what method you need to define, but less great at telling you what each method is supposed to do.

Let’s do a little detective work. Create the following short program, and then run it (either in your browser or via the command line)

<?php
class Foo implements ArrayAccess
{
    public function offsetExists ($offset)
    {
        echo __METHOD__, "\n";
    }

    public function offsetGet ($offset)
    {
        echo __METHOD__, "\n";    
    }

    public function offsetSet ($offset, $value)
    {
        echo __METHOD__, "\n";    
    }

    public function offsetUnset ($offset)
    {
        echo __METHOD__, "\n";
    }

}

$object = new Foo;
$object['foo'] = 'bar';

This program defines the class Foo and implements each of the ArrayAccess interface’s abstract methods. Then, it instantiates a Foo object, and tries to set an array property. We’ve also programed each method to output its name whenever the program calls the method.

If you run the above program, you’ll see output something like this

Foo::offsetSet

Now try getting a property.

$object = new Foo;
$object['foo'] = 'bar';
$bar = $object['foo'];

echo "The value we fetched: " . $bar,"\n";

The above will output something like the following

Foo::offsetSet
Foo::offsetGet
The value we fetched: 

What did this teach us? When we tried to set a value via array access ($object['foo'] = 'bar';), behind the scenes PHP called our class’s offsetSet method. When we tried to get a value via array access ($bar = $object['foo'];), behind the scenes PHP called offsetGet. However, no value was actually set or gotten from the object (The value we fetched:).

That’s how the PHP ArrayAccess interface works. It has some behind the scenes magic that will call a method on your class when you perform an array operation on your object, but it’s still up to you to implement that access. If you try something like this

<?php
class Foo implements ArrayAccess
{
    protected $_data=array();
    public function offsetExists ($offset)
    {
        return array_key_exists($offset, $this->_data);
    }

    public function offsetGet ($offset)
    {
        return $this->_data[$offset];
    }

    public function offsetSet ($offset, $value)
    {
        $this->_data[$offset] = $value;
    }

    public function offsetUnset ($offset)
    {
        unset($this->_data[$offset]);
    }

}

$object = new Foo;
$object['foo'] = 'bar';
$bar = $object['foo'];

echo "The value we fetched: " . $bar,"\n";

You’ll have much better results.

The value we fetched: bar

While you initial reaction may be annoyance — “Why doesn’t PHP just implement this for me” — by giving you the responsibility of implementing your own ArrayAccess rules, the PHP core developers have given you (or the framework developers you rely on) tremendous power to create new behavior for your own objects.

Originally published September 15, 2014

Laravel Objects

Like this article? Frustrated by Magento? Then you’ll love Commerce Bug, the must have debugging extension for anyone using Magento. Whether you’re just starting out or you’re a seasoned pro, Commerce Bug will save you and your team hours everyday. Grab a copy and start working with Magento instead of against it.

Laravel is already a well documented system. The quick-start guide guide has all the information a developer needs to start building applications with Laravel. What’s less well documented, and more interesting to me, is documentation of Laravel’s implementation. The PHP community has a pretty good handle on how to use MVC systems, but less attention is paid to the code that makes these systems run.

Today we’re going to cover the basics of Laravel’s global application object, and how to instantiate “Laravel objects” like an internals developer. A lot of this code will end up being the sort of thing you’d never write day-to-day with Laravel, but understanding the internals will help you debug core system code, understand module implementations, and be a better overall PHP developer ready to handle whatever system eventually replaces Laravel.

Getting Started

The first thing we’ll want to do is create a simple route where we’ll put our code. Open up app/routes.php and add the following to the bottom of the file.

#File app/routes.php
Route::get('tutorial', function(){        
    return '<p>Done</p>';
});

Next, load the following URL in your browser.

http://laravel.example.com/tutorial

You should see the text Done. Next, replace your code with the following.

#File app/routes.php
Route::get('tutorial', function(){        
    $app = app();
    var_dump(get_class($app));
});

If you reload the page, you should see the following text

string 'Illuminate\Foundation\Application' (length=33)

The global app() function returns the Laravel application object. There are other ways to access the Application object, but for now we’re going to keep things simple and use the app() function.

For the remainder of this article we’ll put all our code in this tutorial route.

Laravel Objects

A Laravel object is just a PHP object, but a PHP object that’s been instantiated via the Application object’s make method. You could also call the make method the make factory, or the make factory method.

If you’re more a learn by doing person, consider the following. In plain old PHP, you can instantiate a simple object with code like this

#File: app/routes.php
Route::get('tutorial', function(){       
    $object = new stdClass;
    $object->foo = 'bar';

    var_dump($object);    
});

In Laravel, you instantiate an object with code that’s slightly different.

#File: app/routes.php
Route::get('tutorial', function(){       
    $app = app();
    $laravel_object = $app->make('stdClass');
    $laravel_object->foo = 'bar';
    var_dump($laravel_object);        
});

That is, you call the Illuminate\Foundation\Application object’s make method, and pass in the name of the class. In both cases, the above code will output something like this

object(stdClass)[34]
  public 'foo' => string 'bar' (length=3)

You may be thinking something like

Why bother with the Laravel make method if the results are the same?

We’ll cover that more below — this is one of those catch 22’s in programming where it’s necessary to get a little experience using the system before you can understand why you’d want to use the system.

The make method will work with any PHP class. For example, if you create a simple Laravel model class with the following contents in app/models/Hello.php

#File: app/models/Hello.php
<?php
class Hello
{
}

You can instantiate it via PHP with the following

#File: app/routes.php
Route::get('tutorial', function(){       
    $object = new Hello;
    var_dump($object);        
});

To create a Laravel object using the Hello class, you’d do the following.

#File: app/routes.php
Route::get('tutorial', function(){       
    $app = app();
    $hello = $app->make('Hello');
    var_dump($hello);        
});

Here we’ve used make to instantiate the class Hello. This will work with any PHP class that Laravel can autoload. For example, if we wanted to instantiate the Illuminate/Hashing/BcryptHasher class, we’d do it like this

#File: app/routes.php
Route::get('tutorial', function(){     
    $app = app();    
    $bcrypt = $app->make('Illuminate\Hashing\BcryptHasher');
    var_dump($bcrypt);
});

An important warning here — make does not inherit the scope of the PHP file where you call make — you’ll need to use the full namespace path.

The make factory also supports constructor parameters. For example, consider the following Hello class

#File: app/models/Hello.php
<?php
class Hello
{
    public function __construct($one='default1', $two='default2')
    {
        echo "First  Param: $one","\n<br>\n";
        echo "Second Param: $two","\n<br>\n";
        echo "\n<br>\n";
    }
}

Here we’ve added a __construct method to our Hello class. If you’re super new to PHP, PHP calls a class’s __construct method whenever you instantiate an object. If we ran the following code,

#File: app/routes.php
Route::get('tutorial', function(){       
    $o = new Hello;

    $o = new Hello('changed1','changed1');
});

We’ll get output something like this

First Param: default1 
Second Param: default2 

First Param: changed1 
Second Param: changed1 

That is, instantiating the object without parameters results in the class using the default values for the constructor parameters. If we use parameters when instantiating our object, the class uses the parameters.

So, now consider the same scenario with make. The following code

#File: app/routes.php
Route::get('tutorial', function(){       
    $app = app();
    $app->make('Hello');        
});

will output

First Param: default1 
Second Param: default2 

So that’s the default values used — but how do we tell Laravel we want to use constructor parameters? It’s not obvious, but it’s easy to remember once you’ve learned it — just use make’s second parameter. The following

#File: app/routes.php
Route::get('tutorial', function(){       
    $app = app();
    $app->make('Hello', array('laravel1','laravel2'));
});

will output

First Param: laravel1 
Second Param: laravel2 

That is, Laravel’s second argument accepts an array of parameters to pass to the constructor. Since Laravel is PHP 5.4+ only, we could also write that as

$app->make('Hello', ['laravel1','laravel2']);

Here we’re using the new-in-5.4 [] language construct to create an array. The [] syntax may seem like a small thing, but it’s a good tool for improving the readability of code that uses a lot of arrays.

Why use Laravel Objects?

So that’s the basics of Laravel object instantiation. The question that’s sure to be bouncing around the back of your head is — “Why replace PHP’s new keyword with a factory method if the objects are the same”?

The benefit of using a factory method to instantiate an object is that you give yourself the ability to monitor, control, and change how objects are instantiated in your PHP system. The behavior of PHP’s objects are hardwired into the language. You create an object, the constructor’s called, etc. There’s no chance to change how any of that works.

If you’re a low level C/C++ programmer you could probably write a PHP module to change the behavior of PHP’s object instantiation, but that’s a order of magnitude more work to get right, and low level C/C++ wizards are hard to come by.

By creating a system to replace PHP’s instantiating of objects, the Laravel systems programmers have given themselves the ability to change the behavior of object instantiation, and give their objects super powers. The only caveat is they need to convince you, the PHP client programmer, to use their factory pattern to instantiate objects.

We’ll talk more about that convincing in a future article, but you’re probably more interested in the super powers we mentioned. What sort of super powers do Laravel objects have? Many of them are related to the Application object’s “container and binding” features, which we’ll also cover in a future article. There are, however, a few super powers we can talk about today.

Class Aliasing

Laravel’s implemented a class aliasing feature for their objects. Other names for this functionality include duck-typing, monkey patching, or inversion of control. If you’re a Magento programmer, you’re used to calling it class rewrites. If you’re a Drupal developer the concept is “Pluggable”.

Regardless of what you call it, Laravel allows you to swap out class definitions at runtime. For example, consider the following code from earlier.

#File: app/models/Hello.php
<?php
class Hello
{
}

#File: app/routes.php
Route::get('tutorial', function(){       
    $app = app();
    $hello = $app->make('Hello');
    var_dump($hello);        
});

Here we instantiated an object Hello. Let’s say we want to replace Hello with a new object, Welcome. First we’ll need to create our new class. To do so, add the following code to the app/models/Welcome.php file.

#File: app/models/Welcome.php
<?php
class Welcome extends Hello
{
}    

Here we’ve defined a new class Welcome, and had it extend our original class Hello. This means Welcome will behave exactly the same as Hello. Then, at the end of Laravel’s app/start/global.php file, add the following code. (If you’re not familiar with global.php, read up on the Laravel request lifecycle)

#File: app/start/global.php
$app = app();
$alias = $app->alias('Welcome', 'Hello');

Here we’ve used the Application object’s alias method to tell Laravel whenever it instantiates a Hello object, it should use the Welcome class. Try running the following code

#File: app/routes.php
Route::get('tutorial', function(){       
    $app = app();
    $hello = $app->make('Hello');
    var_dump($hello);        
});

And you’ll see PHP will dump a Welcome object instead of a Hello object.

object(Welcome)[141]

Once an alias is setup, we can start adding new methods to the Welcome class, extending the system’s functionality without needing to replace the original Hello class. This is a powerful feature, and if you’ve ever tried setting up a class rewrite in a system like Magento, you can see the immediate advantage of Laravel’s simpler syntax.

Instantiation Events

Another advantage of using make is the Application object’s instantiation events, or as Laravel calls them — “resolving callbacks”. That is, a PHP callback which fires whenever an object is made. (i.e. when resolving the object)

Try adding the following to the end of you app/start/global.php file

#File: app/start/global.php
$app = app();
$app->resolving('Welcome', function($object, $app){
    echo "I just instantiated a " . get_class($object) . "\n<br>\n";
});

and then reload the page from above. You should see the following content in your browser.

I just instantiated a Welcome

What we did here was tell Laravel that anytime a Welcome object is instantiated, we should call the anonymous function passed in as the second argument to resolving

function($object, $app){
    echo "I just instantiated a " . get_class($object) . "\n<br>\n";
}

Laravel makes heavy use f anonymous functions as callbacks. If you’re not familiar with anonymous functions in programming, this old Joel on Software article is still the best primer I’ve seen on the subject.

Using the resolving feature, we can track when Laravel instantiates certain objects, and also change the object that’s passed into the callback. This powerful feature enables to you do anything you’d like to all objects of a certain type without needing to modify a single line of existing code.

The application also has a “global” resolving callback. This allows you to specify a callback/anonymous function for Laravel to call whenever it makes an object. If you want to give it a try, replace the above code in app/start/global.php with the following

#File: app/start/global.php
$app = app();
$app->resolvingAny(function($object, $application){
    //we'll explain this conditional in a minute. 
    if(!is_object($object))
    {
        return;
    }
    echo "I just instantiated a " . get_class($object) . " object \n<br>\n";
});

Reload your page, and you should see something like the following.

I just instantiated a Illuminate\Routing\Router object 
I just instantiated a Welcome object 

Laravel called the resolvingAny callback/listener you specified when it instantiated a Illuminate\Routing\Router object, as well as our Welcome object. If we had set this callback up earlier in the bootstrap process we would have seen more of Laravel’s internal objects. Laravel will send anything created through make to the resolvingAny callback.

This brings us to our final point for today. You’re probably wondering about that conditional guard clause.

if(!is_object($object))
{
    return;
}

Let’s replace that the with some more debugging code

#File: app/start/global.php
$app = app();
$app->resolvingAny(function($object, $application){
    //we'll explain this conditional in a minute. 
    if(!is_object($object))
    {
        echo "What's inside \$object: [" , $object, "]\n<br>\n";
    }
});

If you reload with the above in place, you’ll see something like the following

What's inside $object: [local] 

For some reason the resolvingAny method has intercepted something that’s not an object. Instead of an object, the parameter contains the string local. Why has a method meant to listen for instantiated objects received a string?

That’s a larger question we’ll start answering next time. Today we’ve concentrated on the object instantiating features of the Application object, but that’s only one small part of the Application object’s responsibilities in Laravel. Next time we’ll cover the Application object’s container features, what binding objects into the container means, and why a method meant for objects might sometimes receive a string.

Originally published September 10, 2014