Laravel 4 - Container class: share function & closure logic - php

I have a follow-up question to the one discussed here:
Laravel core method confusion
I am in the same situation as driechel (author of question above) has been before, currently getting used to Laravel 4 FW and examining the core. Although a precise answer has been given I still don't understand the logic and what is happening under the hood. So I would very much appreciate a further explanation.
I know this might be a duplicate but since I cannot post comments yet I'll give it a shot with a new question. Hope it' ok this way.
I have been looking at this from another angle starting at this article:
http://blog.joynag.net/2013/05/facades-in-laravel-4-and-static-methods-resolution/
When examining the call File:get() I finally end up at the Container class' share function which is called with this actual parameter share(function() { return new Filesystem; }.
What I just can't figure out is the use of $container. Especially at the second occurence within the closure:
$object = $closure($container);
Could you please clarify this again? Why is $container passed as a parameter here and what is actually contained in it? As far as I understand $closure at that point holds and executes function() { return new Filesystem; } which has no input parameter.
I am lost. Studied this and the PHP anonymous functions/closures now for two days straight and still can't figure it out. I neither understand the syntax of $closure($container) here nor the logic.

For reference, this is the share method # v4.0.5.
So, what's happening here. I'll explain it in a couple of steps.
Calling The Share Method
As you pointed out this method is called from service providers. So, the FilesystemServiceProvider calls this method which looks something like this:
$this->app['files'] = $this->app->share(function() { return new Filesystem; });
It's assigning the return value of this share method to a binding in the container. In a nutshell, that return value will be the new Filesystem instance that is returned in the closure.
So What Does Share Do?
The share method is just another way of defining a singleton in IoC container. All this can be a bit intimidating at first. Basically, Laravel itself is an IoC container. All the classes are bound as instances on the container. Sometimes these instances should be the same instance on every call.
If you take a look at the referencing method above on GitHub, you'll notice that inside the closure a static variable is defined. It then checks if that variable is null, and if it is it resolves the closure (this is the closure that returns our new Filesystem instance). Then it simply returns the variable.
Now, the next time you use File::get() it doesn't need to instantiate the Filesystem class again, because it's already been instantiated and stored in the static $object variable. So it simply returns the same object to you.
So! Really, you could replace the $this->app['files'] line with this, and it would still work.
$this->app->instance('files', new Filesystem);
99% of services actually use the share method though because working inside a closure allows objects to be instantiated with more complex dependencies.
Hope this helps.

Related

PHP-DI Potentially polymorphic call when using the set method

The issue
I have an unexpected warning from PHPStorm when I try to set a new value in a PHP-DI container.
Given the following code:
function inject(Psr\Container\ContainerInterface $container){
$container->set(RandomClass::class, new RandomClass());
}
$container = new DI\Container(); class is instantiated
inject($container);
The following warning is triggered
Potentially polymorphic call. does not have members in its hierarchy
I understand what the warning means, but I do not see why it pops up, especially since I have not found any occurrences of this situation while looking on Google and SO and the documentation does not mention it.
Is there something I am missing, or is this a "false positive" ?
The set() method is not part of Psr\Container\ContainerInterface.
If you want to use that method, you can't typehint against the interface because your code explicitly needs a PHP-DI instance.
Your code doesn't have to be generic, don't overthink things too much. The PSR is useful mostly for frameworks and libraries (who need to be compatible with multiple containers), not for end-users.
The day you switch container library you will have many more complex things to do than just replacing the set() call.
The reason behind the issue
Given the following code (which is very similar to the one I use)
function inject(Psr\Container\ContainerInterface $container){
$container->set(RandomClass::class, new RandomClass());
}
$container = new DI\Container(); class is instantiated
inject($container);
The $container->set(...) call is going to trigger the following warning
Potentially polymorphic call. does not have members in its hierarchy
This is to be expected as Psr\Container\ContainerInterface only contains definitions for the following methods
get($id)
has($id)
The solution
Two possible solutions for this issue:
Type the methods directly with the container, making sure to not use the FQN of the class but only use Container and "use the namespace", it will make changing to a new container package easier (because this is still the goal behind PSRs, being able to almost hot-swap packages).
Create a custom interface based on Psr\Container\ContainerInterface and add the required methods to it.
Or, eventually, you can try to make PHP-FIG extend the PSR-11 standard to include a standard set($id, $value) method.

How can I test this method call with PHPUnit?

