Mảng bất biến PHP

Để làm việc với zval một cách chính xác và hiệu quả, điều quan trọng là phải hiểu cách quản lý bộ nhớ của chúng hoạt động. Nhìn chung, chúng ta có thể phân loại các giá trị thành hai loại. Các giá trị đơn giản như số nguyên, được lưu trữ trực tiếp bên trong zval và các giá trị phức tạp như chuỗi, mà zval chỉ lưu trữ một con trỏ tới một cấu trúc riêng biệt

Quản lý bộ nhớ Zval

Với phần sơ bộ đã sẵn sàng, chúng ta có thể thảo luận về cách quản lý bộ nhớ tương tác với zvals. Các cấu trúc được đếm lại có thể được sử dụng độc lập, nhưng lưu trữ chúng bên trong các zval chắc chắn là một trong những trường hợp sử dụng phổ biến hơn

Bản thân các Zvals không bao giờ được phân bổ theo từng đống riêng lẻ. Chúng được phân bổ tạm thời trên ngăn xếp hoặc được nhúng như một phần của cấu trúc phân bổ heap lớn hơn

Ví dụ cơ bản này cho thấy quá trình khởi tạo zval được cấp phát theo ngăn xếp và quá trình hủy sau đó của nó

zval str_val;
ZVAL_STRING(&str_val, "foo"); // Creates zend_string (refcount=1).
// .. Do something with str_val.
zval_ptr_dtor(&str_val); // Decrements to refcount=0, and destroys the string.

void fill_array(zval *array) {
    zval val;
    init_zval(&val);

    // Manually check REFCOUNTED:
    if (Z_REFCOUNTED(val)) {
        Z_ADDREF(val);
    }
    add_index_zval(array, 0, &val);

    // Or use the TRY macro:
    Z_TRY_ADDREF(val);
    add_index_zval(array, 1, &val);

    zval_ptr_dtor(&val);
}
0 tạo một chuỗi zval và
void fill_array(zval *array) {
    zval val;
    init_zval(&val);

    // Manually check REFCOUNTED:
    if (Z_REFCOUNTED(val)) {
        Z_ADDREF(val);
    }
    add_index_zval(array, 0, &val);

    // Or use the TRY macro:
    Z_TRY_ADDREF(val);
    add_index_zval(array, 1, &val);

    zval_ptr_dtor(&val);
}
1 giải phóng nó. Chúng ta sẽ thảo luận về các macro khởi tạo và hàm hủy khác nhau trong giây lát

Một zval được cấp phát ngăn xếp chỉ có thể được sử dụng trong phạm vi mà nó đã được khai báo trong. Mặc dù về mặt kỹ thuật có thể trả về một

void fill_array(zval *array) {
    zval val;
    init_zval(&val);

    // Manually check REFCOUNTED:
    if (Z_REFCOUNTED(val)) {
        Z_ADDREF(val);
    }
    add_index_zval(array, 0, &val);

    // Or use the TRY macro:
    Z_TRY_ADDREF(val);
    add_index_zval(array, 1, &val);

    zval_ptr_dtor(&val);
}
2, nhưng bạn sẽ thấy rằng PHP không bao giờ chuyển hoặc trả về zval theo giá trị. Thay vào đó, zvals luôn được truyền bởi con trỏ. Để trả về một zval, một tham số ngoài cần được chuyển đến hàm

// retval is an output parameter.
void init_zval(zval *retval) {
    ZVAL_STRING(retval, "foo");
}

void some_other_function() {
    zval val;
    init_zval(&val);
    // .. Do something with val.
    zval_ptr_dtor(&val);
}

Mặc dù bản thân các zval thường không được chia sẻ, nhưng có thể chia sẻ các cấu trúc mà chúng chỉ ra bằng cách sử dụng cơ chế đếm lại. Các macro

void fill_array(zval *array) {
    zval val;
    init_zval(&val);

    // Manually check REFCOUNTED:
    if (Z_REFCOUNTED(val)) {
        Z_ADDREF(val);
    }
    add_index_zval(array, 0, &val);

    // Or use the TRY macro:
    Z_TRY_ADDREF(val);
    add_index_zval(array, 1, &val);

    zval_ptr_dtor(&val);
}
3,
void fill_array(zval *array) {
    zval val;
    init_zval(&val);

    // Manually check REFCOUNTED:
    if (Z_REFCOUNTED(val)) {
        Z_ADDREF(val);
    }
    add_index_zval(array, 0, &val);

    // Or use the TRY macro:
    Z_TRY_ADDREF(val);
    add_index_zval(array, 1, &val);

    zval_ptr_dtor(&val);
}
4 và
void fill_array(zval *array) {
    zval val;
    init_zval(&val);

    // Manually check REFCOUNTED:
    if (Z_REFCOUNTED(val)) {
        Z_ADDREF(val);
    }
    add_index_zval(array, 0, &val);

    // Or use the TRY macro:
    Z_TRY_ADDREF(val);
    add_index_zval(array, 1, &val);

    zval_ptr_dtor(&val);
}
5 hoạt động giống như các macro
void fill_array(zval *array) {
    zval val;
    init_zval(&val);

    // Manually check REFCOUNTED:
    if (Z_REFCOUNTED(val)) {
        Z_ADDREF(val);
    }
    add_index_zval(array, 0, &val);

    // Or use the TRY macro:
    Z_TRY_ADDREF(val);
    add_index_zval(array, 1, &val);

    zval_ptr_dtor(&val);
}
6 tương ứng, nhưng hoạt động trên các zval. Điều quan trọng là, các macro này chỉ có thể được sử dụng nếu zval trỏ đến cấu trúc được đếm lại và cấu trúc không phải là bất biến. Cờ loại
void fill_array(zval *array) {
    zval val;
    init_zval(&val);

    // Manually check REFCOUNTED:
    if (Z_REFCOUNTED(val)) {
        Z_ADDREF(val);
    }
    add_index_zval(array, 0, &val);

    // Or use the TRY macro:
    Z_TRY_ADDREF(val);
    add_index_zval(array, 1, &val);

    zval_ptr_dtor(&val);
}
7 xác định xem đây có phải là trường hợp hay không và có thể được truy cập thông qua
void fill_array(zval *array) {
    zval val;
    init_zval(&val);

    // Manually check REFCOUNTED:
    if (Z_REFCOUNTED(val)) {
        Z_ADDREF(val);
    }
    add_index_zval(array, 0, &val);

    // Or use the TRY macro:
    Z_TRY_ADDREF(val);
    add_index_zval(array, 1, &val);

    zval_ptr_dtor(&val);
}
8

