[TASK] Improve revExplode performance 55/27255/5
authorAndreas Wolf <andreas.wolf@typo3.org>
Sat, 1 Feb 2014 18:50:18 +0000 (19:50 +0100)
committerAnja Leichsenring <aleichsenring@ab-softlab.de>
Sun, 9 Feb 2014 14:05:05 +0000 (15:05 +0100)
``GeneralUtility::revExplode()`` is implemented in a very
performance-intensive way: it always does a complete cycle with multiple
array operations, be it necessary or not.

To make the method more performant, it is split into different cases.
Currently, the only used value for the ``$count`` in the core is 2, but
we have to implement all others, too, of course. The performance
increase for $count=2 is greater than 50%; the others will at maximum be
as bad as the old implementation, plus a very tiny overhead for checking
the value of ``$count``.

Change-Id: I79d9a87b790935415c636ee87e6a6db952e0baa4
Resolves: #55564
Releases: 6.2
Reviewed-on: https://review.typo3.org/27255
Reviewed-by: Christian Kuhn
Tested-by: Christian Kuhn
Reviewed-by: Anja Leichsenring
Tested-by: Anja Leichsenring
typo3/sysext/core/Classes/Utility/GeneralUtility.php
typo3/sysext/core/Tests/Unit/Utility/GeneralUtilityTest.php

index 61d67ec..7f09d06 100644 (file)
@@ -1483,9 +1483,17 @@ class GeneralUtility {
         * @return array Exploded values
         */
        static public function revExplode($delimiter, $string, $count = 0) {
-               $explodedValues = explode($delimiter, strrev($string), $count);
-               $explodedValues = array_map('strrev', $explodedValues);
-               return array_reverse($explodedValues);
+               // 2 is the (currently, as of 2014-02) most-used value for $count in the core, therefore we check it first
+               if ($count === 2) {
+                       $position = strrpos($string, $delimiter);
+                       return array(substr($string, 0, $position), substr($string, $position + 1));
+               } else if ($count <= 1) {
+                       return array($string);
+               } else {
+                       $explodedValues = explode($delimiter, strrev($string), $count);
+                       $explodedValues = array_map('strrev', $explodedValues);
+                       return array_reverse($explodedValues);
+               }
        }
 
        /**
index 46603dc..78f3014 100644 (file)
@@ -1351,13 +1351,48 @@ class GeneralUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
        //////////////////////////////////
        // Tests concerning revExplode
        //////////////////////////////////
+
+       public function revExplodeDataProvider() {
+               return array(
+                       'limit 0 should return unexploded string' => array(
+                               'my:words:here',
+                               0,
+                               array('my:words:here')
+                       ),
+                       'limit 1 should return unexploded string' => array(
+                               'my:words:here',
+                               1,
+                               array('my:words:here')
+                       ),
+                       'limit 2 should return two pieces' => array(
+                               'my:words:here',
+                               2,
+                               array('my:words', 'here')
+                       ),
+                       'limit 3 should return unexploded string' => array(
+                               'my:words:here',
+                               3,
+                               array('my', 'words', 'here')
+                       ),
+               );
+       }
+
+       /**
+        * @test
+        * @dataProvider revExplodeDataProvider
+        */
+       public function revExplodeCorrectlyExplodesStringForGivenPartsCount($testString, $count, $expectedArray) {
+               $actualArray = Utility\GeneralUtility::revExplode(':', $testString, $count);
+               $this->assertEquals($expectedArray, $actualArray);
+       }
+
        /**
         * @test
         */
-       public function revExplodeExplodesString() {
-               $testString = 'my:words:here';
-               $expectedArray = array('my:words', 'here');
-               $actualArray = Utility\GeneralUtility::revExplode(':', $testString, 2);
+       public function revExplodeRespectsLimitThreeWhenExploding() {
+               $testString = 'even:more:of:my:words:here';
+               $expectedArray = array('even:more:of:my', 'words', 'here');
+               $actualArray = Utility\GeneralUtility::revExplode(':', $testString, 3);
                $this->assertEquals($expectedArray, $actualArray);
        }