I was looking into the codebase of Amazon AWS PHP sdk and found that, several methods in comments are declared as #command such as the one below(link: https://github.com/aws/aws-sdk-php/blob/master/src/Aws/S3/S3Client.php):
* #method Model getObject(array $args = array()) {#command S3 GetObject}
Can anyone please explain how this actually works? I want to know the actual working mechanism inside 'getObject' method call. Thanks in advance.
Methods such as getObject() are dynamic methods instead of static methods. The real call is getCommand('GetObject'), but the class's __call() method handles the real work.
Every service in the SDK has a Model Definition. The getCommand() method takes the inputs and maps them to the Model Definition and makes the right request.
So, think of getObject() as a convenience method, that is constructed dynamically instead of statically.
Related
How does reflection in Laravel actually work?
I tried to debug it to see how Laravel uses reflection in a controller's constructor or methods to resolve their dependencies and sub-dependencies and then and give it back to us.
But I found it hard, and it's very complicated to see and to even understand 50% of. Jumping from class to class, I can't really see it. I tried a few times by debugging it with low results of understanding.
I am very impressed by this and by reflection, and the way Laravel uses it makes my heart burn—it's just beautiful. And I wish to fully understand that—the whole process—in general, and step by step.
Beginning from hitting the route to finally having, let's say, dd($x), where $x is from a method argument and is a TestClass that has another dependency of TestClass2 that should be constructed through: $x = new TestClass(new TestClass2());
I think those are beautiful mechanics and architecture, and understanding this is something I want so badly.
So again, my question is: how does reflection in Laravel actually work?
It's not about dd guys... Let's say without dd. Just as I said earlier - when we have this object instantiated from the class method. It's not about dumping it, it's just about having it from method injection by reflection.
The dd was only an example. It can even be die(var_dump()); and it will work
Laravel uses PHP's reflection API for several components. Of these, the inverson-of-control (IoC) dependency injection container and controller method injection are most visible to developers.
To more clearly illustrate the use of reflection, here's a dramatically simplified version of the routine Laravel's IoC container class uses to build up an object's dependencies through constructor injection:
function build($className)
{
$reflector = new ReflectionClass($className);
$constructor = $reflector->getConstructor();
foreach ($constructor->getParameters() as $dependency) {
$instances[] = build($dependency->getClass()->name);
}
return $reflector->newInstanceArgs($instances);
}
As we can see, the concept isn't too difficult to understand. The container uses PHP's ReflectionClass to find the names of the classes in an object's constructor, and then loops through each of these names recursively to create instances of each object in the dependency tree. With these instances, build() finally instantiates the original class and passes the dependencies as arguments to the constructor.
Controller method injection uses the same container functionality shown above to resolve instances of dependencies declared as method parameters, but there's a bit of extra logic needed to separate class dependencies from route parameters:
function dispatch(Route $route, Controller $controller, $methodName)
{
$routeParameters = $route->parametersWithoutNulls();
$method = new ReflectionMethod($controller, $methodName);
foreach ($method->getParameters() as $index => $parameter) {
$class = $parameter->getClass();
if ($class !== null) {
$instance = build($class->name);
array_splice($routeParameters, $index, 0, [ $instance ]);
}
}
$controller->callAction($methodName, $routeParameters);
}
Again, this adaptation is slimmed-down to highlight the role reflection plays and relies on our build() function shown previously. The ControllerDispatcher class uses the getParameters() method of PHP's ReflectionMethod to determine which parameters a controller method expects, and then loops through these to find parameters that represent dependencies that it can resolve from the container. Then, it splices each dependency it finds back into the array of route parameters that it passes back to the controller method defined for the route. See RouteDependencyResolverTrait for details.
If we ignore the application bootstrapping process, this dependency injection cascade typically starts for a request when Laravel maps a request to a route, and then determines which controller to pass the request to. Laravel first resolves an instance of the controller from the container, which builds out any constructor-injected dependencies. Then, Laravel finds the appropriate controller method and resolves any more dependencies for the arguments as needed.
As shown here, Laravel uses relatively simple techniques to implement these tools using reflection. However, unlike the examples shown in this answer, the framework adds a lot of additional code to make them as robust and flexible as they are today.
I have an example here from the framework Laravel.
class UserController extends Controller
{
public function store(Request $request)
{
$name = $request->input("name");
}
}
What I don't understand is that Request is explicitly defined within the function signature of store().
Couldn't php's type inference figure out what is being passed into the function?
Would this even be considered dependency injection?
This is method level dependency injection. The Request is being passed into the store method, instead of the store method knowing how to create the Request object.
The type hint in the method signature does two things.
First, for plain PHP, it enforces the fact that the parameter passed to the store method must be a Request object, or an object that inherits from Request. If you attempt to call the store() method with anything other than a Request object (or descendant), you will get an error.
Because of this strict type enforcement, we know that the $request parameter must be a Request object (or descendant), and we can depend on its public interface being available for use (you know the input() method will exist).
Second, for Laravel, it tells the Laravel container what type of object this method needs, so that the correct object can be resolved out of the container and passed to the method. Laravel's controller methods are called through the container, which allows automatic dependency resolution of method calls.
If you were to remove the type hint, this would cause two issues. At an abstract level, it would allow you to pass any type of object, or even scalar values, to the store() method. If you attempt to call input() on a string, you're going to have problems. At a more concrete level, this will break Laravel's automatic dependency resolution of controller methods. Without the type hint, Laravel can't know what object the method requires, so it won't pass in anything, so in reality you'd get an error saying that you can't call input() on null (or an error saying the store method requires one parameter; not sure, didn't test).
Recently I got someones PHP site project (and this someone don't wan't to help me), so I have to understand his code. And maybe my answer would be stupid, but...
But there's some methods before class, that are doxumented as in example:
namespace Base\Classes;
/**
* #method int method1()
* #method $this method2(int $parameter)
*/
class SomeClass extends ParentClass
{
public $_s_a = false;
public $_user_roles = [];
public function SomeClassMethod() {
somethingDone();
}
}
And as you can see in this example, these documented methods are not implemented in defined class. But what my question is about - this methods are called from another classes and templates. And PHPStorm (my IDE) connects this documentation lines with calls, and ctrl+B leads from between references. But I can't find exact implementation of this methods. They cannot be found in parent classes, they are not in this file. And I thought maybe this is some syntax sugar that I'm not familiar with. Am I right? Or there something I'm missing, and all implementations somewhere in another place? (search by method name in folder gives nothing for me)
PHP has a few magic methods, and one of them is __call().
When you have an object that implements __call() (by itself or by one of the parent classes), you may call an inaccessible method on it, and the __call() method will be called instead. This happens, for example, when you call a private method from the outside, or when you call a method that was not defined in code.
When you use such calls to inaccessible methods, IDEs will most likely show a warning that the method does not exist, although the code itself will probably work at runtime. These warnings are quite annoying, so you can add a #method tag to your class, and the IDE will know that this method exists, and will not show a warning.
So, to support the code that you got from someone, take a look at the __call() method implementation. Be aware that this method may be implemented in one of the parent classes, so check them out as well.
In a custom validation function in my model class. I need to use javascript code. for that i used registerJs function but i am getting error:-
Calling to undefined function registerJs()
I also tried calling it by including View class i.e., View::registerJs() but it is also giving error called
Non-static method yii\web\View::registerJs() should not be called statically, assuming $this from incompatible context
How can i user Javascript in Yii2 model class.
Edit:
I have created a custom function for mobile number validation and calling that function from rules section of model. Now i want to use javascript code in that function. is there any other way to achive it?
Thanks in advance
That method is not static. If you open the view.php of the framework you can check out the implementation.
public function registerJs($js, $position = self::POS_READY, $key = null){..
}
Exception clearly mentions that should not be called statically because it is not declared static.
I have seen few of the implementations which call this method as:
$view->registerJs($js, $view::POS_END);
Basically loading a particular JS file in one of the functions.
It is not a good idea using Javascript with a model. If you go that way then probably after some time you will find you heading into big problems with the architecture of the app.
The best way is to call the model inside a controller and then interact with the controller through the Javascript code.
I'm confused about an aspect of OOP/Laravel.
I'm following an OOP tutorial (nothing to do with Laravel) that states that you can only use the Scope Resolution Operator when the method you are calling is static.
So I created a quick script;
class Student {
function welcome_students($var="Hello") {
echo "{$var} students.";
}
}
echo Student::welcome_students("Greetings") ."<br />";
And I get the error;
Strict Standards: Non-static method Student::welcome_students() should
not be called statically in /static_modifier.php on line 11 Greetings students.
But in Laravel 5, I've noticed that I've been using calls like
`ClassName::whereIn($var = `
in quite a few of my Controllers. I've checked the package where the whereIn method is stored and it's not static. It's just a public function.
So how is Laravel 5 allowing me to get away with it? I'm in development mode so I don't know why I'm not seeing that same message.
There are some fairly advanced concepts here that need to be understood in order to fully grasp how this is happening.
First, this would only work for the facades in Laravel. These can be found in the app.php config file in the aliases array. Each of these facades can be thought of as entry points for their real classes which are in the Laravel core. So even though the syntax is telling you that you are calling static methods, what's really happening is Laravel is resolving the underlying classes to these proxy classes and calling methods non-statically on those.
You can see this better if you go to some of those facade classes where you will see the methods you are calling are not actually present on those classes.
To really understand how this is happening, read up on Laravel's inversion of control container (IoC), its use of Facades, and the php magic method __callStatic, and the php method class_alias which is what Laravel is using to setup the aliases.
Again, these are fairly complex concepts so don't get discouraged if they seem confusing or the purpose eludes you.
Basically, the workflow looks like this...
You call Config::get()
Laravel looks up the alias for Config which is a facade.
Using the __callStatic magic method, the facade figures out the underlying class to instantiate and calls the appropriate method on that non-statically.
http://laravel.com/docs/5.0/facades#explanation
http://laravel.com/docs/4.2/ioc#introduction
http://php.net/manual/en/language.oop5.overloading.php#object.callstatic
First of all, your function is not static, you need change it if you want to call it like Student::welcome_students()
public static function welcome_students($var="Hello") {
echo "{$var} students.";
}