isset() vs strlen() - a fast/clear string length c

2019-01-16 13:31发布

I came across this code...

if(isset($string[255])) {
    // too long
}

isset() is between 6 and 40 faster than

if(strlen($string) > 255) {
    // too long
}

The only drawback to the isset() is that the code is unclear - we cannot tell right away what is being done (see pekka's answer). We can wrap isset() within a function i.e. strlt($string,255) but we then loose the speed benefits of isset().

How can we use the faster isset() function while retaining readability of the code?

EDIT : test to show the speed http://codepad.org/ztYF0bE3

strlen() over 1000000 iterations 7.5193998813629
isset() over 1000000 iterations 0.29940009117126

EDIT2 : here's why isset() is faster

$string = 'abcdefg';
var_dump($string[2]);
Output: string(1) “c”

$string = 'abcdefg';
if (isset($string[7])){
     echo $string[7].' found!';
  }else{
     echo 'No character found at position 7!';
}

This is faster than using strlen() because, “… calling a function is more expensive than using a language construct.” http://www.phpreferencebook.com/tips/use-isset-instead-of-strlen/

EDIT3 : I was always taught to be interested in mirco-optimisation. Probably because I was taught at a time when resources on computers were tiny. I'm open to the idea that it may not be important, there are some good arguments against it in the answers. I've started a new question exploring this... https://stackoverflow.com/questions/6983208/is-micro-optimisation-important-when-coding

8条回答
Viruses.
2楼-- · 2019-01-16 14:23

In modern ObjectOriented Web Applications a single line that you write within a small Class easily can be run several 100s of times to build a single Web Page.
You might want to profile your Web Site with XDebug and you might be surprised how many times each Method of a Class is executed.
Then in real world scenarios you might not work only with little strings but also with really big documents up to 3MB size or larger.
You might also come across text with non latin characters.
So eventually what was initially just a little performance loss might result in serveral 100s of milliseconds on a Web Page Rendering.

So I am very interested in this issue and wrote a little test that would test 4 different Methods to check whether a string is really empty "" or does actually contain something like "0".

function stringCheckNonEmpty0($string)
{
  return (empty($string));
}

function stringCheckNonEmpty1($string)
{
  return (strlen($string) > 0);
}

function stringCheckNonEmpty1_2($string)
{
  return (mb_strlen($string) > 0);
}

function stringCheckNonEmpty2($string)
{
  return ($string !== "");
}

function stringCheckNonEmpty3($string)
{
  return (isset($string[0]));
}

I found that PHP as a hard time to work with non latin characters to I copied a russian text from a Web Page to compare the results between the tiny string "0" and the bigger russian text.

$steststring = "0";

$steststring2 = "Hotel Majestic в городе Касабланка располагается всего в нескольких минутах от "
  . "следующих достопримечательностей и объектов: "
  . "Playas Ain Diab y La Corniche и Центральный рынок Касабланки. "
  . "Этот отель находится вблизи следующих достопримечательностей и объектов: "
  . "Площадь Мухаммеда V и Культурный комплекс Сиди-Бельот.";

To see really a difference I called each test function several millions of times.

$iruncount = 10000000;

echo "test: empty(\"0\"): starting ...\n";

$tmtest = 0;
$tmteststart = microtime(true);
$tmtestend = 0;

for($irun = 0; $irun < $iruncount; $irun++)
  stringCheckNonEmpty0($steststring);

$tmtestend = microtime(true);
$tmtest = $tmtestend - $tmteststart;

echo "test: empty(\"0\"): '$tmtest' s\n";

Test Results

$ php test_string_check.php
test0.1: empty("0"): starting ...
test0.1: empty("0"): '7.0262970924377' s
test0.2: empty(russian): starting ...
test0.2: empty(russian): '7.2237210273743' s
test1.1.1: strlen("0"): starting ...
test1.1.1: strlen("0"): '11.045154094696' s
test1.1.2: strlen(russian): starting ...
test1.1.2: strlen(russian): '11.106546878815' s
test1.2.1: mb_strlen("0"): starting ...
test1.2.1: mb_strlen("0"): '11.320801019669' s
test1.2.2: mb_strlen(russian): starting ...
test1.2.2: mb_strlen(russian): '23.082058906555' s
test2.1: ("0" !== ""): starting ...
test2.1: ("0" !== ""): '7.0292129516602' s
test2.2: (russian !== ""): starting ...
test2.2: (russian !== ""): '7.1041729450226' s
test3.1: isset(): starting ...
test3.1: isset(): '6.9401099681854' s
test3.2: isset(russian): starting ...
test3.2: isset(russian): '6.927631855011' s

$ php test_string_check.php
test0.1: empty("0"): starting ...
test0.1: empty("0"): '7.0895299911499' s
test0.2: empty(russian): starting ...
test0.2: empty(russian): '7.3135821819305' s
test1.1.1: strlen("0"): starting ...
test1.1.1: strlen("0"): '11.265664100647' s
test1.1.2: strlen(russian): starting ...
test1.1.2: strlen(russian): '11.282053947449' s
test1.2.1: mb_strlen("0"): starting ...
test1.2.1: mb_strlen("0"): '11.702164888382' s
test1.2.2: mb_strlen(russian): starting ...
test1.2.2: mb_strlen(russian): '23.758249998093' s
test2.1: ("0" !== ""): starting ...
test2.1: ("0" !== ""): '7.2174110412598' s
test2.2: (russian !== ""): starting ...
test2.2: (russian !== ""): '7.240779876709' s
test3.1: isset("0"): starting ...
test3.1: isset("0"): '7.2104151248932' s
test3.2: isset(russian): starting ...
test3.2: isset(russian): '7.2232971191406' s

Conclusion

  • The conventional emtpy() Function performs well but fails on strings like "0".
  • The mb_strlen() Function which is necessary to check on texts with non latin characters performs worse on larger texts.
  • The Check $string !== "" performs very well. Even better than the empty() Function.
  • But the best Performance gives the isset($string[0]) Check.

I will definitely have to work over my whole Object Library.

查看更多
做自己的国王
3楼-- · 2019-01-16 14:28

If you want to keep clarity you could do something like:

function checklength(&$str, $len)
{
     return isset($str[$len]);
}
查看更多
登录 后发表回答