Home > other >  I can not create a class instance from a string in Symfony
I can not create a class instance from a string in Symfony

Time:08-14

What I wanted to is to create class instance from string in Symfony framework to use Doctrine Repository. Here is my code block:

        $type = "SomeClassName";
        $productType = $this->productTypeProvider->getProductType($product->getBarcode());
    $repository = $this->doctrine->getRepository($type::class);

I want to use SomeClassName::class above but it gives me the following error. Any help would be appeciated:

Cannot use "::class" on value of type string (500 Internal Server Error)

CodePudding user response:

As mentioned above, using the full class name worked perfectly.

CodePudding user response:

To understand why this doesn't work, it's useful to have some background on how namespaces are implemented in PHP:

  • Every class, interface, trait, and enum has a "fully-qualified class name" (FQCN), which can contain zero or more namespace separators (\)
  • A particular file, or code-block, can have a "current namespace" defined.
  • Within that block, you can have any number of use statements, which provide short-hands within the scope of that file.

The expansion of the current namespace, and the currently in-scope use statements, happens at compile-time - in case you're not aware, PHP is a compiled language, the compiler is just invoked automatically, for a single file.

The ::class syntax is part of this compile-time expansion: it substitutes any relevant use statements or current namespace, and then treats the result as a string. In other words, this:

namespace Foo\Bar;
use Something\Else;
use Something\Else\Again as Alias;

echo Example::class;
echo Else::class;
echo Else\More::class;
echo Alias::class;

Is compiled exactly as though it said this:

echo 'Foo\Bar\Example';
echo 'Something\Else';
echo 'Something\Else\More';
echo 'Something\Else\Again';

Those strings can then be passed around to wherever needs an FQCN.

The key point here is that this all happens before any code in the file is executed. When you tried to write $type::class, the value of $type is something that will only be known at run-time; far too late for the namespace expansion in the compiler to affect it. Theoretically, the compiler could know what you meant by "SomeClassName"::class, but it would be unnecessary extra complexity since you can just write SomeClassName::class instead.

If you are building a string at run-time, you are responsible for turning it into an FQCN.

Note that despite its name, ::class doesn't actually check that the result is a class name, it just does string manipulation based on the current namespace and use statements, so the following are all equivalent:

namespace Example;

use App\Entity; // [1]
use App\Entity\SomeClassName; // [2]

// explicit FQCN
$type = 'App\Entity\SomeClassName';

// straight-forward expansion of [2]
$type = SomeClassName::class;

// expansion of [1]
$type = Entity\SomeClassName::class;

// expand the namespace via [1] then add class name
$namespace = Entity::class;
$type = $namespace . '\SomeClassName';

// expand to a non-existent class, then add more text
$prefix = Entity\So::class;
$type = $prefix . 'meClassName';
  • Related