void fill_array(zval *array) {
    zval val;
    init_zval(&val);

    // Manually check REFCOUNTED:
    if (Z_REFCOUNTED(val)) {
        Z_ADDREF(val);
    }
    add_index_zval(array, 0, &val);

    // Or use the TRY macro:
    Z_TRY_ADDREF(val);
    add_index_zval(array, 1, &val);

    zval_ptr_dtor(&val);
}

Ví dụ này thêm cùng một giá trị vào một mảng hai lần, điều đó có nghĩa là số lần truy cập phải được tăng lên hai lần. Mặc dù có thể kiểm tra thủ công xem zval có phải là

void fill_array(zval *array) {
    zval val;
    init_zval(&val);

    // Manually check REFCOUNTED:
    if (Z_REFCOUNTED(val)) {
        Z_ADDREF(val);
    }
    add_index_zval(array, 0, &val);

    // Or use the TRY macro:
    Z_TRY_ADDREF(val);
    add_index_zval(array, 1, &val);

    zval_ptr_dtor(&val);
}
8 hay không, nhưng thay vào đó, nên sử dụng
void fill_array(zval *array) {
    zval val;
    init_zval(&val);

    // Manually check REFCOUNTED:
    if (Z_REFCOUNTED(val)) {
        Z_ADDREF(val);
    }
    add_index_zval(array, 0, &val);

    // Or use the TRY macro:
    Z_TRY_ADDREF(val);
    add_index_zval(array, 1, &val);

    zval_ptr_dtor(&val);
}
30, điều này chỉ làm tăng số lần đếm lại cho các cấu trúc được đếm lại

Một điều cần xem xét ở đây là ai chịu trách nhiệm tăng số lần đếm lại. Trong ví dụ này, người gọi của

void fill_array(zval *array) {
    zval val;
    init_zval(&val);

    // Manually check REFCOUNTED:
    if (Z_REFCOUNTED(val)) {
        Z_ADDREF(val);
    }
    add_index_zval(array, 0, &val);

    // Or use the TRY macro:
    Z_TRY_ADDREF(val);
    add_index_zval(array, 1, &val);

    zval_ptr_dtor(&val);
}
31 chịu trách nhiệm tăng. Thật không may, các API PHP không nhất quán về vấn đề này. Theo nguyên tắc chung, các giá trị mảng mong muốn số lần truy cập sẽ được tăng lên bởi người gọi, trong khi hầu hết các API khác sẽ tự xử lý nó

Sao chép zvals

Thông thường, các zval cần được sao chép từ vị trí này sang vị trí khác. Với mục đích này, một số macro sao chép được cung cấp. Đầu tiên là

void fill_array(zval *array) {
    zval val;
    init_zval(&val);

    // Manually check REFCOUNTED:
    if (Z_REFCOUNTED(val)) {
        Z_ADDREF(val);
    }
    add_index_zval(array, 0, &val);

    // Or use the TRY macro:
    Z_TRY_ADDREF(val);
    add_index_zval(array, 1, &val);

    zval_ptr_dtor(&val);
}
32

void fill_array(zval *array) {
    zval val;
    init_zval(&val);

    // Manually check REFCOUNTED:
    if (Z_REFCOUNTED(val)) {
        Z_ADDREF(val);
    }
    add_index_zval(array, 0, &val);

    // Or use the TRY macro:
    Z_TRY_ADDREF(val);
    add_index_zval(array, 1, &val);

    zval_ptr_dtor(&val);
}
3

Ví dụ (khá ngớ ngẩn) này khởi tạo một ngăn xếp zval và sau đó chuyển giá trị sang tham số

