Resolving an instance out of the container: $container = app(); $logger = $container->make(Illuminate\Log\Writer::class); // or $logger = app()->make(Illuminate\Log\Writer::class); drop instance.. Or even shorter... :
class MyClass { public function doThing() { echo 'abc'; } } $instance = app(MyClass::class); $instance->doThing(); At this point not actually providing any value. But...
class MyClass { protected $otherThing; public function __construct(OtherThing $otherThing) { $this->otherThing = $otherThing; } } $instance = new MyClass;
class MyClass { protected $otherThing; public function __construct(OtherThing $otherThing) { $this->otherThing = $otherThing; } } $instance = new MyClass(new OtherThing);
AUTOWIRING A framework/package's ability to instantiate a class without being given explicit instructions from the user of how to instantiate that class. If a class has dependencies, an autowiring framework will use reflection to determine and provide its dependencies.
namespace Illuminate\Foundation; class Application { public function make($key) { $dependencies = $this->getConstructorDependenciesFor($key); return new $key(... $dependencies); } } It now uses reflection to figure out the constructor dependencies.
BIND // Binding a class to the container app()->bind(MyService::class, function () { return new MyService('0h5oh1kn09da'); }); // Now, we can use it: $service = app(MyService::class);
USING $app WITHIN A BINDING CLOSURE class MyService { public function __construct(Thing $thing, Other $other, $apiKey) { ... } } app()->bind(MyService::class, function ($app) { return new MyService( $app->make(Thing::class), $app->make(Other::class), 'api1o2n34' ); });
ALIAS FREEDOM We can really bind to any arbitrary string. Therefore interfaces are bindable too. app()->alias( PostmarkMailer::class, Mailer::class // Interface ); app()->alias( MagicService::class, 'my-favorite-interface-thing-or-whatever' // silly string );
LARAVEL'S SHORT ALIASES (CONTINUED) Each alias is pointing to a real class instantiated to a shortcut. // Illuminate/Foundation/Application public function registerCoreContainerAliases() { $aliases = [ 'app' => [ \Illuminate\Foundation\Application::class, \Illuminate\Contracts\Container\Container::class, \Illuminate\Contracts\Foundation\Application::class ], // ... ]; }
COMMON USES of AUTOMATIC DEPENDENCY INJECTION ▸ Requesting classes from the framework (like Request, Logger, Mailer) in controllers and other user-facing code ▸ Route model binding ▸ Form Requests ▸ Relying on constructor injection more confidently in custom classes
REQUESTING CLASSES FROM THE FRAMEWORK (LIKE REQUEST, LOGGER, MAILER) IN CONTROLLERS AND OTHER USER-FACING CODE // PostsController public function store(Request $request) { $this->validate($request, [ ... ]); Post::create($request->only(['title', 'body'])); return back(); }
FORM REQUESTS // PostsController public function update(UpdatePost $request) { // do stuff } // UpdatePost public function rules() { return [ 'title' => 'required|unique:posts|max:255', 'body' => 'required', ]; }
RELYING ON CONSTRUCTOR INJECTION MORE CONFIDENTLY IN CUSTOM CLASSES namespace Symposium\JoindIn; // ... imports class Client { // ... class properties public function __construct(Client $guzzle, Logger $logger, Cache $cache) { // ... assign as class properties } }
SERVICE PROVIDERS: WHAT ARE THEY? Central location to bind services for use by your application's code, usually grouped by functionality; the place where all of Laravel's bootstrapping takes place.
THE ANATOMY OF A SERVICE PROVIDER ▸ register: binding into the container ▸ boot: called after all registrations are complete; everything else here (registering event listeners, routes, or any other functionality) ▸ defer?: can we avoid running this service provider if certain bindings aren't requested? ▸ provides: if deferred, which bindings' requests should trigger running this service provider?
WHAT DEFINES A FACADE? class Cache extends Facade { protected static function getFacadeAccessor() { return 'cache'; } } Cache::get(); // same as: app('cache')->get();
CREATING YOUR OWN FACADE (CONTINUED) Define the facade class and point it to your bound class name class Twitter extends Facade { protected static function getFacadeAccessor() { return 'twitter'; } }
REAL TIME FACADES Prepend Facades\ to your namespace when you import your class and now use it as a Facade backed by that class. class Thing { public function do() { // ... } } Facades\Thing::do();
TESTING AND THE CONTAINER Dependency injection aids tests; the container aids DI. Swap in a mock or a spy easily. // in code Route::get('whatever', function (MyService $service) { return $service->get('whatever'); }); // in test $mock = Mockery::mock('MyService'); app()->instance('MyService', $mock);
TESTING AND THE CONTAINER (CONTINUED) It works for Facades too: // in code Route::get('whatever', function () { return Twitter::post('here is my status!'); }); // in test $mock = Mockery::mock(MyTwitterClient::class); app()->instance('twitter', $mock);