Parse smiley codes only once during the request lifetime
authorAlexander Ebert <ebert@woltlab.com>
Tue, 9 Jan 2018 10:30:09 +0000 (11:30 +0100)
committerAlexander Ebert <ebert@woltlab.com>
Tue, 9 Jan 2018 10:30:09 +0000 (11:30 +0100)
The parsed smilies are already semi-immutable during the request
lifetime and especially the ordering by lenght via `mb_strlen()` is an
expensive operation. Using a static runtime cache improves the
performance when rebuilding messages in bulk, reducing the time by up to
40%.

We should backport this to 3.0 once it has proven to be stable,
especially changing the `$smilies` property into a static variable can
break derived classes.

wcfsetup/install/files/lib/system/html/input/node/HtmlInputNodeTextParser.class.php

index 8ea4f1024ead66bc3c9dcb0cba46cd604e7ab791..5554dbc427f5bfe5759cab5bf9db47c3f50011c0 100644 (file)
@@ -43,12 +43,6 @@ class HtmlInputNodeTextParser {
         */
        protected $smileyCount = 0;
        
-       /**
-        * list of smilies by smiley code
-        * @var Smiley[]
-        */
-       protected $smilies = [];
-       
        /**
         * @var string[]
         */
@@ -60,6 +54,12 @@ class HtmlInputNodeTextParser {
         */
        protected static $illegalChars = '[^\x0-\x2C\x2E\x2F\x3A-\x40\x5B-\x60\x7B-\x7F]+';
        
+       /**
+        * list of smilies by smiley code
+        * @var Smiley[]
+        */
+       protected static $smilies;
+       
        /**
         * regex for user mentions
         * @var string
@@ -91,34 +91,40 @@ class HtmlInputNodeTextParser {
                if (MODULE_SMILEY) {
                        $this->smileyCount = $smileyCount;
                        
-                       // get smilies
-                       $smilies = SmileyCache::getInstance()->getSmilies();
-                       $categories = SmileyCache::getInstance()->getCategories();
-                       
-                       foreach ($smilies as $categoryID => $categorySmilies) {
-                               if (!array_key_exists($categoryID ?: null, $categories) || $categories[$categoryID ?: null]->isDisabled) continue;
+                       if (self::$smilies === null) {
+                               self::$smilies = [];
                                
-                               /** @var Smiley $smiley */
-                               foreach ($categorySmilies as $smiley) {
-                                       foreach ($smiley->smileyCodes as $smileyCode) {
-                                               $this->smilies[$smileyCode] = $smiley;
-                                       }
-                               }
-                       }
-                       
-                       uksort($this->smilies, function($a, $b) {
-                               $lengthA = mb_strlen($a);
-                               $lengthB = mb_strlen($b);
+                               // get smilies
+                               $smilies = SmileyCache::getInstance()->getSmilies();
+                               $categories = SmileyCache::getInstance()->getCategories();
                                
-                               if ($lengthA < $lengthB) {
-                                       return 1;
-                               }
-                               else if ($lengthA === $lengthB) {
-                                       return 0;
+                               foreach ($smilies as $categoryID => $categorySmilies) {
+                                       if (!array_key_exists($categoryID ?: null, $categories) || $categories[$categoryID ?: null]->isDisabled) continue;
+                                       
+                                       /** @var Smiley $smiley */
+                                       foreach ($categorySmilies as $smiley) {
+                                               foreach ($smiley->smileyCodes as $smileyCode) {
+                                                       self::$smilies[$smileyCode] = $smiley;
+                                               }
+                                       }
                                }
                                
-                               return -1;
-                       });
+                               uksort(self::$smilies, function ($a, $b) {
+                                       $lengthA = mb_strlen($a);
+                                       $lengthB = mb_strlen($b);
+                                       
+                                       if ($lengthA < $lengthB) {
+                                               return 1;
+                                       }
+                                       else {
+                                               if ($lengthA === $lengthB) {
+                                                       return 0;
+                                               }
+                                       }
+                                       
+                                       return -1;
+                               });
+                       }
                }
        }
        
@@ -457,7 +463,7 @@ class HtmlInputNodeTextParser {
                                'difficult' => []
                        ];
                        
-                       foreach ($this->smilies as $smileyCode => $smiley) {
+                       foreach (self::$smilies as $smileyCode => $smiley) {
                                $smileyCode = preg_quote($smileyCode, '~');
                                
                                if (preg_match('~^\\\:.+\\\:$~', $smileyCode)) {
@@ -544,7 +550,7 @@ class HtmlInputNodeTextParser {
                                }
                                
                                $this->smileyCount++;
-                               $smiley = $this->smilies[$smileyCode];
+                               $smiley = self::$smilies[$smileyCode];
                                $element = $text->ownerDocument->createElement('img');
                                $element->setAttribute('src', $smiley->getURL());
                                $element->setAttribute('class', 'smiley');