Reading about laravel bindings,I understand $this->app->bind,$this->app->singleton and $this->app->instance because they are almost the same.
But $this->app->when is a little bit tricky for me.
In laravel example
$this->app->when('App\Http\Controllers\UserController')
->needs('$variableName')
->give($value);
In my understanding it injects some primitive value and the App\Http\Controllers\UserController is the alias of the object that will be binded.But where is the object?
Can anyone explain? Thank you for your help.
Contextual binding does not work on variable names, but on types. It is used to provide different implementations for interfaces to consuming classes or functions, depending on the context. In fact, you can actually read the method calls and it does exactly what you'd expect. To elaborate on this, I'll take the example of the documentation and adapt it slightly:
$this->app->when(Worker::class)
->needs(Money::class)
->give(function () {
return new Dollar();
});
$this->app->when(Boss::class)
->needs(Money::class)
->give(function () {
return new Cheque();
});
In this example, Money is an interface and Dollar as well as Cheque are implementations of the interface. The example literally means that if you typehint Money on a Worker class, it will resolve to an instance of Dollar while it will resolve to Cheque on a Boss class. To illustrate, here the implementations and the results:
interface Money
{
public function getAmount();
}
class Dollar implements Money
{
public function getAmount()
{
return 1;
}
}
class Cheque implements Money
{
public function getAmount()
{
return 100000;
}
}
And now we typehint the Money interface to see what we'll get:
class Worker
{
public function __construct(Money $money)
{
echo $money->getAmount(); // prints '1'
}
}
class Boss
{
public function __construct(Money $money)
{
echo $money->getAmount(); // prints '100000'
}
}
It means that if a class of UserController is instantiated and it needs a variable with the name $variableName Larvel will automatically resolve this variable with the given value and you don't have to provide it.
For example:
$value = "Sven"
$this->app->when('App\Http\Controllers\UserController')
->needs('$userName')
->give($value);
This would insert the value 'Sven' into the UserController whenever it needs the variable with the name $userName
In other words, if you had a function like public function __construct(Request $request) Laravel knows what to insert because it knows that a Request object is expected. When you use a function like public function __construct($name) Laravel has no clue what to insert here, essentially you tell Laravel how to resolve this variable with the bindings.
This is an example of primitive binding, for Contextual binding see the answer of #Namoshek
In case anyone finds this thread, trying to achieve contextual binding on an app()->make() or similar situation:
use Closure;
use Illuminate\Container\Container;
class FooBar {
public function doSomething(): void
{
//...do your thing
$this->getFooObject();
}
private function getFooObject(): FooAbstract
{
$class = FooAbstract::class;
$buildStack = static::class;
app()->beforeResolving(
$class,
Closure::bind(
function () use ($buildStack) {
$this->buildStack[] = $buildStack;
},
app(),
Container::class,
)
);
return app($class);
}
}
In the above example laravel's app container is bind as $this to this closure. Since the buildStack property, that's used to identify the object that "needs" the object that is being created, is protected, we have access to it, and we can add the classname to the stack.
for example: if $buildStack = Bar::class; you can do the following
app()->when(FooBar::class)->needs(FooAbstract::class)->give(FooImplementation::class);
Related
I need to know what is the purpose of using service container's tagging and how to use it by example this is what I have tried so far.
class MemoryReport
{
}
class SpeedReport
{
}
class ReportAggregator
{
public function __construct(MemoryReport $memory, SpeedReport $speed)
{
}
}
App::bind('MemoryReport', function () {
return new MemoryReport;
});
App::bind('SpeedReport', function () {
return new SpeedReport;
});
App::tag(['MemoryReport', 'SpeedReport'], 'reports');
App::bind('ReportAggregator', function ($app) {
return new ReportAggregator($app->tagged('reports'));
});
$reportAggregator = resolve('ReportAggregator');
dd($reportAggregator);
This is the error I get.
Argument 1 passed to ReportAggregator::__construct() must be an
instance of MemoryReport, instance of
Illuminate\Container\RewindableGenerator given, called in
/media/mazzam/9068A9DC68A9C0F81/M.azzam/Learning/laravel/00
Tutorial/tut/routes/web.php on line 80
According to the documentation, tagging is used to resolve a certain "category" of binding.
I will explain what does this means by showing you some code from one of our projects.
We use several OCR systems to scan the uploaded documents:
App\Support\OCR\GoogleVision
App\Support\OCR\AmazonTextract
App\Support\OCR\Tesseract
...
All these classes implement the App\Contracts\OCR interface:
interface OCR
{
public function scan(File $file): ScannedFile;
}
We grouped all the OCR(s) into a tag named ocrs:
// AppServiceProvider -> register method
$this->app->tag([GoogleVision::class, AmazonTextract::class, Tesseract::class], 'ocrs');
Then we inject the ocrs tag into the Scan object as follows:
$this->app->bind(Scan::class, function() {
return new Scan(...$this->app->tagged('ocrs'));
});
As you might have noticed, we've used the array spread operator ... which spreads the array elements and pass them individually to the Scan object.
Let's see how the Scan class looks like:
namespace App\Support;
class Scan
{
private array $ocrs;
public function __construct(App\Contracts\OCR ...$ocrs)
{
$this->ocrs = $ocrs;
}
public function scan(File $file)
{
foreach ($this->ocrs as $ocr)
{
$scannedFile = $ocr->scan($file);
// ...
}
}
}
The Scan's contractor uses the argument unpacking (variadic) which means that we can pass N number of objects that implementing the App\Contracts\OCR.
You may be wondering, why didn't use type-hinting instead of tagging?
That's because we constantly add/remove OCR systems based on the customer's needs.
So, by using the tags, we are not tied to specific implementations, since we can easily add/remove the classes based on the customer's needs.
I hope, I answered your question.
Tagging allows you to group services under a common name. This is for example useful if you have multiple services implementing the same interface and you need one of the interfaces method to be executed for each of the implementations:
interface Messenger
{
public function sendMessage(string $recipient, string $message): void;
}
class SlackMessenger implements Messenger
{
public function sendMessage(string $recipient, string $message): void
{
app(Slack::class)->send($recipient, $message);
}
}
class TwilioMessenger implements Messenger
{
public function sendMessage(string $recipient, string $message): void
{
app(Twilio::class)->sendSMS($recipient, $message);
}
}
// AppServiceProvider::register()
App::tag([SlackMessenger::class, TwilioMessenger::class], Messenger::class);
// somewhere in your application
$messengers = app()->tagged(Messenger::class);
foreach ($messengers as $messenger) {
$messenger->sendMessage($recipient, $message);
}
Note: This is a fictional test case and the underlying services may be different. You also need to add namespaces and use imports.
In your case, you don't need to bind any of the classes. If their construction is based on other services of the service container, type-hinting is sufficient.
In an application I'm building there's a CLI entry point class:
class CLIEntryPoint {
protected $factory;
public function __construct(ApplicationObjectFactoryInterface $factory) {
$this->factory = $factory;
}
public function run(...$args) {
$choice = $args[1];
$appObject = $this->factory->makeApplicationObject($choice);
$appObject->doApplicationRelatedStuff();
}
}
This entry point is created using Dependency Injection in my "front controller" script and it receives an ApplicationObjectFactoryInterface implementation (actually the current implementation of ApplicationObjectFactoryInterface is injected by the DI container, which in turn reads it from its configuration file, but that's not the point).
The current implementation of ApplicationObjectFactoryInterface also uses DI and depends on other factories which help it building the resulting application object:
class CurrentImplementationOfApplicationObjectFactory implements ApplicationObjectFactoryInterface {
protected $someComponentFactory;
protected $anotherComponentFactory;
public function __construct(SomeComponentFactoryInterface $someComponentFactory, AnotherComponentFactoryInterface $anotherComponentFactory) {
$this->someComponentFactory = $someComponentFactory;
$this->anotherComponentFactory = $anotherComponentFactory;
}
/**
* Interface's method
*
* #return ApplicationObjectInterface
*/
public function makeApplicationObject($choice) {
$component = $this->someComponentFactory->makeSomeComponent();
$anotherComponent = $this->anotherComponent->makeAnotherComponent();
switch ($choice) {
case 1:
return new CurrentImplementationOfApplicationObject1($component, $anotherComponent);
case 2:
return new CurrentImplementationOfApplicationObject2($component, $anotherComponent);
default:
return new DefaultImplementationOfApplicationObject($component, $anotherComponent);
}
}
}
Here CurrentImplementationOfApplicationObject1, CurrentImplementationOfApplicationObject2 and DefaultImplementationOfApplicationObject all implement the ApplicationObjectInterface interface and therefore they all have the doApplicationRelatedStuff method.
I would like to know whether it's good practice or not to write code like I did and if not how can I improve it.
Basically here I am creating a component which depends on other components in order to function properly using a factory which in turn needs inner factories to build the component which implements the ApplicationObjectInterface interface.
Is it considered good practice?
Thanks for the attention, as always!
EDIT: I looked at the article of Steven and tried to refactor CLIEntryPoint. The only problem now seems to be how to pass the $choice parameter to the factory which now is inside of the proxy when the run() method is called. Is this code structure better than the one I posted above? Of course, SomeComponentFactoryInterface and AnotherComponentFactoryInterface should follow the same behaviour (the factory that uses them should not use them directly, but through two proxies which implement, in order, SomeComponentInterface and AnotherComponentInterface). I hope I get it right, anyway, here is the code:
class CLIEntryPoint {
protected $applicationObject;
public function __construct(ApplicationObjectInterface $applicationObject) {
$this->applicationObject = $applicationObject;
}
public function run(...$args) {
$choice = $args[1]; // How do I deal with different choices when I am using a Proxy? I should have different application objects depending on input.
$this->applicationObject->doApplicationRelatedStuff();
}
}
interface ApplicationObjectInterface {
public function doApplicationRelatedStuff();
}
class ApplicationObjectProxy implements ApplicationObjectInterface {
protected $applicationObjectFactory;
protected $applicationObjectImplementation = NULL;
public function __construct(ApplicationObjectFactoryInterface $factory) {
$this->applicationObjectFactory = $factory;
}
public function __call($method, $args) {
// Calling interface's
$implementation = $this->getImplementation();
$methodOfInterfaceToCall = preg_replace('/Proxy$/', '', $method);
return $implementation->{$methodOfInterfaceToCall}(...$args);
}
/**
* Laxy loading method.
*/
protected function getImplementation() {
if (is_null($this->applicationObjectImplementation)) {
$this->applicationObjectImplementation = $this->applicationObjectFactory->makeApplicationObject(); // Choice should go here somehow...
}
return $this->applicationObjectImplementation;
}
public function doApplicationRelatedStuff() {
// This will call the PHP's magic `__call` method, which in turn will forward the call to the application object's
// implementation returned by the factory.
return $this->doApplicationRelatedStuffProxy();
}
}
Actually yes, this is a pattern called the Abstract Factory Pattern. So an example that I used to present it in front of my class during my undergrad:
So if you are building a video game first person shooter, you might want to create three concrete factories like:
FlyingMonsterFactory
SwimmingMonsterFactory
WalkingMonsterFactory.
All these factories would implement an abstract MonsterFactory.
With this, you can have your video game create a level in which you want waves of the same type of monsters, so you can have a randomWaveMonsterGenerator method return a MonsterFactory which might have returned a concrete SwimmingMonsterFactory. So then you will have a wave of SwimmingMonster(s) generated by the SwimmingMonsterFactory.
So answer your description more directly, looking at your code above, you asked the question on choice for Dependency Injection. With Dependency Injection, I believe for this type of pattern, you will have to inject every concrete class before your code even attempts to get the implementation class.
So for example:
Your code above says the run method gives an argument called
choice.
With this choice, you will have to use it as a parameter into a getImplementation method.
All the concrete objects that the getImplementation method that rely upon Dependency
Injection have to be created BEFORE you call the getImplementation method.
But since you don't know which implementation class will be called, I believe you have to inject ALL the implementation classes before hand.
Then you can use the choice variable as a parameter to get the correct implemented factory class.
Hope this helps!
Hello guys I was creating a package and i was trying to implement a dependency injection on my class without success. I followed all the instruction for do it work. I'm getting crazy on it.
When i try to call
Player::team_players(2);
it throw me an error:
Argument 1 passed to Team\Player\Player::__construct() must be an
instance of Team\Player\StatusPlayerInterface, none given, called in
C:\wamp\www\ultima\workbench\team\player\src\Team\Player\PlayerServiceProvider.php
on line 35 and defined
I created my class Player.php
<?php namespace Team\Player;
use Team\Player\Models\User;
use Team\Player\Models\Team;
use Team\Player\Models\Fighter;
use Team\Player\StatusPlayerInterface;
use DB;
class Player {
protected $player;
function __construct(StatusPlayerInterface $player) {
$this->player = $player;
}
public function team_players($team_id) {
return $player->team($team_id);
}
}
StatusPlayerInterface.php
<?php namespace Team\Player;
interface StatusPlayerInterface {
public function team($team_id); // active - retired - injured by team id
}
Active.php
<?php namespace Team\Player;
use Team\Player\Models\User;
use Team\Player\Models\Team;
use Team\Player\Models\Fighter;
/**
*
*/
class Active implements StatusPlayerInterface
{
protected $user;
protected $team;
protected $fighter;
function __construct(User $user,Team $team,Fighter $fighter)
{
$this->user = $user;
$this->team = $team;
$this->fighter = $fighter;
}
public function team($team_id)
{
return $fighters = $this->fighter->with('user')->where('team_id',$team_id)->active()->Confirmed()->get();
}
}
PlayerServiceProvider.php
public function register()
{
$this->app->bind('Team\Player\StatusPlayerInterface','Team\Player\Player'); // bind the interface
$this->app['player'] = $this->app->share(function($app)
{
return new Player; // line 35
});
$this->app->booting(function()
{
$loader = \Illuminate\Foundation\AliasLoader::getInstance();
$loader->alias('Player', 'Team\Player\Facades\Player');
});
}
EDIT:
What i'm trying to do is to follow a principle that Jeffrey Way suggested to follow. It say
Entities should be open for extension but close for modification.
I 2 others classes that implements StatusPlayerInterface and of course change only the query on the function team()
Active // on the example
Retired
Injured
Then i have the main class Player and with the method team_players it should automatically call the function team of the instance called. this method is used for don't do
class Player {
....
function team_player($team_id,$status) {
if (is_a($status) == "Active") {
$fighters = $this->fighter->with('user')->where('team_id',$team_id)->active()->Confirmed()->get();
} elseif(is_a($status) == "Retired") {
$fighters = $this->fighter->with('user')->where('team_id',$team_id)->retired()->Confirmed()->get();
}
// ecc
}
}
but i can throw pass the interface to the constructor and return just the function team of the interface, because the interface is like a contract so it can trust that exist that function. But the problem is that i cannot find a way for pass that interface on the constructor.
Your constructor here is waiting for a $player:
class Player {
...
function __construct(StatusPlayerInterface $player) {
$this->player = $player;
}
}
So your ServiceProvider should be passing one to it in line 35:
return new Player; // line 35
I can see you tried to use IoC to do that for you:
$this->app->bind('Team\Player\StatusPlayerInterface','Team\Player\Player');
But you have two problems,
1) Team\Player\Player doesn't implements Team\Player\StatusPlayerInterface and it must. But Active class does implements, shouldn't you be using it?
2) I'm not sure that the IoC will be effective at this point of the code, would have to ask Taylor Otwell himself.
But this is something you can do:
public function register()
{
$this->app['player'] = $this->app->share(function($app)
{
return new Player(new Team\Player\Player);
//// OR
return new Player(new Team\Player\Active);
});
$this->app->booting(function()
{
$loader = \Illuminate\Foundation\AliasLoader::getInstance();
$loader->alias('Player', 'Team\Player\Facades\Player');
});
}
Your Player class would have to implement the StatusPlayerInterface:
class Player implements StatusPlayerInterface {
}
But I'm not sure if it is supposed to, so, look, those are suggestions, I not aware of what you're doing exactly with your package, so I'm just pointing what I'm seeing is wrong on it, okay?
EDIT
For example, you are constructing your Player class already passing a Player Status, right? But how would you swap different statuses if the constructor, the way you're building, will only receive the one you are passing via your ServiceProvider? In this case the IoC container will not help you, because you should be able to instantiate that same class with 3 differents statuses: active, retired and injured.
You can create a setPlayerStatus() method, to change it in the during a request, of course, but as I hope you can see, before building the whole package, you have first to think a lot about your architecture and then write your code based on it, always remembering that the IoC container has its boundaries and there are some resolutions it will not solve, just because they are problems on your architecture.
EDIT 2
You don't really pass an interface to a constructor. You pass a concrete object of a concrete class that implemented that interface.
Look at the error again, it says 3 important things
Argument 1 passed to Team\Player\Player::__construct()
must be an instance of Team\Player\StatusPlayerInterface,
none given
So you need to instantiate Player
return new Player;
with something:
return new Player(new Active);
That's all you need to make it work, really. The error will go away. But you need this package to work too and I'm afraid this is not enough.
As I said before, if the IoC could work here, how could you make it send the correct implementation of Active, Retired or Injured, at the time you need? I see two options:
1) Call
$this->app->bind('Team\Player\StatusPlayerInterface','Team\Player\Active');
$this->app->bind('Team\Player\StatusPlayerInterface','Team\Player\Retired');
$this->app->bind('Team\Player\StatusPlayerInterface','Team\Player\Injured');
every time you need one of them, which is bad.
2) Change the architecture to keep you in the SOLID track, in the case the Open Closed Principle.
Take a read on the Factory Design Pattern, it might help you out with this achitecture. This is an answer about it: What is a Factory Design Pattern in PHP?.
I've run into a problem and I'm not sure if this is just normal behaviour or if I wrote something wrong. I have a method in my base class that applies a global filter to a given class by way of creating a proxy for all new instances of that particular class. The way I planned to go about it is as follows:
Attach static $global_filter (the proxy) to the class I want to be filtered, which extends the base class object
Via my loading mechanism, return the proxy instead of the actual class upon new instantiations (which will mask method calls and apply filters accordingly)
However, I am getting stuck in step 1 and it seems that when I try to assign static $global_filter to the descendent class I want filtered, my base class object also gets the same assignment, which breaks everything else that extends from it.
Please see below for relevant code:
class object {
public static $global_filter;
public function _filterGlobal($class, $method, $callback) {
if ( !is_object($class::$global_filter) ) {
$class::$global_filter = new filterable(null);
# Replace the object being called with the new proxy.
}
var_dump($class);
var_dump($class::$global_filter); // `filterable`
var_dump(\core\blueprint\object::$global_filter); // Returns same as line above
die();
return $class::$global_filter->_add($method, $callback);
}
}
Both $class::$global_filter and \core\blueprint\object::$global_filter (the base class) are returning same instance. Whereas I expected object::$global_filter to be null.
I'm not using late static binding in order to preserve consistency (both single-object filters and global filters are called much in the same way non-statically).
This question seems relevant
Any help will be much appreciated :)
Edit, full example
This would be a concrete class, which extends model which extends object
<?php
use core\blueprint\model;
class modelMock extends model {
protected $schema = array();
public function method($test) {
return $test;
}
}
This would be another object (e.g a controller), which extends object aswell. It applies a filter to all new instances of model
<?php
use core\blueprint\object;
class objectMock extends object {
public function applyFilters() {
$this->_filterGlobal('core\blueprint\model', 'method', function($self, $chain) {
$chain->params[0] = 'new param'; // adjust the paramters
return $chain->next();
});
}
}
when I try to assign static $global_filter to the descendent class I want filtered, my base class object also gets the same assignment
Yes, indeed this happens. A static property in essence is a global variable, constrained within the class's namespace. Running into problems with global variables is often an indication you're not using the best solution.
To solve your problem, you could make the filter a (non-static) property:
$class->$filter = new Whatever();
But as always, there's more roads that lead to Rome, and I would advise you to look for alterative ways to do it.
I don't know if this is a help for you:
class a {
public static $type;
public static function setType($class, $newType) {
$class::$type = $newType;
var_dump($class::$type);
}
}
class b {
public static $type = 'myType';
}
var_dump(b::$type);
a::setType('b', 'yourType');
var_dump(a::$type);
May be you have not defined the static property to the concrete class.
Thanks everyone for you help, I spent some time on it this morning and managed to solve my problem. It's a bit of a workaround but here's how it goes:
public function _filterGlobal($class, $method, $callback) {
if ( !is_object($class::$global_filter[$class]) ) {
$class::$global_filter[$class] = new filterable(null);
# Replace the object being called with the new proxy.
}
return $class::$global_filter[$class]->_add($method, $callback);
}
So basically in order to get unique static variables working in child classes without having to explicitly define them, you can use an array that stores the child's class name as a key and then access these variables via a getter.
I would like to know whether there's a way to chain methods on a newly created object in PHP?
Something like:
class Foo {
public function xyz() { ... return $this; }
}
$my_foo = new Foo()->xyz();
Anyone know of a way to achieve this?
In PHP 5.4+, the parser's been modified so you can do something like this
(new Foo())->xyz();
Wrap the instantiation in parenthesis, and chain away.
Prior to PHP 5.4, when you're using the
new Classname();
syntax, you can't chain a method call off the instantiation. It's a limitation of PHP 5.3's syntax. Once an object is instantiated, you can chain away.
One method I've seen used to get around this is a static instantiation method of some kind.
class Foo
{
public function xyz()
{
echo "Called","\n";
return $this;
}
static public function instantiate()
{
return new self();
}
}
$a = Foo::instantiate()->xyz();
By wrapping the call to new in a static method, you can instantiate a class with method call, and you're then free to chain off that.
Define a global function like this:
function with($object){ return $object; }
You will then be able to call:
with(new Foo)->xyz();
In PHP 5.4 you can chain off a newly instantiated object:
http://docs.php.net/manual/en/migration54.new-features.php
For older versions of PHP, you can use Alan Storm's solution.
This answer is outdated - therefore want to correct it.
In PHP 5.4.x you can chain a method to a new-call. Let's take this class as example:
<?php class a {
public function __construct() { echo "Constructed\n"; }
public function foo() { echo "Foobar'd!\n"; }
}
Now, we can use this: $b = (new a())->foo();
And the output is:
Constructed
Foobar'd!
Further information may be found on the manual: http://www.php.net/manual/en/migration54.new-features.php
Well, this may be an old question but as with a lot of things in programming - eventually the answer changes.
Regarding PHP 5.3, no, you can't chain directly from the constructor. To expand on the accepted answer however, in order to properly accommodate for inheritance, you can do:
abstract class Foo
{
public static function create()
{
return new static;
}
}
class Bar extends Foo
{
public function chain1()
{
return $this;
}
public function chain2()
{
return $this;
}
}
$bar = Bar::create()->chain1()->chain2();
That will work just fine and will return you a new Bar() instance.
In PHP 5.4, however, you can simply do:
$bar = (new Bar)->chain1()->chain2();
Hopefully this helps someone stumbling across the question like I have!
It would be really helpful if they 'fix this' in a future release. I really appreciate the ability to chain (especially when populating collections):
I added a method to the base class of my framework called create() that can be chained off of. Should work with all descendant classes automatically.
class baseClass
{
...
public final static function create()
{
$class = new \ReflectionClass(get_called_class());
return $class->newInstance(func_get_args());
}
...
public function __call($method, $args)
{
$matches = array();
if (preg_match('/^(?:Add|Set)(?<prop>.+)/', $method, $matches) > 0)
{
// Magic chaining method
if (property_exists($this, $matches['prop']) && count($args) > 0)
{
$this->$matches['prop'] = $args[0];
return $this;
}
}
}
...
}
Class::create()->SetName('Kris')->SetAge(36);
Just for the sake of completeness (and for the fun of it...), since nobody seems to have mentioned the solution with the shortest (and least sophisticated) code.
For frequently used short-lived objects, especially when writing test cases, where you typically do lots of object creation, you may want to optimize for typing convenience (rather than purity), and sorta' combine Alan Storm's Foo::instantiate() factory method and Kenaniah's with() global function technique.
Simply make the factory method a global function with the same name as the class!. ;-o (Either add it as a convenience wrapper around the proper static Foo::instantiate() or just move it out there while nobody is looking.)
class Foo
{
public function xyz()
{
echo "Called","\n";
return $this;
}
}
function Foo()
{
return new Foo();
}
$a = Foo()->xyz();
NOTE:
I WOULDN'T DO THIS on production code. While kinda' sexy, this is an abuse on basic coding principles (like "principle of least surprise" (although this is actually rather intuitive syntax), or "don't repeat yourself", esp. if wrapping a real factory method with some parameters, which itself, BTW, is already an abuse of DRY...), plus PHP may change in he future to break code like this in funny ways.