1. 程式人生 > >PHP7.0中的寫時複製機制

PHP7.0中的寫時複製機制

LZ:PHP版本7.0

一、變數型別(資料型別)

  1. 標量型別:字串,整形,浮點型,布林型
  2. 複合型別:陣列,物件
  3. 特殊型別:資源,空

二、所需概念

  1. 引用:某一變數的別名,指向同一空間,類似給某人取外號
  2. 淺拷貝:除了第一層是另闢空間值拷貝之外,其餘層次都是引用
  3. 深拷貝:都是另闢空間進行值拷貝,都不是引用
  4. 寫時複製:發生寫的時候才會進行深拷貝

三、研究寫時複製機制

/**
 * 知識點1:寫時複製 <==> 在必要的時候才會進行深拷貝(即發生寫的時候才會進行深拷貝)
 * 知識點2:在PHP中並不是所有的資料型別都可通過value賦值就可以進行深拷貝,比如物件、資源就無法
 * 知識點3:好處:因為只讀共享,寫時分離(即只讀類似使用引用,寫時取消引用,並建立新的指向),所以可提升效率
 */


/**
 * @return int 1 測試字串賦值是否是寫時複製
 *
 */
function test_string(): int {
    $s_origin = 'origin';
    $s_deep_copy = $s_origin;
    $s_origin .= 'copy';
    if ($s_origin !== $s_deep_copy){
        var_dump($s_origin, $s_deep_copy);
        return 1;
    }
    return 0;
}

/**
 * @return int 1 測試整型、浮點型、布林賦值是否是寫時複製
 */
function test_int_float_bool($origin, $chg_origin): int {
    $deep_copy = $origin;
    $origin = $chg_origin;
    if ($origin !== $deep_copy){
        var_dump($origin, $deep_copy);
        return 1;
    }
    return 0;
}

/**
 * @return int 1 測試陣列賦值是否是寫時複製
 */
function test_array(): int {
    $arr_origin = array();
    $arr_deep_copy = $arr_origin;
    array_push($arr_origin, 1);
    if ($arr_origin !== $arr_deep_copy){
        var_dump($arr_origin, $arr_deep_copy);
        return 1;
    }
    return 0;
}

/**
 * Class A 測試物件賦值是否是寫時複製
 */
class A
{
    public $b;
    public function test_object(): int {
        $object_origin = new self();
        $object_deep_copy_1 = $object_origin; //嘗試賦值 進行深拷貝
        $object_deep_copy_2 = clone $object_deep_copy_1; //嘗試語言結構clone 進行深拷貝
        $object_origin->b = 2;
        var_dump($object_origin->b, $object_deep_copy_1->b, $object_deep_copy_2->b); //只有clone 才進行深拷貝
        if (($object_origin !== $object_deep_copy_1) && $object_origin !== $object_deep_copy_2){
            return 1;
        }
        return 0;
    }
}

function test_resource(){
    $tmp_file_name = './test.txt';
    $file_handler = fopen($tmp_file_name, 'w');
    $file_handler_deep_copy = $file_handler;
    fwrite($file_handler, '哈哈');
    var_dump($file_handler, $file_handler_deep_copy);
    if ($file_handler !== $file_handler_deep_copy){
        return 1;
    }
    fclose($file_handler);
    if (file_exists($tmp_file_name)){
        unlink($tmp_file_name);
    }
    return 0;
}

/**
 * 美化程式碼
 * @param $callback array 測試陣列
 * @param $type     array 測試型別陣列
 */
function beatiful_code($callback, $type){
    if (is_array($callback) && is_array($type) && count($callback) == count($type)){
        array_map(function ($cb_index, $tp_index){
            echo '===========' . $tp_index . '============'.PHP_EOL;
            $cb_index();
            echo '===========' . $tp_index . '============'.PHP_EOL.PHP_EOL;
        }, $callback, $type);
    }
    else{
        print_r('測試引數錯誤');
        return;
    }
}

$callback = [
    function (){
        // 字串支援寫時複製
        var_dump('返回值:'.test_string());
    },function (){
        // 整型支援寫時複製
        var_dump('返回值:'.test_int_float_bool(1, 2));
    },function (){
        // 浮點型支援寫時複製
        var_dump('返回值:'.test_int_float_bool(1.1, 2.1));
    },function (){
        // 浮點型支援寫時複製
        var_dump('返回值:'.test_int_float_bool(true, false));
    },function (){
        // 陣列支援寫時複製
        var_dump('返回值:'.test_array());
    },function (){
        // 物件不支援寫時複製
        var_dump('返回值:'.(new A())->test_object());
    },function (){
        // 資源型別不支援寫時複製
        var_dump('返回值:'.test_resource());
    }
];

$type = [
    'string', 'int', 'float', 'bool', 'array', 'object', 'resource'
];

beatiful_code($callback, $type);

/* result:
    ===========string============
    string(10) "origincopy"
    string(6) "origin"
    string(13) "返回值:1"
    ===========string============
    
    ===========int============
    int(2)
    int(1)
    string(13) "返回值:1"
    ===========int============
    
    ===========float============
    float(2.1)
    float(1.1)
    string(13) "返回值:1"
    ===========float============
    
    ===========bool============
    bool(false)
    bool(true)
    string(13) "返回值:1"
    ===========bool============
    
    ===========array============
    array(1) {
      [0]=>
      int(1)
    }
    array(0) {
    }
    string(13) "返回值:1"
    ===========array============
    
    ===========object============
    int(2)
    int(2)
    NULL
    string(13) "返回值:0"
    ===========object============
    
    ===========resource============
    resource(5) of type (stream)
    resource(5) of type (stream)
    string(13) "返回值:0"
    ===========resource============

*/

// 由此可以看出,PHP7.0版本除了物件、資源之外,其餘資料型別均已實現寫時複製

四、結論

PHP7.0版本除了物件,資源之外,其餘資料型別均已實現寫時複製

五、型別轉換

1、自動型別轉換

$a = '100' + 200; //字串自動轉化成整型
print_r($a);

2、強制型別轉換

(string):轉化為字串
(int)(integer):轉化為整型
(float)(double)(real):轉化為浮點型float
(bool)(boolean):轉化為布林型
(array):轉化為陣列
(object):轉化為物件
(unset):轉化為null