Cache the list of known HTML tag handlers
authorAlexander Ebert <ebert@woltlab.com>
Thu, 11 Apr 2024 13:33:14 +0000 (15:33 +0200)
committerAlexander Ebert <ebert@woltlab.com>
Sat, 8 Jun 2024 10:29:35 +0000 (12:29 +0200)
The `\class_exists()` call for handlers that do not exist always go through the autoloaders.

For large sets of documents this change improves the request latency by up to 2%.

wcfsetup/install/files/lib/system/html/node/AbstractHtmlNodeProcessor.class.php

index 17fca6196b9b5a34bc33120afb07ca1c69e64b40..6ef44f7e32f84bc29fc93ad0bbb9ea40195af2db 100644 (file)
@@ -320,6 +320,8 @@ abstract class AbstractHtmlNodeProcessor implements IHtmlNodeProcessor
      */
     protected function invokeNodeHandlers($classNamePattern, array $skipTags = [], ?callable $callback = null)
     {
+        static $handlerClassExists = [];
+
         $skipTags = \array_merge($skipTags, ['html', 'head', 'title', 'meta', 'body', 'link']);
 
         $tags = [];
@@ -343,7 +345,15 @@ abstract class AbstractHtmlNodeProcessor implements IHtmlNodeProcessor
                 return \ucfirst($matches[1]);
             }, $tagName);
             $className = $classNamePattern . \ucfirst($tagName);
-            if (\class_exists($className)) {
+
+            // The `\class_exists()` call has to go through the autoloader which
+            // can become quite expensive when dealing with a lot of tags and
+            // messages within one request.
+            if (!isset($handlerClassExists[$className])) {
+                $handlerClassExists[$className] = \class_exists($className);
+            }
+
+            if ($handlerClassExists[$className]) {
                 if ($callback === null) {
                     $this->invokeHtmlNode(new $className());
                 } else {