void fill_array(zval *array) {
    zval val;
    init_zval(&val);

    // Manually check REFCOUNTED:
    if (Z_REFCOUNTED(val)) {
        Z_ADDREF(val);
    }
    add_index_zval(array, 0, &val);

    // Or use the TRY macro:
    Z_TRY_ADDREF(val);
    add_index_zval(array, 1, &val);

    zval_ptr_dtor(&val);
}
33 out. Macro
void fill_array(zval *array) {
    zval val;
    init_zval(&val);

    // Manually check REFCOUNTED:
    if (Z_REFCOUNTED(val)) {
        Z_ADDREF(val);
    }
    add_index_zval(array, 0, &val);

    // Or use the TRY macro:
    Z_TRY_ADDREF(val);
    add_index_zval(array, 1, &val);

    zval_ptr_dtor(&val);
}
34 thực hiện một bản sao zval đơn giản mà không cần tăng số lượng truy cập lại. Như vậy, cách sử dụng chính của nó là di chuyển một zval, có nghĩa là zval ban đầu sẽ không còn được sử dụng nữa (bao gồm cả việc nó không được hủy). Đôi khi, macro này cũng được sử dụng như một cách tối ưu hóa để sao chép một zval mà chúng tôi biết là không được tính lại

Macro

void fill_array(zval *array) {
    zval val;
    init_zval(&val);

    // Manually check REFCOUNTED:
    if (Z_REFCOUNTED(val)) {
        Z_ADDREF(val);
    }
    add_index_zval(array, 0, &val);

    // Or use the TRY macro:
    Z_TRY_ADDREF(val);
    add_index_zval(array, 1, &val);

    zval_ptr_dtor(&val);
}
34 khác với nhiệm vụ đơn giản (
void fill_array(zval *array) {
    zval val;
    init_zval(&val);

    // Manually check REFCOUNTED:
    if (Z_REFCOUNTED(val)) {
        Z_ADDREF(val);
    }
    add_index_zval(array, 0, &val);

    // Or use the TRY macro:
    Z_TRY_ADDREF(val);
    add_index_zval(array, 1, &val);

    zval_ptr_dtor(&val);
}
36) ở chỗ nó chỉ sao chép giá trị và loại zval chứ không sao chép thành viên
void fill_array(zval *array) {
    zval val;
    init_zval(&val);

    // Manually check REFCOUNTED:
    if (Z_REFCOUNTED(val)) {
        Z_ADDREF(val);
    }
    add_index_zval(array, 0, &val);

    // Or use the TRY macro:
    Z_TRY_ADDREF(val);
    add_index_zval(array, 1, &val);

    zval_ptr_dtor(&val);
}
37 của nó. Như vậy, việc
void fill_array(zval *array) {
    zval val;
    init_zval(&val);

    // Manually check REFCOUNTED:
    if (Z_REFCOUNTED(val)) {
        Z_ADDREF(val);
    }
    add_index_zval(array, 0, &val);

    // Or use the TRY macro:
    Z_TRY_ADDREF(val);
    add_index_zval(array, 1, &val);

    zval_ptr_dtor(&val);
}
34 vào một zval có thành viên
void fill_array(zval *array) {
    zval val;
    init_zval(&val);

    // Manually check REFCOUNTED:
    if (Z_REFCOUNTED(val)) {
        Z_ADDREF(val);
    }
    add_index_zval(array, 0, &val);

    // Or use the TRY macro:
    Z_TRY_ADDREF(val);
    add_index_zval(array, 1, &val);

    zval_ptr_dtor(&val);
}
37 đang được sử dụng là an toàn, vì nó sẽ không bị ghi đè

Macro thứ hai là

void fill_array(zval *array) {
    zval val;
    init_zval(&val);

    // Manually check REFCOUNTED:
    if (Z_REFCOUNTED(val)) {
        Z_ADDREF(val);
    }
    add_index_zval(array, 0, &val);

    // Or use the TRY macro:
    Z_TRY_ADDREF(val);
    add_index_zval(array, 1, &val);

    zval_ptr_dtor(&val);
}
40, là sự kết hợp tối ưu của
void fill_array(zval *array) {
    zval val;
    init_zval(&val);

    // Manually check REFCOUNTED:
    if (Z_REFCOUNTED(val)) {
        Z_ADDREF(val);
    }
    add_index_zval(array, 0, &val);

    // Or use the TRY macro:
    Z_TRY_ADDREF(val);
    add_index_zval(array, 1, &val);

    zval_ptr_dtor(&val);
}
34 và
void fill_array(zval *array) {
    zval val;
    init_zval(&val);

    // Manually check REFCOUNTED:
    if (Z_REFCOUNTED(val)) {
        Z_ADDREF(val);
    }
    add_index_zval(array, 0, &val);

    // Or use the TRY macro:
    Z_TRY_ADDREF(val);
    add_index_zval(array, 1, &val);

    zval_ptr_dtor(&val);
}
30

void fill_array(zval *array) {
    zval val;
    init_zval(&val);

    // Manually check REFCOUNTED:
    if (Z_REFCOUNTED(val)) {
        Z_ADDREF(val);
    }
    add_index_zval(array, 0, &val);

    // Or use the TRY macro:
    Z_TRY_ADDREF(val);
    add_index_zval(array, 1, &val);

    zval_ptr_dtor(&val);
}
4

Ví dụ này sao chép giá trị hai lần, tăng số lần đếm lại (nếu có) hai lần. Một cách khác và hiệu quả hơn một chút để viết chức năng này sẽ là

void fill_array(zval *array) {
    zval val;
    init_zval(&val);

    // Manually check REFCOUNTED:
    if (Z_REFCOUNTED(val)) {
        Z_ADDREF(val);
    }
    add_index_zval(array, 0, &val);

    // Or use the TRY macro:
    Z_TRY_ADDREF(val);
    add_index_zval(array, 1, &val);

    zval_ptr_dtor(&val);
}
8