Code to be tested:
// Add the activation provider argument to the factory definition
$factoryDefinition = $container->getDefinition('gremo_subscription_factory');
$factoryDefinition->addArgument(new Reference($providerId));
Test method should check the addArgument method, including $providerId argument. I'm just learining PHPUnit and right now I'm only able to call $this->anything():
$container->expects($this->at(3))
->method('getDefinition')
->with('gremo_subscription_factory')
->will($this->returnValue($factory));
$factory->expects($this->once())
->method('addArgument')
->with($this->anything());
$this->pass->process($container);
How can I check that argument type is Reference class, and (in turn) its argument is exactly the string $providerId?
This is pretty complicated, especially since the Reference class is not dependency injected and method call doesn't return anything. However, I think you can get around it using argument constraints. Here's how I would do that second clause:
$factory->expects($this->once())
->method('addArgument')
->with($this->logicalAnd(
$this->isInstanceOf('Reference'),
$this->attributeEqualTo('attribute', $providerId)
));
The second item in the logicalAnd() is basically just checking the Reference object that is created to see if $providerId gets assigned correctly (I'm not sure what happens to $providerId in the Reference constructor, but I'm assuming it gets saved to an instance variable or something).
This sort of thing, however, is moving into the territory of testing implementation details of the Reference class, so tests like this are not great for maintaining SRP. All of this would be better solved by refactoring your code. Generally speaking, if it's hard to test, it is probably not the test suite's fault. If you are able to, consider changing things on that end first, rather than writing overly-clever tests.

JavaScript Objects Sharing Local Variable

So I have a bug in some JavaScript code that has been driving me moderately crazy. I've been trying to mimic classical inheritance in JavaScript (I know, I know, half the posts I read on here say not to twist JavaScript into such a framework, but my application needs to have a client-side heirarchy that maps to the inheritance structure of my server-side php code). And mostly, it looks like everything is working. Here's the function I'm using to extend classes:
Function.prototype.inheritsFrom = function(parentClass) {
//:: Ordinary Classes
if (parentClass.constructor == Function) {
this.prototype = new parentClass();
this.prototype.constructor = this;
this.prototype.parent = parentClass.prototype;
//:: Abstract Classes
} else {
this.prototype = parentClass;
this.prototype.constructor = this;
this.prototype.parent = parentClass;
}
return this;
}
Not my own creation, I found it online, but it works well. The only thing I needed to add was a "super" function to search the prototype chain for parent methods; the parent construct in the aforementioned code doesn't work in every case.
In any case, as I've been ironing out some bugs in my code, I found that one of the methods in my base "class" is accessing/modifying the same variable for all instances created from all of its subclasses. In other words, whenever one instance modifies this variable which should be local to its object context, it in fact modifies some variable that is shared between all instances. Here's the base class:
function DataManipulatorControl() {
//|| Private Members ||//
var that = this;
//|| Properties ||//
//|| Root ID
this.rootID = function(value) {
if (value !== undefined) {
if (_root_id !== null) {
alert('# ' + _root_id);
$('#' + _root_id).prop('js_object', null);
}
_root_id = value;
$('#' + _root_id).prop('js_object', this);
}
return _root_id;
}
var _root_id = null;
// other properties/methods
}
//|| Class: DataManipulatorContainerControl
function DataManipulatorContainerControl() {
//|| Private Members ||//
var that = this;
// subclass properties/methods
}
DataManipulatorContainerControl.inheritsFrom(DataManipulatorControl);
As I mentioned, when I create new instances of these prototypes, I'm finding that changing the rootID for one instance will change it for all. My first thought was that I forgot a "var" somewhere, and that my function was accessing the global context. That doesn't seem to be the case though, so my next thought is that it's using a variable local to the prototype. That doesn't make much sense to me either though, because variables local to the prototype's constructor call shouldn't be accessible outside of it, unless accessed by a method that already has it in scope. Of course, the rootID() function does have it in scope, but I was under the impression that it would be run using the object context of the invoking object, not the prototype.
So, I'm very confused. Any light that can be shed on this issue would evoke much gratitude.
EDIT: The article provided by PRB describes a solution which cleanly solves this issue - mostly. The article notes that you need to also call the parent class' constructor from within the child class constructor to initialize everything correctly. As a result, all of the methods are created fresh, with their own versions of the parent class local variables in closure.
There does seem to be one shortcoming with this approach (aside from efficiency concerns of duplicating functions in every instance). If one tries to call "overridden" functions from the prototype chain in an attempt at super functionality, this problem will resurface. The prototypes are, as before, instances of a single object, and trying to call their versions of a function will cause them to try to access their instance's local variables.
Still the best solution I've seen though, aside from making all the data public :-).
Using this line is probably the issue:
this.prototype = new parentClass();
This means that all instances of the function share the same memory blob defined by parentClass(). This is why when you change the value in one, it affects all of them.
Okay, so I've been thinking about it over some dinner, and I think I might have a handle on what's going on. I think I'm confusing variables available to a function due to a changing object context, and variables available to a function because of closures.
As PRB pointed out, my rootID() function always accesses the blob of memory from the instantiated prototype. _root_id is created as a variable local to the constructor for my base class, so when that base class is instantiated to become a prototype, all subclasses using the prototype's function will as a result be reading from/writing to the one variable created in the constructor.
So while that is a valid way to create a prototype, hiding the object's data using variables local to the constructor will not work correctly in subclasses. Rather, I'll need to read from/write to variables in 'this', so that it changes as the object's context changes. If anyone knows of a better way to handle this - one which obeys data hiding, please feel free to comment; a lot of the developers I work with have no qualms about accessing data members directly instead of through accessors. Makes code hard to maintain :-/.
At any rate, thanks PRB for the clarification!
~ Nate

