PHP的substr函数效率如何?

10

我正在使用PHP编写一个解析器,必须能够处理大型内存字符串,因此这是一个相当重要的问题。(也就是说,请不要“过早优化”抨击我,请)

substr函数如何工作?它是否会在内存中创建第二个字符串数据副本,还是只是引用原始字符串?我应该担心在循环中调用$str = substr($str, 1); 这样的函数吗?


2
我认为赋值操作才是致命的,而不是字符串截取。 - CaffGeek
FFI 扩展可能有所帮助,但需要在 php.ini 中启用。 - Jan Turoň
3个回答

4
如果你真的想提高效率,需要在字符串中保留一个指针(也就是索引)。许多字符串函数接受一个偏移量来开始操作(例如strpos()的第三个参数)。通常我会建议编写一个对象来封装这个功能,但如果你期望经常使用它,那可能会造成性能瓶颈。以下是一个没有面向对象的示例:
while ($whatever) {
    $pos = strpos($string, $myToken, $startIndex);
    # do something using $pos
    $startIndex = $pos;
}

如果您想的话,可以编写自己的包装类来执行这些字符串操作,并查看是否有速度影响:
class _String {
    private $string;
    private $startIndex;
    private $length;
    public function __construct($string) {
        $this->string = $string;
        $this->startIndex = 0;
        $this->length = strlen($string);
    }
    public function substr($from, $length = NULL) {
        $this->startIndex = $from;
        if ($length !== NULL) {
            $this->endIndex = $from + $length;
        }
    }
    # other functions you might use
    # ...
}

普通的Java字符串可以自动完成这些操作,为什么PHP不能呢? - Pacerier

3

进一步回应Chad的评论,您的代码需要同时在内存中存储两个字符串(完整的字符串和去掉第一个字符的完整字符串)(尽管不是由于Chad所述的赋值)。请参见:

$string = str_repeat('x', 1048576);
printf("MEM:  %d\nPEAK: %d\n", memory_get_usage(), memory_get_peak_usage());

substr($string, 1);
printf("MEM:  %d\nPEAK: %d  :-(\n", memory_get_usage(), memory_get_peak_usage());

$string = substr($string, 1);
printf("MEM:  %d\nPEAK: %d  :-(\n", memory_get_usage(), memory_get_peak_usage());

输出结果大致如下(内存值以字节为单位):

MEM:  1093256
PEAK: 1093488
MEM:  1093280
PEAK: 2142116  :-(
MEM:  1093276
PEAK: 2142116  :-(

2

是的,在循环中进行任何字符串操作时,应该小心,因为每次迭代都会生成新的字符串副本。


1
我不是 PHP 方面的专家,所以你可能只需简单地说“不行”。在 Java 中,它仅会创建对同一不可变字符数组的新引用。因此,虽然它会创建一个新的 String 对象,但它不会存储底层字符数组的更多副本。它只是声明偏移量不同而已。PHP 是否实际上会创建字符数组的新副本?还是只是引用同一字符数组? - corsiKa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接