- */ -class LazyString -{ - private $value; - - /** - * @param callable $callback A callable or a [Closure, method] lazy-callable - * - * @return static - */ - public static function fromCallable($callback, ...$arguments): self - { - if (!\is_callable($callback) && !(\is_array($callback) && isset($callback[0]) && $callback[0] instanceof \Closure && 2 >= \count($callback))) { - throw new \TypeError(sprintf('Argument 1 passed to %s() must be a callable or a [Closure, method] lazy-callable, %s given.', __METHOD__, \gettype($callback))); - } - - $lazyString = new static(); - $lazyString->value = static function () use (&$callback, &$arguments, &$value): string { - if (null !== $arguments) { - if (!\is_callable($callback)) { - $callback[0] = $callback[0](); - $callback[1] = $callback[1] ?? '__invoke'; - } - $value = $callback(...$arguments); - $callback = self::getPrettyName($callback); - $arguments = null; - } - - return $value ?? ''; - }; - - return $lazyString; - } - - public function __toString() - { - if (\is_string($this->value)) { - return $this->value; - } - - try { - return $this->value = ($this->value)(); - } catch (\Throwable $e) { - if (\TypeError::class === \get_class($e) && __FILE__ === $e->getFile()) { - $type = explode(', ', $e->getMessage()); - $type = substr(array_pop($type), 0, -\strlen(' returned')); - $r = new \ReflectionFunction($this->value); - $callback = $r->getStaticVariables()['callback']; - - $e = new \TypeError(sprintf('Return value of %s() passed to %s::fromCallable() must be of the type string, %s returned.', $callback, static::class, $type)); - } - - if (\PHP_VERSION_ID < 70400) { - // leverage the ErrorHandler component with graceful fallback when it's not available - return trigger_error($e, E_USER_ERROR); - } - - throw $e; - } - } - - private function __construct() - { - } - - private static function getPrettyName(callable $callback): string - { - if (\is_string($callback)) { - return $callback; - } - - if (\is_array($callback)) { - $class = \is_object($callback[0]) ? \get_class($callback[0]) : $callback[0]; - $method = $callback[1]; - } elseif ($callback instanceof \Closure) { - $r = new \ReflectionFunction($callback); - - if (false !== strpos($r->name, '{closure}') || !$class = $r->getClosureScopeClass()) { - return $r->name; - } - - $class = $class->name; - $method = $r->name; - } else { - $class = \get_class($callback); - $method = '__invoke'; - } - - if (isset($class[15]) && "\0" === $class[15] && 0 === strpos($class, "class@anonymous\x00")) { - $class = get_parent_class($class).'@anonymous'; - } - - return $class.'::'.$method; - } -} diff --git a/src/Symfony/Component/DependencyInjection/Tests/LazyStringTest.php b/src/Symfony/Component/DependencyInjection/Tests/LazyStringTest.php deleted file mode 100644 index 38899bb36972..000000000000 --- a/src/Symfony/Component/DependencyInjection/Tests/LazyStringTest.php +++ /dev/null @@ -1,72 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\LazyString; -use Symfony\Component\ErrorHandler\ErrorHandler; - -class LazyStringTest extends TestCase -{ - public function testLazyString() - { - $count = 0; - $s = LazyString::fromCallable(function () use (&$count) { - return ++$count; - }); - - $this->assertSame(0, $count); - $this->assertSame('1', (string) $s); - $this->assertSame(1, $count); - } - - public function testLazyCallable() - { - $count = 0; - $s = LazyString::fromCallable([function () use (&$count) { - return new class($count) { - private $count; - - public function __construct(int &$count) - { - $this->count = &$count; - } - - public function __invoke() - { - return ++$this->count; - } - }; - }]); - - $this->assertSame(0, $count); - $this->assertSame('1', (string) $s); - $this->assertSame(1, $count); - $this->assertSame('1', (string) $s); // ensure the value is memoized - $this->assertSame(1, $count); - } - - /** - * @runInSeparateProcess - */ - public function testReturnTypeError() - { - ErrorHandler::register(); - - $s = LazyString::fromCallable(function () { return []; }); - - $this->expectException(\TypeError::class); - $this->expectExceptionMessage('Return value of '.__NAMESPACE__.'\{closure}() passed to '.LazyString::class.'::fromCallable() must be of the type string, array returned.'); - - (string) $s; - } -} diff --git a/src/Symfony/Component/DependencyInjection/composer.json b/src/Symfony/Component/DependencyInjection/composer.json index 4924d389eeda..5e3f2eab8cee 100644 --- a/src/Symfony/Component/DependencyInjection/composer.json +++ b/src/Symfony/Component/DependencyInjection/composer.json @@ -23,7 +23,6 @@ "require-dev": { "symfony/yaml": "^3.4|^4.0|^5.0", "symfony/config": "^4.3|^5.0", - "symfony/error-handler": "^4.4|^5.0", "symfony/expression-language": "^3.4|^4.0|^5.0" }, "suggest": {