diff --git a/src/Error/Error.php b/src/Error/Error.php index 6c72f7ffc..3ccdda2cd 100644 --- a/src/Error/Error.php +++ b/src/Error/Error.php @@ -142,7 +142,7 @@ class Error extends \Exception } if ($this->name) { - if (\is_string($this->name) || (\is_object($this->name) && method_exists($this->name, '__toString'))) { + if (\is_string($this->name) || $this->name instanceof \Stringable) { $name = \sprintf('"%s"', $this->name); } else { $name = json_encode($this->name); diff --git a/src/Extension/CoreExtension.php b/src/Extension/CoreExtension.php index 9f3457a12..6e1e1428e 100644 --- a/src/Extension/CoreExtension.php +++ b/src/Extension/CoreExtension.php @@ -1175,7 +1175,7 @@ final class CoreExtension extends AbstractExtension return iterator_count($thing); } - if (method_exists($thing, '__toString')) { + if ($thing instanceof \Stringable) { return mb_strlen((string) $thing, $charset); } @@ -1300,7 +1300,7 @@ final class CoreExtension extends AbstractExtension return !iterator_count($value); } - if (\is_object($value) && method_exists($value, '__toString')) { + if ($value instanceof \Stringable) { return '' === (string) $value; } diff --git a/src/Extension/SandboxExtension.php b/src/Extension/SandboxExtension.php index fd5f242db..9335b453b 100644 --- a/src/Extension/SandboxExtension.php +++ b/src/Extension/SandboxExtension.php @@ -119,7 +119,7 @@ final class SandboxExtension extends AbstractExtension public function ensureToStringAllowed($obj, int $lineno = -1, ?Source $source = null) { - if ($this->isSandboxed($source) && \is_object($obj) && method_exists($obj, '__toString')) { + if ($this->isSandboxed($source) && $obj instanceof \Stringable) { try { $this->policy->checkMethodAllowed($obj, '__toString'); } catch (SecurityNotAllowedMethodError $e) { diff --git a/src/Extension/StringLoaderExtension.php b/src/Extension/StringLoaderExtension.php index b1f2b4e46..8f8087fcd 100644 --- a/src/Extension/StringLoaderExtension.php +++ b/src/Extension/StringLoaderExtension.php @@ -29,12 +29,11 @@ final class StringLoaderExtension extends AbstractExtension * * {{ include(template_from_string("Hello {{ name }}")) }} * - * @param string $template A template as a string or object implementing __toString() - * @param string|null $name An optional name of the template to be used in error messages + * @param string|null $name An optional name of the template to be used in error messages * * @internal */ - public static function templateFromString(Environment $env, $template, ?string $name = null): TemplateWrapper + public static function templateFromString(Environment $env, string|\Stringable $template, ?string $name = null): TemplateWrapper { return $env->createTemplate((string) $template, $name); } diff --git a/src/Markup.php b/src/Markup.php index 68b9894cf..81f5ae7a5 100644 --- a/src/Markup.php +++ b/src/Markup.php @@ -16,7 +16,7 @@ namespace Twig; * * @author Fabien Potencier */ -class Markup implements \Countable, \JsonSerializable +class Markup implements \Countable, \JsonSerializable, \Stringable { private string $content; private string $charset; diff --git a/src/Runtime/EscaperRuntime.php b/src/Runtime/EscaperRuntime.php index 664ef6092..43fb17778 100644 --- a/src/Runtime/EscaperRuntime.php +++ b/src/Runtime/EscaperRuntime.php @@ -91,7 +91,7 @@ final class EscaperRuntime implements RuntimeExtensionInterface } if (!\is_string($string)) { - if (\is_object($string) && method_exists($string, '__toString')) { + if ($string instanceof \Stringable) { if ($autoescape) { $c = $string::class; if (!isset($this->safeClasses[$c])) {