Thao tác này sao chép giá trị một lần vào

void fill_array(zval *array) {
    zval val;
    init_zval(&val);

    // Manually check REFCOUNTED:
    if (Z_REFCOUNTED(val)) {
        Z_ADDREF(val);
    }
    add_index_zval(array, 0, &val);

    // Or use the TRY macro:
    Z_TRY_ADDREF(val);
    add_index_zval(array, 1, &val);

    zval_ptr_dtor(&val);
}
43, sau đó thực hiện di chuyển vào
void fill_array(zval *array) {
    zval val;
    init_zval(&val);

    // Manually check REFCOUNTED:
    if (Z_REFCOUNTED(val)) {
        Z_ADDREF(val);
    }
    add_index_zval(array, 0, &val);

    // Or use the TRY macro:
    Z_TRY_ADDREF(val);
    add_index_zval(array, 1, &val);

    zval_ptr_dtor(&val);
}
44, tiết kiệm một phần tăng và giảm số lần đếm dư thừa. Cuối cùng, cách chúng ta có thể viết mã này trong thực tế là

void fill_array(zval *array) {
    zval val;
    init_zval(&val);

    // Manually check REFCOUNTED:
    if (Z_REFCOUNTED(val)) {
        Z_ADDREF(val);
    }
    add_index_zval(array, 0, &val);

    // Or use the TRY macro:
    Z_TRY_ADDREF(val);
    add_index_zval(array, 1, &val);

    zval_ptr_dtor(&val);
}
1

Ở đây, giá trị được khởi tạo trực tiếp vào

void fill_array(zval *array) {
    zval val;
    init_zval(&val);

    // Manually check REFCOUNTED:
    if (Z_REFCOUNTED(val)) {
        Z_ADDREF(val);
    }
    add_index_zval(array, 0, &val);

    // Or use the TRY macro:
    Z_TRY_ADDREF(val);
    add_index_zval(array, 1, &val);

    zval_ptr_dtor(&val);
}
43 và sau đó được sao chép vào
void fill_array(zval *array) {
    zval val;
    init_zval(&val);

    // Manually check REFCOUNTED:
    if (Z_REFCOUNTED(val)) {
        Z_ADDREF(val);
    }
    add_index_zval(array, 0, &val);

    // Or use the TRY macro:
    Z_TRY_ADDREF(val);
    add_index_zval(array, 1, &val);

    zval_ptr_dtor(&val);
}
44. Phiên bản này vừa đơn giản vừa hiệu quả nhất

Macro

void fill_array(zval *array) {
    zval val;
    init_zval(&val);

    // Manually check REFCOUNTED:
    if (Z_REFCOUNTED(val)) {
        Z_ADDREF(val);
    }
    add_index_zval(array, 0, &val);

    // Or use the TRY macro:
    Z_TRY_ADDREF(val);
    add_index_zval(array, 1, &val);

    zval_ptr_dtor(&val);
}
47 tương tự như
void fill_array(zval *array) {
    zval val;
    init_zval(&val);

    // Manually check REFCOUNTED:
    if (Z_REFCOUNTED(val)) {
        Z_ADDREF(val);
    }
    add_index_zval(array, 0, &val);

    // Or use the TRY macro:
    Z_TRY_ADDREF(val);
    add_index_zval(array, 1, &val);

    zval_ptr_dtor(&val);
}
40, nhưng sẽ nhân bản các mảng, thay vì chỉ tăng số lượng truy cập của chúng. Nếu bạn đang sử dụng macro này, gần như chắc chắn bạn đang làm sai điều gì đó

Cuối cùng,

void fill_array(zval *array) {
    zval val;
    init_zval(&val);

    // Manually check REFCOUNTED:
    if (Z_REFCOUNTED(val)) {
        Z_ADDREF(val);
    }
    add_index_zval(array, 0, &val);

    // Or use the TRY macro:
    Z_TRY_ADDREF(val);
    add_index_zval(array, 1, &val);

    zval_ptr_dtor(&val);
}
49 là một macro sao chép rất chuyên dụng có thể được sử dụng khi sao chép từ một zval có khả năng tồn tại lâu dài trong quá trình yêu cầu. Như đã đề cập trước đây, việc tăng số lượng truy cập lại là bất hợp pháp trong trường hợp này, vì nó sẽ không an toàn cho luồng. Macro này sẽ tăng số lần đếm lại trên các giá trị không liên tục, nhưng thực hiện sao chép chuỗi/mảng đầy đủ cho các giá trị liên tục

Phá hủy zvals

Các ví dụ trên đã sử dụng

void fill_array(zval *array) {
    zval val;
    init_zval(&val);

    // Manually check REFCOUNTED:
    if (Z_REFCOUNTED(val)) {
        Z_ADDREF(val);
    }
    add_index_zval(array, 0, &val);

    // Or use the TRY macro:
    Z_TRY_ADDREF(val);
    add_index_zval(array, 1, &val);

    zval_ptr_dtor(&val);
}
1 để hủy zvals. Nếu giá trị được đếm lại, hàm này sẽ giảm số đếm lại và hủy giá trị khi nó về 0

