Open3
substr vs str_starts_with
substr vs str_starts_with
先頭一文字目だけの比較をするとき、 substr($string, 0, 1) === "s" とか書くのですが、 str_starts_with -- php.net というメソッドもあって、どっちの方がパフォーマンスがいいのかチェック。
substr_vs_str_starts_with.php
<?php
function getVeryManyStrings(int $max)
{
$r = [];
for ($i = 0; $i < $max; $i++) {
$r[] = base64_encode(random_bytes(32));
}
return $r;
}
print("Generate very many strings\n");
$check1 = getVeryManyStrings(100_000_000);
print("Start !!!\n\n");
$start = microtime(true);
array_map(fn($k) => substr($k, 0, 1) === 's', $check1);
$end = microtime(true);
array_map(fn($k) => str_starts_with($k, 'k'), $check1);
$end2 = microtime(true);
print("substr is " . ($end - $start) . " sec\n");
print("str_starts_with is " . ($end2 - $end) . " sec\n");
結果
❯ php -d memory_limit=-1 substr_vs_str_starts_with.php
Generate very many strings
Start !!!
substr is 7.6892261505127 sec
str_starts_with is 6.5366988182068 sec
おまけ
正規表現を使ったとき、どうなるか。
<?php
function getVeryManyStrings(int $max)
{
$r = [];
for ($i = 0; $i < $max; $i++) {
$r[] = base64_encode(random_bytes(32));
}
return $r;
}
print("Generate very many strings\n");
$check1 = getVeryManyStrings(100_000_000);
print("Start !!!\n\n");
$start = microtime(true);
array_map(fn($k) => substr($k, 0, 1) === 's', $check1);
$end = microtime(true);
array_map(fn($k) => str_starts_with($k, 'k'), $check1);
$end2 = microtime(true);
array_map(fn($k) => preg_match('/^i/u', $k), $check1);
$end3 = microtime(true);
print("substr is " . ($end - $start) . " sec\n");
print("str_starts_with is " . ($end2 - $end) . " sec\n");
print("preg_match is " . ($end3 - $end2) . " sec\n");
結果
❯ php -d memory_limit=-1 substr_vs_str_starts_with.php
Generate very many strings
Start !!!
substr is 7.9892220497131 sec
str_starts_with is 6.3257839679718 sec
preg_match is 9.3445250988007 sec
str_starts_with の実装
ソースコードを追っかける。
RETURN_BOOL(zend_string_starts_with(haystack, needle));
→ https://github.com/php/php-src/blob/223683dfb594d3fa680c7a72b34c11e70192dbe5/Zend/zend_string.h#L408
突き詰めた所で、実態はこれ。
要は C で直接、メモリー上のバイト比較をしているので、高速に動く。
substr の実装
ZEND_ を使ってて、割りとスクリプトみたいな感じになってる。