Để 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 Show Quản lý bộ nhớ ZvalVớ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 zvalsThô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 zvalsCá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 zvalsCho đế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 zvalsTrong 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"; |