php字符串是不可变的吗?

时间:2009-01-30 18:43:16

标签: php string

或者:我应该在PHP中优化我的字符串操作吗?我试着询问PHP的手册,但我没有得到任何提示。

6 个答案:

答案 0 :(得分:20)

PHP已经优化了它 - 变量被赋值using copy-on-write,对象通过引用传递。在PHP 4 它没有,但是无论如何都没有人应该使用PHP 4来创建新代码。

答案 1 :(得分:5)

许多语言中最基本的速度优化技术之一是实例重用。在这种情况下,速度增加至少来自两个因素:

<强> 1。实例化程度越低意味着在构建上花费的时间越少。

<强> 2。应用程序使用的内存量越少,可能的CPU cache misses就越少。

对于速度为#1优先级的应用程序,CPU和RAM之间存在真正严重的瓶颈。瓶颈的原因之一是RAM的延迟。

PHP,Ruby,Python等与缓存缺失有关,即使它们至少存储了RAM中解释程序的一些(可能是全部)运行时数据。

字符串实例化是经常以相对“大量”完成的操作之一,它可能对速度产生明显的影响。

以下是测量实验的run_test.bash:

#!/bin/bash

for i in `seq 1 200`;
do
        /usr/bin/time -p -a -o ./measuring_data.rb  php5 ./string_instantiation_speedtest.php
done

以下是./string_instantiation_speedtest.php和测量结果:

<?php

// The comments on the
// next 2 lines show arithmetic mean of (user time + sys time) for 200 runs.
$b_instantiate=False; // 0.1624 seconds
$b_instantiate=True;  // 0.1676 seconds
// The time consumed by the reference version is about 97% of the
// time consumed by the instantiation version, but a thing to notice is
// that the loop contains at least 1, probably 2, possibly 4,
// string instantiations at the array_push line.
$ar=array();
$s='This is a string.';
$n=10000;
$s_1=NULL;

for($i=0;$i<$n;$i++) {
    if($b_instantiate) {
        $s_1=''.$s;
    } else {
        $s_1=&$s;
    }
    // The rand is for avoiding optimization at storage.
    array_push($ar,''.rand(0,9).$s_1);
} // for

echo($ar[rand(0,$n)]."\n");

?>

我从这个实验得到的结论以及我在Ruby 1.8中做的另一个实验是,通过引用传递字符串值是有意义的。

在整个应用程序范围内允许“按引用传递字符串”的一种可能方法是,只要需要使用字符串的修改版本,就可以始终如一地创建新的字符串实例。

为了增加位置,因此增加速度,可能希望减少每个操作数消耗的内存量。以下实验演示了字符串连接的情况:

<?php

// The comments on the
// next 2 lines show arithmetic mean of (user time + sys time) for 200 runs.
$b_suboptimal=False; // 0.0611 seconds
$b_suboptimal=True;  // 0.0785 seconds
// The time consumed by the optimal version is about 78% of the
// time consumed by the suboptimal version.
//
// The number of concatenations is the same and the resultant
// string is the same, but what differs is the "average" and maximum
// lengths  of the tokens that are used for assembling the $s_whole.
$n=1000;
$s_token="This is a string with a Linux line break.\n";
$s_whole='';

if($b_suboptimal) {
    for($i=0;$i<$n;$i++) {
        $s_whole=$s_whole.$s_token.$i;
    } // for
} else {
    $i_watershed=(int)round((($n*1.0)/2),0);
    $s_part_1='';
    $s_part_2='';
    for($i=0;$i<$i_watershed;$i++) {
        $s_part_1=$s_part_1.$i.$s_token;
    } // for
    for($i=$i_watershed;$i<$n;$i++) {
        $s_part_2=$s_part_2.$i.$s_token;
    } // for
    $s_whole=$s_part_1.$s_part_2;
} // else

// To circumvent possible optimization one actually "uses" the
// value of the $s_whole.
$file_handle=fopen('./it_might_have_been_a_served_HTML_page.txt','w');
fwrite($file_handle, $s_whole);
fclose($file_handle);

?>

例如,如果一个人组装包含大量文本的HTML页面,那么人们可能想要考虑顺序,生成的HTML的不同部分如何连接在一起。

可获得BSD许可的PHP implementationRuby implementation分水岭字符串连接算法。相同的算法可以(已经由我)推广以加速任意精度整数的乘法。

答案 2 :(得分:3)

快速google似乎暗示它们是可变的,但首选的做法是将它们视为不可变的。

答案 3 :(得分:2)

数组和字符串具有写时复制行为。它们是可变的,但是当你最初将它们分配给变量时,变量将包含完全相同的字符串或数组实例。只有在修改数组或字符串时才会制作副本。

示例:

$a = array_fill(0, 10000, 42);  //Consumes 545744 bytes
$b = $a;                        //   "         48   "
$b[0] = 42;                     //   "     545656   "

$s = str_repeat(' ', 10000);    //   "      10096   "
$t = $s;                        //   "         48   "
$t[0] = '!';                    //   "      10048   "

答案 4 :(得分:0)

PHP 7.4使用了可变字符串:

<?php
$str = "Hello\n";
echo $str;
$str[2] = 'y';
echo $str;

输出:

Hello
Heylo

测试:PHP Sandbox

答案 5 :(得分:-3)

PHP字符串是不可变的。

试试这个:

    $a="string";
    echo "<br>$a<br>";
    echo str_replace('str','b',$a);
    echo "<br>$a";

回声:

string
bing
string

如果字符串是可变的,它将继续显示“bing”。