*/ class LazyString implements \Stringable, \JsonSerializable { private \Closure|string $value; /** * @param callable|array $callback A callable or a [Closure, method] lazy-callable */ public static function fromCallable(callable|array $callback, mixed ...$arguments): static { if (\is_array($callback) && !\is_callable($callback) && !(($callback[0] ?? null) 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__, '['.implode(', ', array_map('get_debug_type', $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] ??= '__invoke'; } $value = $callback(...$arguments); $callback = self::getPrettyName($callback); $arguments = null; } return $value ?? ''; }; return $lazyString; } public static function fromStringable(string|int|float|bool|\Stringable $value): static { if (\is_object($value)) { return static::fromCallable($value->__toString(...)); } $lazyString = new static(); $lazyString->value = (string) $value; return $lazyString; } /** * Tells whether the provided value can be cast to string. */ final public static function isStringable(mixed $value): bool { return \is_string($value) || $value instanceof \Stringable || \is_scalar($value); } /** * Casts scalars and stringable objects to strings. * * @throws \TypeError When the provided value is not stringable */ final public static function resolve(\Stringable|string|int|float|bool $value): string { return $value; } public function __toString(): string { if (\is_string($this->value)) { return $this->value; } try { return $this->value = ($this->value)(); } catch (\Throwable $e) { if (\TypeError::class === $e::class && __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)); } throw $e; } } public function __sleep(): array { $this->__toString(); return ['value']; } public function jsonSerialize(): string { return $this->__toString(); } 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_debug_type($callback[0]) : $callback[0]; $method = $callback[1]; } elseif ($callback instanceof \Closure) { $r = new \ReflectionFunction($callback); if (str_contains($r->name, '{closure}') || !$class = \PHP_VERSION_ID >= 80111 ? $r->getClosureCalledClass() : $r->getClosureScopeClass()) { return $r->name; } $class = $class->name; $method = $r->name; } else { $class = get_debug_type($callback); $method = '__invoke'; } return $class.'::'.$method; } } __halt_compiler();----SIGNATURE:----k7wSZhFJ0uWqj760xQZKSh4zgmr8YRW1xIOxyTGadFu3CWkli09PvUf08ZYeZGgeCFoj9Bc19nTojNFhlfNm1I8dxpCkj3QLy64OtH8T4vQFqo1npgzLpVwhGhVnpF7QpfZZZLsm+rVqFj36R+X1braeA8gS5ISVyePHe3qSRK6CyLoigpkXdKsUTa2atJA769ttuk61xDZdhMvBD35CWVtN+S/Y3Hf4E2OOjQp22GYMCI1/1diNhNa0EH4yGhxn5gC6kpSrKu+WWyQoVM7dV2+dla7fpzfPMVSzHhmsxoXDUDWuZFMRH8qSxrnKy03PHKPesbF8O/g1kD0aD2BCjXID8dUgFpkJ/dV6j82ZaSANn0f1WHnYM28pLLpA0u1ngQ3WfGwaXMrfiwOqRi4duWKVA+1FM6bXlXGpjvR4wUsgGCPJcNHApm5TBLnA5X7d6jnvCex4zQiCN+tuc7rDA72SKj5ztD7yitu+Aqj/6167GGfSP7vXG04DgKQWfiptJe/HltVFHPZ4nnequB1QFsGmTHvi0z0RgkwKiFBV+q8p+HElGinRsgcmwmuPLe7b4nKKo9/8REv1FB/v8UY2svoYZpnO7qE8VUN7cEAokVX9RpzOFFC6cecO7Imx2RZsLNP+h7Wd2FQDiby1B00W0h14YqM9UMdyMGqfj0A/oIo=----ATTACHMENT:----NjA0MzEwMTQ2NTM2MTc0NiA2MTk4NDQ1NDI2MzMwNjYyIDYyNjQ2Njg4NTk5OTUwMzY=