Why to use variable hinting in Laravel or PHP - php

PHP is not a strict typing language right? I am working with Laravel 5.1 and PHP 7.2
I would make my route like this
Route::get('/getSizes', 'JobTickeController#getSizes')->name('getSizes');
in JobTicketController there I define my function as below
public function getSizes(Request $response){
}
My question is even if PHP is not a strict typing (by default) why should I define Request variable type before $request variable? This code throws an exception with out the type hinting Request.

Although others go into the fact that PHP is not a strictly typed language, there's no answer to why the type hinting is necessary.
What happens in your Laravel app is the following. Laravel will attempt to hit the getSizes method in your controller by resolving any typehinted arguments from "the (Service) Container" also known as IoC. In case it finds no bindings, it will attempt to instantiate the class. Any arguments that have no type hinting are assumed to be "route parameters".
As your route has no parameters, the $request cannot be given any value without being typehinted. When you type hint the $request argument with the Illuminate\Http\Request class Laravel will automatically resolve that binding from its container and make it available inside your method.
TLDR:
Your exception is thrown in case you don't typehint because there's no route parameter to use as value.
Using typehinting will have Laravel automatically resolve a binding from the container or instantiate the class if it has not been bound.
See Method Inject in the Documentation.

First there is nothing named Loose Type, but you can say PHP is not a strictly typed language like JAVA for example.
In your example, that is a Type Hinting, so here you force the function to accept parameters with type Request only.

Related

Symfony 4 extend request for validation

I'm currently working on an API project. I'm used to Laravel and now I need to work with Symfony. I want to use the request like Laravel does for validation.
So I extend the Symfony\Component\HttpFoundation\Request class. There I made some logic to check and sanitize the incoming request.
After that I add my newly created request to the store function in the controller. But that gives me an error:
Argument 1 passed to App\Controller\Ticket\TicketController::store() must be an instance of App\Validation\Ticket\TicketStoreRequest, instance of Symfony\Component\HttpFoundation\Request given,/vendor/symfony/http-kernel/HttpKernel.php on line 149 {"exception":"[object] (Symfony\\Component\\Debug\\Exception\\FatalThrowableError(code: 0): Argument 1 passed to App\\Controller\\Ticket\\TicketController::store() must be an instance of App\\Validation\\Ticket\\TicketStoreRequest, instance of Symfony\\Component\\HttpFoundation\\Request given
After some googling, I found a few options.
Add every controller action to the service.yaml
Create a listener and add the validation on correct route
But all options require extra information on a different place. I hope someone has a better idea.
I found a few hints that might point you in the right direction:
Symfony ships with five value resolvers in the HttpKernel component:
...
RequestValueResolver
Injects the current Request if type-hinted with Request or a class extending Request.
see https://symfony.com/doc/current/controller/argument_value_resolver.html
Then the page goes on to describe the implementation of a custom RequestAttributeValueResolver. This custom resolver can be registered in your
services.yml.
Though in this example a single Class is created for one single attribute type (User), there are ways to create a more dynamic implementation.
In this example the ArgumentMetadata parameter has a method $argument->getType() that should contain a string representation of the type that is checked against:
if (User::class !== $argument->getType()) {
return false;
}
Nothing is stopping you from checking against an array of supported Request-types. This array can be managed as a class member in your custom RequestValueResolver. The only requirement for your custom RequestValueResolver class, is that the supports() method returns true for supported Request types, and that the resolve() function returns an instance of this supported Request type. This should be straightforward because both methods are supplied the 'desired' class through the ArgumentMetaData parameter.
As an alternative, you can implement a custom RequestValueResolver for each custom Request type you want to support, but this does not feel very elegant.
I can not guarantee this will work and I'm also not sure about the differences between implementing the RequestAttributeValueResolver in the example and implementing a custom RequestValueResolver, but I have a feeling it might just work, with a bit of elbow grease.
For reference: https://api.symfony.com/4.1/Symfony/Component/HttpKernel/Controller/ArgumentResolver/RequestValueResolver.html
Here is a solution that elaborates on my other example. It's not as secure as my other example, but it satisfies your requirements.
public function supports(Request $request, ArgumentMetadata $argument)
{
$desiredRequestClass = $argument->getType();
return class_exists($desiredRequestClass);
}
public function resolve(Request $request, ArgumentMetadata $argument)
{
$desiredRequestClass = $argument->getType();
$customRequest = new $desiredRequestClass();
$customRequest->createFromGlobals();
// TODO: more initialization you might need.
yield $customRequest;
}
It might be advisable to check if $desiredRequestClass is a descendant of Request.

PHP type hinting in Laravel

I was wondering if there is any difference in using type hint in method parameters, such as:
function xyz (UserRepository $repo)
and doing the same stuff with annotations:
function xyz ($repo)
/* #var UserRepository $repo */
Using a type hint like
function xyz (UserRepository $repo)
is an instruction that the compiler will understand and react to. This means, PHP will raise an error when you try to pass anything that is not a UserRepository.
Quoting from the PHP Manual:
Type declarations allow functions to require that parameters are of a certain type at call time. If the given value is of the incorrect type, then an error is generated: in PHP 5, this will be a recoverable fatal error, while PHP 7 will throw a TypeError exception.
Using the "annotation" is just documentation. It's just a hint for your IDE and a developer. It has no functional meaning when executing PHP. A user would be able to pass whatever he wants to the function, e.g.
$somethingElse = new SomethingElse;
xyz($somethingElse);
This would work, but then it will fail when trying to access methods on $somethingElse that belong to the UserRespository. With a type hint, you would fail early.
Note: I put annotation in quotes because it's not really an annotation as you know from other languages, like Java. PHP doesn't have annotations as of 7.2. Userland implementations exist though.
Prefer real type hints.
This is not a Laravel specific thing by the way. Type Hints are a native PHP feature.
In addition to what Gordon said, Laravel uses type-hints for automatic injection: https://laravel.com/docs/5.5/container#automatic-injection

How does PHP function dependancy work?

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).

