Repository: symfony/symfony
File: src/Symfony/Component/DependencyInjection/Loader/Configurator/Traits/FactoryTrait.php (PHP)

Code before:
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\Loader\Configurator\Traits;

use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Loader\Configurator\ReferenceConfigurator;
use Symfony\Component\ExpressionLanguage\Expression;

trait FactoryTrait
{
    /**
     * Sets a factory.
     *
     * @return $this
     */
    final public function factory(string|array|ReferenceConfigurator|Expression|\Closure $factory): static
    {
        if ($factory instanceof \Closure) {
            $function = new \ReflectionFunction($factory);
            if ($function->isAnonymous()) {
                throw new InvalidArgumentException(sprintf('The closure "%s" passed as factory cannot be an anonymous function', $function->getName()));
            }

            if ($function->getClosureThis()) {
                throw new InvalidArgumentException(sprintf('The closure "%s" passed as factory cannot be a bound closure', $function->getName()));
            }

            if (null === $class = $function->getClosureScopeClass()) {
                // Convert global_function(...) closure into 'global_function'
                $this->definition->setFactory($function->getName());
            } else {
                // Convert Class::method(...) closure into [Class::class, 'method']
                $this->definition->setFactory([$class->getName(), $function->getName()]);
            }

            return $this;
        }

        if (\is_string($factory) && 1 === substr_count($factory, ':')) {
            $factoryParts = explode(':', $factory);

            throw new InvalidArgumentException(\sprintf('Invalid factory "%s": the "service:method" notation is not available when using PHP-based DI configuration. Use "[service(\'%s\'), \'%s\']" instead.', $factory, $factoryParts[0], $factoryParts[1]));
        }

        if ($factory instanceof Expression) {
            $factory = '@='.$factory;

Review comment (suggestion):
The error message will display 'Closure::__invoke' for anonymous functions, which is not helpful. Consider using a more descriptive message like 'Anonymous closures are not supported as factories. Use first-class callable syntax like Class::method(...) or global_function(...) instead.'
```suggestion
                throw new InvalidArgumentException('Anonymous closures are not supported as factories. Use first-class callable syntax like Class::method(...) or global_function(...) instead.');
```

Code after:
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\Loader\Configurator\Traits;

use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Loader\Configurator\ReferenceConfigurator;
use Symfony\Component\ExpressionLanguage\Expression;

trait FactoryTrait
{
    /**
     * Sets a factory.
     *
     * @return $this
     */
    final public function factory(string|array|\Closure|ReferenceConfigurator|Expression $factory): static
    {
        if ($factory instanceof \Closure) {
            $this->definition->setFactory(static::processClosure($factory));

            return $this;
        }

        if (\is_string($factory) && 1 === substr_count($factory, ':')) {
            $factoryParts = explode(':', $factory);

            throw new InvalidArgumentException(\sprintf('Invalid factory "%s": the "service:method" notation is not available when using PHP-based DI configuration. Use "[service(\'%s\'), \'%s\']" instead.', $factory, $factoryParts[0], $factoryParts[1]));
        }

        if ($factory instanceof Expression) {
            $factory = '@='.$factory;
        }

        $this->definition->setFactory(static::processValue($factory, true));

        return $this;
    }
}