Tuy nhiên, có một sự tinh tế ở đây. Việc đếm tham chiếu không đủ để phát hiện các giá trị không sử dụng là một phần của chu kỳ. Vì lý do này, PHP sử dụng một bộ thu gom rác tròn kiểu đánh dấu và quét bổ sung (GC). Khi số lần đếm giảm nhưng không đạt đến 0 và cấu trúc được đánh dấu là có khả năng xoay vòng (cờ

void fill_array(zval *array) {
    zval val;
    init_zval(&val);

    // Manually check REFCOUNTED:
    if (Z_REFCOUNTED(val)) {
        Z_ADDREF(val);
    }
    add_index_zval(array, 0, &val);

    // Or use the TRY macro:
    Z_TRY_ADDREF(val);
    add_index_zval(array, 1, &val);

    zval_ptr_dtor(&val);
}
81 không được đặt), thì PHP sẽ thêm cấu trúc vào bộ đệm gốc GC

Hàm

void fill_array(zval *array) {
    zval val;
    init_zval(&val);

    // Manually check REFCOUNTED:
    if (Z_REFCOUNTED(val)) {
        Z_ADDREF(val);
    }
    add_index_zval(array, 0, &val);

    // Or use the TRY macro:
    Z_TRY_ADDREF(val);
    add_index_zval(array, 1, &val);

    zval_ptr_dtor(&val);
}
82 là một biến thể không thực hiện kiểm tra bộ đệm gốc của GC và chỉ an toàn khi sử dụng nếu bạn biết rằng dữ liệu bị hủy là không tuần hoàn.
void fill_array(zval *array) {
    zval val;
    init_zval(&val);

    // Manually check REFCOUNTED:
    if (Z_REFCOUNTED(val)) {
        Z_ADDREF(val);
    }
    add_index_zval(array, 0, &val);

    // Or use the TRY macro:
    Z_TRY_ADDREF(val);
    add_index_zval(array, 1, &val);

    zval_ptr_dtor(&val);
}
83 là bí danh kế thừa cho chức năng tương tự

Một biến thể khác có thể gặp trong mã nội bộ là

void fill_array(zval *array) {
    zval val;
    init_zval(&val);

    // Manually check REFCOUNTED:
    if (Z_REFCOUNTED(val)) {
        Z_ADDREF(val);
    }
    add_index_zval(array, 0, &val);

    // Or use the TRY macro:
    Z_TRY_ADDREF(val);
    add_index_zval(array, 1, &val);

    zval_ptr_dtor(&val);
}
84, giống như
void fill_array(zval *array) {
    zval val;
    init_zval(&val);

    // Manually check REFCOUNTED:
    if (Z_REFCOUNTED(val)) {
        Z_ADDREF(val);
    }
    add_index_zval(array, 0, &val);

    // Or use the TRY macro:
    Z_TRY_ADDREF(val);
    add_index_zval(array, 1, &val);

    zval_ptr_dtor(&val);
}
1 nhưng sử dụng triển khai nội tuyến. Tiền tố
void fill_array(zval *array) {
    zval val;
    init_zval(&val);

    // Manually check REFCOUNTED:
    if (Z_REFCOUNTED(val)) {
        Z_ADDREF(val);
    }
    add_index_zval(array, 0, &val);

    // Or use the TRY macro:
    Z_TRY_ADDREF(val);
    add_index_zval(array, 1, &val);

    zval_ptr_dtor(&val);
}
86 là một quy ước chung cho các hàm có cả biến thể nội tuyến và phác thảo

Đang khởi tạo zvals

Cho đến bây giờ, chúng tôi đã sử dụng một hàm trừu tượng

void fill_array(zval *array) {
    zval val;
    init_zval(&val);

    // Manually check REFCOUNTED:
    if (Z_REFCOUNTED(val)) {
        Z_ADDREF(val);
    }
    add_index_zval(array, 0, &val);

    // Or use the TRY macro:
    Z_TRY_ADDREF(val);
    add_index_zval(array, 1, &val);

    zval_ptr_dtor(&val);
}
87 bằng cách nào đó khởi tạo một zval. Sẽ không có gì ngạc nhiên khi PHP xử lý khởi tạo zval bằng rất nhiều macro. Việc khởi tạo các kiểu đơn giản đặc biệt đơn giản

// retval is an output parameter.
void init_zval(zval *retval) {
    ZVAL_STRING(retval, "foo");
}

void some_other_function() {
    zval val;
    init_zval(&val);
    // .. Do something with val.
    zval_ptr_dtor(&val);
}
5

Đối với chuỗi, có khá nhiều tùy chọn khởi tạo. Cơ bản nhất là macro

void fill_array(zval *array) {
    zval val;
    init_zval(&val);

    // Manually check REFCOUNTED:
    if (Z_REFCOUNTED(val)) {
        Z_ADDREF(val);
    }
    add_index_zval(array, 0, &val);

    // Or use the TRY macro:
    Z_TRY_ADDREF(val);
    add_index_zval(array, 1, &val);

    zval_ptr_dtor(&val);
}
88, lấy một
void fill_array(zval *array) {
    zval val;
    init_zval(&val);

    // Manually check REFCOUNTED:
    if (Z_REFCOUNTED(val)) {
        Z_ADDREF(val);
    }
    add_index_zval(array, 0, &val);

    // Or use the TRY macro:
    Z_TRY_ADDREF(val);
    add_index_zval(array, 1, &val);

    zval_ptr_dtor(&val);
}
89 đã được tạo sẵn