Laravel 5.1 service container: Binding using something other than the class name?

Bit of a long winded question, but here goes. I'm a little confused regarding some of the documentation for the service container in Laravel 5.1. I'll explain my current understanding of the container first, and then explain where my confusion has arisen.
So, I'm fairly sure I understand the process of registering a binding with the service container. To quote the documentation, you register a binding using the bind method, passing the class or interface name that we wish to register along with a Closure that returns an instance of the class:
$this->app->bind('HelpSpot\API', function ($app) {
return new HelpSpot\API($app['HttpClient']);
});
Now, in the Laravel 5.0 docs, that's actually stated slightly differently:
A Closure resolver is registered in the container with a key (typically the class name) and a Closure that returns some value.
So, in Laravel 5.0, it seems you were able to bind some class, say FooBar to a key that, while recommended to be the class name, could be something different, so for example:
$this->app->bind('myfoobarclass', function($app) {
return new FooBar($app['SomethingElse']);
});
And then later you could resolve the class using:
$fooBar = $this->app->make('myfoobarclass');
However, this would remove your ability ro resolve that class using type hinting, which I'm guessing is why the docs for 5.1 states specifically to use the class name. However, in the section on Facades (http://laravel.com/docs/5.1/facades#facade-class-reference), they list the facades along with their "service container binding key", which is different to their class name. Does this mean you can't resolve these facades using type hinting? Why would they register their bindings as something other than their class name? Or is this documentation simply out of date?
If anyone could shed some light on the reasons behind this inconsistency that would be amazing, thanks in advance.
You normally bind implementations to interfaces. So instead of adding something to the service container by the name of the class, you would instead use the name of an interface it implements instead:
$this->app->bind('App\HttpClientInterface', function ($app) {
return new \Guzzle\HttpClient;
});
You can then type-hint the HttpClientInterface interface in your application, and instead get the bound GuzzleHttpClient instance. This allows you to swap your implementations out in one place without having to re-write your application code.
You’re not restricted to using fully-qualified class/interface names, you can use arbitrary strings as key names if you wish:
$this->app->bind('http.client', function () {
return new \Guzzle\HttpClient;
});
But you can’t type-hint on these; this is where you would use the app()->make('http.client') method instead.
In regards to the Façade Class Reference section of the Laravel documentation, there are two ways of resolving the services in your app.
You can type-hint on the value in the Class column, i.e. Illuminate\Contracts\Hashing\Hasher
Alternatively, you can use what’s in the Service Container Binding column with the app()->make('hash') method. These are just “aliases” for the class name.
Hope this helps!

What's the difference between App::singleton and bindShared?

The Laravel docs indicate that the appropriate way to bind a singleton is with the App::singleton() method, but internally Laravel will use the bindShared() method (for example, in TranslationServiceProvider).
I assume that the documented approach is preferred, but is there a functional difference? If not, is there any reason for having two approaches (beyond maybe historical accident)?
I've been wondering the same thing. I don't know the motivations behind this, but I can speak to a few differences.
Here is the definition of the two methods from Laravel 4.2:
public function singleton($abstract, $concrete = null)
{
$this->bind($abstract, $concrete, true);
}
public function bindShared($abstract, Closure $closure)
{
$this->bind($abstract, $this->share($closure), true);
}
Similarities:
Both methods call bind() under the hood.
Both methods pass true to the 3rd parameter of bind(), which signifies that this is a shared object.
In both cases, because this is a shared object, a call to isShared($abstract) will return true.
In both cases, because this is a shared object, a call to make($abstract) will return only the first instance.
Differences:
singleton() will accept a Closure or a string. bindShared() will only accept a Closure, not a string.
bindShared(), in addition to binding the object into the IOC container as a shared object, takes the additional step of wrapping the passed Closure in a share'd Closure, which prevents the passed Closure from being executed more than once. At first glance, this appears to be a double assurance that the object will be treated as a singleton. I can only guess why this might be desirable.
bindShared() is called 87 times inside the framework. singleton() is called 0 times.
They are (were) functionally identical, except that bindShared() only accepts closures.
Thus bindShared() has been deprecated in Laravel 5.1 (PR 9009 - commit 829060f) and removed in Laravel 5.2 (PR 9037).
Case finally solved :)
bind($abstract, $concrete, $shared)
Adds $abstract as a key to the container, with $concrete being the concrete class to instantiate in its place. Mainly used for providing a concrete implementation for an interface.
share($closure)
Given a closure (only), makes it act as if it was shared (instance/singleton style), and returns it. Technically equivalent to App::bind($key, $closure, true) but goes about it a different way. Mainly used in service providers to add a fully resolvable service to the IoC container.
bindShared($abstract, $closure)
A shortcut that was introduced in 4.1 that caters to a common pattern. Essentially helps those who want to bind a shared instance in the container. See below for example.
singleton($abstract, $concrete)
Simply an alias to bind with the $shared argument set to true. Mainly used for providing a concrete implementation for an interface, but one that should only have one instance (database connection, etc.)."
This is from http://alexrussell.me.uk/laravel-cheat-sheet/ I think this link should be helpfull
I think mainly for backwards compatibility. Singleton explains better behavior than bindShared. Removing bindShared would mean Package developers to refactor their code.

Categories