3

This is not about instructions (the docs are sufficient), but a question of how things work.

Symfony 4's autowiring system allows us to auto-inject services by simply typehinting

use App\Util\Rot13Transformer;

class TwitterClient
{
  public function __construct(Rot13Transformer $transformer)
  {
    $this->transformer = $transformer;
  }
}

To gain a deeper understanding of PHP, I have looked around in the symfony-bundle source code but can't find the spot where the "magic" happens.

How can Symfony prevent PHP from protesting that not enough arguments were fed to the constructor (or any function that uses autowiring)?

4

2 回答 2

6

They use Refection

How can Symfony prevent PHP from protesting that not enough arguments were fed to the constructor

Reflection allows you to inspect the definition of other "things" in PHP. Among them are Classes their methods, and the arguments for those methods.

<?php
class bar
{
    //just a placeholder class
};

$bar = new bar(); //instance of bar

//class to inspect
class foo
{        
    public function __construct( bar $bar)
    {
        //do something fancy with $bar
    }        
}

//get the Reflection of the constructor from foo
$Method = new ReflectionMethod('foo', '__construct');

//get the parameters ( I call them arguments)
$Args = $Method->getParameters();

//get the first argument
$Arg = reset($Args);

//export the argument definition
$export = ReflectionParameter::export(
   array(
      $Arg->getDeclaringClass()->name, 
      $Arg->getDeclaringFunction()->name
   ), 
   $Arg->name, 
   true
);

//parse it for the typehint
$type = preg_replace('/.*?(\w+)\s+\$'.$Arg->name.'.*/', '\\1', $export);
echo "\nType: $type\n\n";

var_dump(is_a($bar, $type));

Outputs:

Type: bar

bool(true)

You can see it here

Then you just use is_a() or whatever to see if an "input" object has bar as one of it's ancestors. And as you can see in this simplified example if we had object $bar, we would know that it's perfectly good as an input to our constructor because it returns true.

I should note SO is probably not the right place to ask this, but i could use it in one of my many projects so I didn't mind figuring it out. Also I never used Symphony... Special thanks to this SO question for the last bit on parsing the type hint:

PHP Reflection - Get Method Parameter Type As String

That said I would have figured the Regx out in about 10 seconds, the export method no so much.

This is the extent of the documentation on it

http://php.net/manual/en/reflectionparameter.export.php

Literally

public static string ReflectionParameter::export ( string $function , string $parameter [, bool $return ] )
于 2017-12-03T14:46:54.160 回答
2

As others mentioned, they use Reflection. If you want to see how exactly Symfony is doing this, start with autowire() method here

于 2017-12-03T14:53:44.110 回答