// retval is an output parameter.
void init_zval(zval *retval) {
    ZVAL_STRING(retval, "foo");
}

void some_other_function() {
    zval val;
    init_zval(&val);
    // .. Do something with val.
    zval_ptr_dtor(&val);
}
8

Vì việc tạo một

void fill_array(zval *array) {
    zval val;
    init_zval(&val);

    // Manually check REFCOUNTED:
    if (Z_REFCOUNTED(val)) {
        Z_ADDREF(val);
    }
    add_index_zval(array, 0, &val);

    // Or use the TRY macro:
    Z_TRY_ADDREF(val);
    add_index_zval(array, 1, &val);

    zval_ptr_dtor(&val);
}
10 từ một chuỗi ký tự hoặc một chuỗi hiện có là quá phổ biến nên có hai trình bao bọc tiện lợi

void fill_array(zval *array) {
    zval val;
    init_zval(&val);

    // Manually check REFCOUNTED:
    if (Z_REFCOUNTED(val)) {
        Z_ADDREF(val);
    }
    add_index_zval(array, 0, &val);

    // Or use the TRY macro:
    Z_TRY_ADDREF(val);
    add_index_zval(array, 1, &val);

    zval_ptr_dtor(&val);
}
0

Macro

void fill_array(zval *array) {
    zval val;
    init_zval(&val);

    // Manually check REFCOUNTED:
    if (Z_REFCOUNTED(val)) {
        Z_ADDREF(val);
    }
    add_index_zval(array, 0, &val);

    // Or use the TRY macro:
    Z_TRY_ADDREF(val);
    add_index_zval(array, 1, &val);

    zval_ptr_dtor(&val);
}
11 sẽ đặt cờ
void fill_array(zval *array) {
    zval val;
    init_zval(&val);

    // Manually check REFCOUNTED:
    if (Z_REFCOUNTED(val)) {
        Z_ADDREF(val);
    }
    add_index_zval(array, 0, &val);

    // Or use the TRY macro:
    Z_TRY_ADDREF(val);
    add_index_zval(array, 1, &val);

    zval_ptr_dtor(&val);
}
7 dựa trên việc chuỗi có bất biến hay không. Có hai biến thể được tối ưu hóa có thể được biết nếu biết trước liệu chuỗi có được thực hiện hay không

// retval is an output parameter.
void init_zval(zval *retval) {
    ZVAL_STRING(retval, "foo");
}

void some_other_function() {
    zval val;
    init_zval(&val);
    // .. Do something with val.
    zval_ptr_dtor(&val);
}
0

Các chuỗi trống có một trình trợ giúp riêng

// retval is an output parameter.
void init_zval(zval *retval) {
    ZVAL_STRING(retval, "foo");
}

void some_other_function() {
    zval val;
    init_zval(&val);
    // .. Do something with val.
    zval_ptr_dtor(&val);
}
1

Macro

void fill_array(zval *array) {
    zval val;
    init_zval(&val);

    // Manually check REFCOUNTED:
    if (Z_REFCOUNTED(val)) {
        Z_ADDREF(val);
    }
    add_index_zval(array, 0, &val);

    // Or use the TRY macro:
    Z_TRY_ADDREF(val);
    add_index_zval(array, 1, &val);

    zval_ptr_dtor(&val);
}
13 có thể được sử dụng để tránh phân bổ
void fill_array(zval *array) {
    zval val;
    init_zval(&val);

    // Manually check REFCOUNTED:
    if (Z_REFCOUNTED(val)) {
        Z_ADDREF(val);
    }
    add_index_zval(array, 0, &val);

    // Or use the TRY macro:
    Z_TRY_ADDREF(val);
    add_index_zval(array, 1, &val);

    zval_ptr_dtor(&val);
}
10 nếu chuỗi trống hoặc có một ký tự đơn, vì các chuỗi như vậy luôn có các biến thể nội bộ có thể được tìm nạp nhanh chóng

// retval is an output parameter.
void init_zval(zval *retval) {
    ZVAL_STRING(retval, "foo");
}

void some_other_function() {
    zval val;
    init_zval(&val);
    // .. Do something with val.
    zval_ptr_dtor(&val);
}
2

Cuối cùng, macro

void fill_array(zval *array) {
    zval val;
    init_zval(&val);

    // Manually check REFCOUNTED:
    if (Z_REFCOUNTED(val)) {
        Z_ADDREF(val);
    }
    add_index_zval(array, 0, &val);

    // Or use the TRY macro:
    Z_TRY_ADDREF(val);
    add_index_zval(array, 1, &val);

    zval_ptr_dtor(&val);
}
15 là sự kết hợp của
void fill_array(zval *array) {
    zval val;
    init_zval(&val);

    // Manually check REFCOUNTED:
    if (Z_REFCOUNTED(val)) {
        Z_ADDREF(val);
    }
    add_index_zval(array, 0, &val);

    // Or use the TRY macro:
    Z_TRY_ADDREF(val);
    add_index_zval(array, 1, &val);

    zval_ptr_dtor(&val);
}
11 và
void fill_array(zval *array) {
    zval val;
    init_zval(&val);

    // Manually check REFCOUNTED:
    if (Z_REFCOUNTED(val)) {
        Z_ADDREF(val);
    }
    add_index_zval(array, 0, &val);

    // Or use the TRY macro:
    Z_TRY_ADDREF(val);
    add_index_zval(array, 1, &val);

    zval_ptr_dtor(&val);
}
17, trong đó macro sau tăng số lần đếm lại của chuỗi

