Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel Difference `between app->bind` and `app->singleton`?

I've been trying to figure out what the difference between app->bind and app->singleton are when setting up a service provider in Laravel. I was under the impression that if I register an singleton it would return the same instance of the object each time it was called vs bind which would be a new instance.

Here is simple example:

Facade:

use Illuminate\Support\Facades\Facade;

class DataFacade extends Facade
{
    protected static function getFacadeAccessor() { 
        return 'Data';
    }
}

ServiceProvider:

use Illuminate\Support\ServiceProvider;

class DataServiceProvider extends ServiceProvider
{
    public function register() {
        $this->app->singleton('Data', function() {
            return new Data;
        });
    }
}

Class:

class Data
{
    public $data = [];

    public function get($key)
    {
        return isset($this->data[$key]) ? $this->data[$key] : null;
    }

    public function set($key, $val)
    {
        $this->data[$key] = $val;
    }
}

If we do something like:

$instance = App::make('Data');
$instance->set('foo', 'foo');

$instance2 = App::make('Data');

echo $instance->get('foo');
echo $instance2->get('foo');

And run that we will see the appropriate behavior between bind and singleton with foo being printed out once and then twice respectively. However if we run it through the facade like so:

Data::set('test', 'test');
Data::set('cheese', 'cheese');

When it's a singleton I would expect both test and cheese to be available and when it's a bind I'm not sure what I would expect to be available via the facade, but it seems like there is no difference.

It's the facade treating everything as a singleton?

like image 985
Rob Avatar asked Sep 11 '14 21:09

Rob


People also ask

Does Laravel use singleton?

The database layer of Laravel is also implemented using singletons. This means that there is only one database connection per request. This helps to keep the database layer of the application clean and easy to use.

What is binding in Laravel?

If we take a look at the Laravel documentation, binds are registered using the bind() method. The first argument passed in is a class name, followed by a closure that returns an instantiated instance of that class object.

What is Laravel Service container?

The Laravel service container is a powerful tool for managing class dependencies and performing dependency injection. Dependency injection is a fancy phrase that essentially means this: class dependencies are "injected" into the class via the constructor or, in some cases, "setter" methods.

When and why to use bind and Singleton in Laravel?

In this tutorial we will try to know that when and why we use bind and singleton in our Laravel app. Use bind for reusable classes or objects - the object is constructed each time it is called. If you need multiple instances of a class, in this situation use bind.

What is the difference between bind and Singleton in Java?

Use bind for reusable classes or objects - the object is constructed each time it is called. If you need multiple instances of a class, in this situation use bind. Use singleton for a class or object that you need access to throughout the application - the object is only constructed once and so retains state throughout execution.

How do you register a bind in Laravel?

If we take a look at the Laravel documentation, binds are registered using the bind () method. The first argument passed in is a class name, followed by a closure that returns an instantiated instance of that class object.

What does make () do in Laravel?

When you say App::make('Data')you're telling Laravel to instantiate an object from the class Data. There's a caveat to number 1. If you call makeand have already bound the string Datato something in the service container, Laravel will return the service instead.


1 Answers

Your question is a little confusing and doesn't have all the information for someone to answer, but it's a confusing topic, so don't feel bad. Here's a rundown that may help you better understand, and ask the question you wanted to ask (also, I'm newish to Laravel, so I may be off base with these)

  1. The make method is used to instantiate objects. When you say App::make('Data') you're telling Laravel to instantiate an object from the class Data.

  2. There's a caveat to number 1. If you call make and have already bound the string Data to something in the service container, Laravel will return the service instead. This may mean Laravel instantiates a new service object, or it may mean Laravel returns a service singleton

  3. Whether or not Laravel returns a singleton or an instance for a service depends on how the service was bound

  4. The make method doesn't bind anything

  5. You bind services with the application object's bind method, defined on the container class with the following method prototype public function bind($abstract, $concrete = null, $shared = false)

  6. See that third $shared parameter? If that's true your service will return a singleton. If it's false your service will return instances.

  7. The application object's singleton method is a method for binding services

Re: #7, here's the definition of singleton

#File: vendor/laravel/framework/src/Illuminate/Container/Container.php
public function singleton($abstract, $concrete = null)
{
    $this->bind($abstract, $concrete, true);
}

In your examples above you're binding the service Data into the container. Using a leading case service name is going to cause problems -- data would be a better choice. If your register method isn't called for some reason, make will still instantiate an object with your global class Data

Regarding your Facade -- a Facade is an extra layer of instance/singleton-ness. Here's the method where the facade class uses the string from getFacadeAccessor to return an object from a static call

#File: vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php
protected static function resolveFacadeInstance($name)
{
    if (is_object($name)) return $name;

    if (isset(static::$resolvedInstance[$name]))
    {
        return static::$resolvedInstance[$name];
    }

    return static::$resolvedInstance[$name] = static::$app[$name];
}

So, a facade uses $app[$name]; to grab a service from the container. This is ArrayAccess, so if we look at the definition of offsetGet

public function offsetGet($key)
{
    return $this->make($key);
}

We see ArrayAccess wraps a call to make. This means if you have no bound service, facade access will instantiate an object. If you have the service bound as a singleton/shared service, facade access will return that singleton. If you have the service bound as not a singleton/shared service, facade access will instantiate a new object.

HOWEVER, the Facade itself will store any object it instantiates inside static::$resolvedInstance, and future calls to the facade will return this same instance. This means Facade access introduces a second singleton implementation. A service bound as a singleton will be stored on the application object, a service accessed via a facade will be stored as a singleton on the Facade class.

like image 118
Alan Storm Avatar answered Oct 23 '22 15:10

Alan Storm