In PHP, is there a way to get all declared classes in a specific namespace?

I'd like to get the names of all classes within a specific namespace in PHP. Currently, I'm attempting to do some magic via reflection on a specific list of named classes, but I'd like to do it without knowing the names ahead of time.
I've tried calling get_declared_classes(), but for whatever reason, classes that I do have available are not showing up. I can call get_declared_classes(), not see Event in the list, then immediately call $x = new Event() without a problem. Something like the following, which I would think should cause a problem...
if (! in_array('Event', get_declared_classes())) { $x = new Event(); }
...works fine. I'm wondering if namespacing these classes and retrieving that way would help alleviate the problem. Is this possible?
EDIT: For clarification, let me add that I am not currently using namespaces, and I am not specifically trying to achieve something from the above listed code. What I want is to get the names of all classes I have declared. Despite the fact the class declarations for all of them are being hit before I call get_declared_classes(), they are not all appearing in the list. I was hoping that namespacing might help solve the problem.
EDIT2: Several people have pointed out that the classes may be autoloaded. I tested this by doing the following. echo(class_exists('Event')) returned a value of 1. echo(class_exists('Event', FALSE)) returned a value of 0. The second, optional parameter to class_exists is whether or not to autoload. So, apparently the class is being autoloaded. That answers that.
So, next question - how do I prevent this? I'm using a framework that really doesn't give me much low-level control. Is there a way to force autoloading, THEN call get_declared_classes, or for get_declared_classes to fire an autoload first?
You do not need to hard code it in the code, you can use variable name:
$class_name = 'Event';
if (!in_array($class_name, get_declared_classes())) {
$x = new $class_name();
};
See similar code in action here: codepad.org/hCLE4ToA.
Also some classes may not appear in get_declared_classes()'s result, because they may not be loaded at the time this function is called. It may be the case if they are autoloaded after you try to instantiate them. See more on autoloading classes here: php.net/autoload.
Does it answer some of your questions? Did it help?

Is there anyway to get the order of the OOP method being called?

For example lets say I have a set of classes and methods to do so:
$obj->method1()->method2();
Is there anyway for method1() to know with in itself that its the first method being called or for method2 to know that its the last?
Some more details
I just want to be able to build a set of these calls so that it either returns an instance of itself if the call to the method isnt at the end of the chain or return something different if its at the end.
For example
$obj->method1()->method2(); #Here method 2 will return lets say a string.
$obj->method1()->method2()->method3(); #Since method2 isnt at the end of the chain, it should return an instance of itself (or another object) here so that the chain could continue.
EDIT: anyone whoz trying to do this - it is a bad design pattern.
This does seem to be a duplicate. Refer to this question for more answers.
Not out of the box, not even with a Stack trace.
I guess you could put something together using constants or global variables:
Don't try this at home!
$GLOBALS["chain"] = array();
$obj->method1()->method2(); // method1 adds member to $GLOBALS["chain"],
// array_push($GLOBALS["chain"], __FUNCTION__);
// method2 does the same...
print_r($GLOBALS["chain"]);
That would give you the full chain - not yet which one is the last one, to do that, you would have to pass a flag to method2().
But it would be horribly hacky and pollute your code.
Is there a specific reason you need this for?
All you could do is find out which methods have been called so far, by setting some kind of global state in the class. But you can't find out what methods are being called after a method, and you wouldn't be able to tell the difference between methods in one chain and methods in another:
$obj->m1()->m2();
$obj->m3(); // You would think that m1() and m2() came before this in the same chain
You would need to have a method at the end of each chain to clear the global state in the class.
Since it seems you need to see which method comes next in a chain, this won't work for you.
I would say that this is a really bad design pattern, at least for PHP (and every other language I've worked in). Each method should do one thing only. If you need a method to either return a string or an object depending on what you need it for later, you are doing something wrong.
Granted, I have done something like this before. It was a meta-information class for images submitted by users -- you could set it up like this:
$meta = new ImageMeta();
$meta->first_name("foo")->last_name("bar")->email("baz")->id("guid");
But, if you did this:
$meta->first_name();
it would return a string. The default value for the first parameter was NULL, and if the method got NULL, it returned a string. Otherwise it set (and escaped) an internal value and returned $this.
At first I thought it was kind of cool, but it turned out to be a mistake. I hate using that class now. Just make one method/function do one thing only and you will be much happier.
I don't think this is possible, no -- at least, I've never seen anything about this.
(Out of curiosity : why would you need that ? Maybe it would be possible to use onther solution to solve your actual problem ?)
The only way this is possible is to let the methods save some global state.
If both methods are in the same class, you could add a variable to the class and let each class set a unique value.
But the question is if this is desirable. This kind of behavior is often not very smart in the long run.

Categories