// retval is an output parameter.
void init_zval(zval *retval) {
    ZVAL_STRING(retval, "foo");
}

void some_other_function() {
    zval val;
    init_zval(&val);
    // .. Do something with val.
    zval_ptr_dtor(&val);
}
3

Đối với mảng, may mắn thay, chúng tôi chỉ phải xem xét hai macro khởi tạo

// retval is an output parameter.
void init_zval(zval *retval) {
    ZVAL_STRING(retval, "foo");
}

void some_other_function() {
    zval val;
    init_zval(&val);
    // .. Do something with val.
    zval_ptr_dtor(&val);
}
4

Cái đầu tiên khởi tạo một mảng zval thành cấu trúc

void fill_array(zval *array) {
    zval val;
    init_zval(&val);

    // Manually check REFCOUNTED:
    if (Z_REFCOUNTED(val)) {
        Z_ADDREF(val);
    }
    add_index_zval(array, 0, &val);

    // Or use the TRY macro:
    Z_TRY_ADDREF(val);
    add_index_zval(array, 1, &val);

    zval_ptr_dtor(&val);
}
18 hiện có, trong khi cái sau khởi tạo một mảng trống cụ thể. Lưu ý rằng mặc dù cả hai ví dụ trên đều khởi tạo một mảng trống nhưng chúng không giống nhau.
void fill_array(zval *array) {
    zval val;
    init_zval(&val);

    // Manually check REFCOUNTED:
    if (Z_REFCOUNTED(val)) {
        Z_ADDREF(val);
    }
    add_index_zval(array, 0, &val);

    // Or use the TRY macro:
    Z_TRY_ADDREF(val);
    add_index_zval(array, 1, &val);

    zval_ptr_dtor(&val);
}
19 sử dụng một mảng trống được chia sẻ bất biến, trong khi
// retval is an output parameter.
void init_zval(zval *retval) {
    ZVAL_STRING(retval, "foo");
}

void some_other_function() {
    zval val;
    init_zval(&val);
    // .. Do something with val.
    zval_ptr_dtor(&val);
}
50 tạo một mảng mới. Nếu bạn định sửa đổi mảng ngay sau đó, bạn nên sử dụng biến thể
// retval is an output parameter.
void init_zval(zval *retval) {
    ZVAL_STRING(retval, "foo");
}

void some_other_function() {
    zval val;
    init_zval(&val);
    // .. Do something with val.
    zval_ptr_dtor(&val);
}
50

Các zval đối tượng được khởi tạo bằng cách sử dụng

// retval is an output parameter.
void init_zval(zval *retval) {
    ZVAL_STRING(retval, "foo");
}

void some_other_function() {
    zval val;
    init_zval(&val);
    // .. Do something with val.
    zval_ptr_dtor(&val);
}
52

// retval is an output parameter.
void init_zval(zval *retval) {
    ZVAL_STRING(retval, "foo");
}

void some_other_function() {
    zval val;
    init_zval(&val);
    // .. Do something with val.
    zval_ptr_dtor(&val);
}
5

Mặc dù những điều này hơi phổ biến khi xử lý các đối tượng đã có sẵn, nhưng

// retval is an output parameter.
void init_zval(zval *retval) {
    ZVAL_STRING(retval, "foo");
}

void some_other_function() {
    zval val;
    init_zval(&val);
    // .. Do something with val.
    zval_ptr_dtor(&val);
}
53 là cách điển hình để tạo một đối tượng từ đầu. Điều này sẽ được đề cập trong một chương sau về các đối tượng

Cuối cùng, tài nguyên được khởi tạo bằng cách sử dụng

// retval is an output parameter.
void init_zval(zval *retval) {
    ZVAL_STRING(retval, "foo");
}

void some_other_function() {
    zval val;
    init_zval(&val);
    // .. Do something with val.
    zval_ptr_dtor(&val);
}
54

// retval is an output parameter.
void init_zval(zval *retval) {
    ZVAL_STRING(retval, "foo");
}

void some_other_function() {
    zval val;
    init_zval(&val);
    // .. Do something with val.
    zval_ptr_dtor(&val);
}
6

Tách zvals

Trong PHP, tất cả các giá trị theo ngữ nghĩa theo giá trị theo mặc định. Điều này có nghĩa là nếu bạn viết

// retval is an output parameter.
void init_zval(zval *retval) {
    ZVAL_STRING(retval, "foo");
}

void some_other_function() {
    zval val;
    init_zval(&val);
    // .. Do something with val.
    zval_ptr_dtor(&val);
}
55 thì việc sửa đổi của
// retval is an output parameter.
void init_zval(zval *retval) {
    ZVAL_STRING(retval, "foo");
}

void some_other_function() {
    zval val;
    init_zval(&val);
    // .. Do something with val.
    zval_ptr_dtor(&val);
}
56 sẽ không ảnh hưởng đến
// retval is an output parameter.
void init_zval(zval *retval) {
    ZVAL_STRING(retval, "foo");
}

void some_other_function() {
    zval val;
    init_zval(&val);
    // .. Do something with val.
    zval_ptr_dtor(&val);
}
57 và ngược lại. Đồng thời,
// retval is an output parameter.
void init_zval(zval *retval) {
    ZVAL_STRING(retval, "foo");
}

void some_other_function() {
    zval val;
    init_zval(&val);
    // .. Do something with val.
    zval_ptr_dtor(&val);
}
55 về cơ bản được triển khai như

// retval is an output parameter.
void init_zval(zval *retval) {
    ZVAL_STRING(retval, "foo");
}

void some_other_function() {
    zval val;
    init_zval(&val);
    // .. Do something with val.
    zval_ptr_dtor(&val);
}
7

Nghĩa là, cả

// retval is an output parameter.
void init_zval(zval *retval) {
    ZVAL_STRING(retval, "foo");
}

void some_other_function() {
    zval val;
    init_zval(&val);
    // .. Do something with val.
    zval_ptr_dtor(&val);
}
56 và
// retval is an output parameter.
void init_zval(zval *retval) {
    ZVAL_STRING(retval, "foo");
}

void some_other_function() {
    zval val;
    init_zval(&val);
    // .. Do something with val.
    zval_ptr_dtor(&val);
}
57 đều trỏ đến cùng một cấu trúc với số lượng truy cập tăng dần. Điều này có nghĩa là một sửa đổi ngây thơ của
// retval is an output parameter.
void init_zval(zval *retval) {
    ZVAL_STRING(retval, "foo");
}

void some_other_function() {
    zval val;
    init_zval(&val);
    // .. Do something with val.
    zval_ptr_dtor(&val);
}
56 cũng sẽ sửa đổi
// retval is an output parameter.
void init_zval(zval *retval) {
    ZVAL_STRING(retval, "foo");
}

void some_other_function() {
    zval val;
    init_zval(&val);
    // .. Do something with val.
    zval_ptr_dtor(&val);
}
57

Đây là lúc khái niệm copy-on-write xuất hiện. Bạn chỉ được phép sửa đổi các cấu trúc mà bạn sở hữu độc quyền, điều đó có nghĩa là chúng phải có số lượng truy cập là một. Nếu một cấu trúc có số lượng truy cập lớn hơn một, trước tiên nó cần được tách ra. Tách biệt chỉ là một từ ưa thích để sao chép cấu trúc

Trong thực tế, "cấu trúc" có thể được thay thế bằng "mảng". Mặc dù về lý thuyết, khái niệm này cũng áp dụng cho các chuỗi, nhưng các chuỗi hầu như không bao giờ bị thay đổi sau khi xây dựng trong PHP. Như vậy _______ 483 là macro phân tách chính, chỉ có thể được áp dụng cho ________ 484 zvals

// retval is an output parameter.
void init_zval(zval *retval) {
    ZVAL_STRING(retval, "foo");
}

void some_other_function() {
    zval val;
    init_zval(&val);
    // .. Do something with val.
    zval_ptr_dtor(&val);
}
8

Macro

// retval is an output parameter.
void init_zval(zval *retval) {
    ZVAL_STRING(retval, "foo");
}

void some_other_function() {
    zval val;
    init_zval(&val);
    // .. Do something with val.
    zval_ptr_dtor(&val);
}
83 không chỉ chăm sóc các mảng được chia sẻ mà còn cả các mảng bất biến

// retval is an output parameter.
void init_zval(zval *retval) {
    ZVAL_STRING(retval, "foo");
}

void some_other_function() {
    zval val;
    init_zval(&val);
    // .. Do something with val.
    zval_ptr_dtor(&val);
}
9

Macro

// retval is an output parameter.
void init_zval(zval *retval) {
    ZVAL_STRING(retval, "foo");
}

void some_other_function() {
    zval val;
    init_zval(&val);
    // .. Do something with val.
    zval_ptr_dtor(&val);
}
86 tách một zval chung, nhưng hiếm khi hữu ích, vì việc tách thường trực tiếp trước một sửa đổi và dù sao bạn cũng cần biết loại zval để thực hiện bất kỳ sửa đổi có ý nghĩa nào

Làm cách nào để nhận các giá trị duy nhất trong mảng PHP?

The array_unique() là một hàm tích hợp sẵn trong PHP và hàm này loại bỏ các giá trị trùng lặp khỏi một mảng. Nếu có nhiều phần tử trong mảng có cùng giá trị thì phần tử xuất hiện đầu tiên sẽ được giữ lại và tất cả các lần xuất hiện khác của phần tử này sẽ bị xóa khỏi mảng.

Làm cách nào để kiểm tra mảng trùng lặp trong PHP?

Hàm array_unique() loại bỏ các giá trị trùng lặp khỏi một mảng . Nếu hai hoặc nhiều giá trị mảng giống nhau, thì giá trị đầu tiên sẽ được giữ lại và giá trị còn lại sẽ bị xóa. Ghi chú. Mảng được trả về sẽ giữ loại khóa của mục mảng đầu tiên.

Làm cách nào để kiểm tra giá trị trùng lặp trong PHP?

Đây là đoạn mã đang hoạt động để kiểm tra xem mảng có giá trị trùng lặp hay không. .
$arr = array('Email','Name','Something','Else','Email');
nếu ( đếm( $arr ). == đếm( array_unique( $arr ) ) ) echo "Một số trùng lặp";