2013-01-31 27 views
5

Tôi đang phát triển một phần mở rộng PHP, bằng cách sử dụng C. Cho đến nay tôi đang làm việc trên xác nhận hợp lệ các đối số, được chuyển đến chức năng của phần mở rộng từ không gian người dùng PHP.Làm cách nào để tạo số đối số kiểm soát ZEND_BEGIN_ARG_INFO_EX, được chuyển đến tiện ích mở rộng PHP?

Macro ZEND_BEGIN_ARG_INFO_EX có thể được sử dụng để cung cấp cho Zend Engine thông tin về các đối số của hàm. Tham số thứ 4 của macro, có tên là required_num_args, để cho động cơ tự động kiểm soát số lượng đối số, loại bỏ rắc rối này khỏi tôi. Tuy nhiên, tôi không thể tìm thấy cách để làm cho nó hoạt động: động cơ luôn chạy chức năng của phần mở rộng mà không có bất kỳ cảnh báo nào, ngay cả khi một tập lệnh PHP không vượt qua đủ đối số.

Dưới đây là định nghĩa của tôi về đối số chức năng:

ZEND_BEGIN_ARG_INFO_EX(test_func_swt_arginfo, 0, 0, 3) 
    ZEND_ARG_INFO(1, firstArg) 
    ZEND_ARG_ARRAY_INFO(0, secondArg, true) 
    ZEND_ARG_OBJ_INFO(1, thirdArg, SomeClass, false) 
ZEND_END_ARG_INFO() 

Dưới đây là định nghĩa của tôi về chức năng, xuất khẩu của phần mở rộng PHP:

static const zend_function_entry test_func_functions[] = { 
    PHP_FE(sample_with_types, test_func_swt_arginfo) 
    PHP_FE_END 
}; 

Đây là chức năng của tôi:

PHP_FUNCTION(sample_with_types) 
{ 
    RETURN_TRUE; 
} 

Đây là tập lệnh PHP tôi chạy:

<?php 
sample_with_types(); 

Kết quả mong đợi: PHP hiển thị lỗi/cảnh báo/ngoại lệ, giống như "không đủ đối số được chuyển đến hàm"; chức năng không thực thi.

Kết quả thực tế: hàm thực hiện và trả về true.

Làm cách nào để cấu hình đúng cấu trúc đối số hàm, để Công cụ Zend kiểm tra số đối số tự động? Hoặc tôi có nhầm lẫn mục đích của đối số required_num_args trong macro ZEND_BEGIN_ARG_INFO_EX không?

Trả lời

8

Theo như tôi biết, đây không phải là những gì ZEND_BEGIN_ARG_INFO_EX dành cho.

ZEND_BEGIN_ARG_INFO_EX là một bổ sung PHP 5 được sử dụng để tạo mã sạch hơn, cho phép gợi ý loại, thông qua tham chiếu và phản chiếu. Hãy xem xét các tờ khai arginfo sau cho chức năng thực tế của bạn mà chỉ trả về true:

ZEND_BEGIN_ARG_INFO_EX(arginfo_test, 0, 0, 3) 
    ZEND_ARG_INFO(0, firstArg) 
    ZEND_ARG_OBJ_INFO(0, objNonNull, stdClass, 0) 
    ZEND_ARG_OBJ_INFO(0, obj, stdClass, 1) 
    ZEND_ARG_OBJ_INFO(1, objByRef, stdClass, 1) 
ZEND_END_ARG_INFO() 

Nó có tác dụng sau:

sample_with_types();       // ok 
sample_with_types(1, null);     // error: arg #2 should be stdClass 
sample_with_types(1, new stdClass, null);  // ok 
sample_with_types(1, new stdClass, 1);  // error: arg #3 should be stdClass 
sample_with_types(1, new stdClass, null, 2); // error: arg #4 must be reference 

Ngoài ra, nó cung cấp khả năng phản ánh đến chức năng của bạn:

$ref = new ReflectionFunction('sample_with_types'); 
var_dump($ref->getParameters()); 

... cho ra kết quả tương tự như:

array(4) { 
    [0]=> 
    &object(ReflectionParameter)#2 (1) { 
    ["name"]=> 
    string(8) "firstArg" 
    } 
    [1]=> 
    &object(ReflectionParameter)#3 (1) { 
    ["name"]=> 
    string(10) "objNonNull" 
    } 
    [2]=> 
    &object(ReflectionParameter)#4 (1) { 
    ["name"]=> 
    string(3) "obj" 
    } 
    [3]=> 
    &object(ReflectionParameter)#5 (1) { 
    ["name"]=> 
    string(8) "objByRef" 
    } 
} 

Nếu bạn bỏ qua arginfo, thay vào đó, ReflectionFunction::getParameters() sẽ trả về một mảng trống.

Thông số macro required_num_args được sử dụng đặc biệt để phản ánh và biểu thị số lượng thông số sẽ được đánh dấu là bắt buộc khi phản ánh hàm.

Nếu bạn cần phải thực hiện các đối số cần thiết và không chỉ đánh dấu chúng là cần thiết khi sử dụng phản chiếu, bạn vẫn phải sử dụng zend_parse_parameters, mà trong nhiều trường hợp, bạn vẫn sẽ cần phải nhận được giá trị thực tế của các đối số:

PHP_FUNCTION(sample_with_types) 
{ 
    long arg1; 
    zval *arg2 = NULL, *arg3 = NULL, *arg4 = NULL; 
    zend_class_entry ce2, ce3, ce4; 

    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "looo", &arg1, 
           &arg2, &ce2, &arg3, &ce3, &arg4, &ce4) == FAILURE) 
    { 
     return; 
    } 

    RETURN_TRUE; 
} 

Lưu ý cách tôi đã sử dụng "looo" (loại đối tượng chung) và không "lOO!O!" (loại đối tượng cụ thể có bộ chỉ định null) ở trên. Loại gợi ý đã được chỉ định với arginfo, do đó không cần phải thực hiện hai lần.

Vì vậy, không arginfo:

  • Bạn sẽ phải sử dụng một số ít các zend_fetch_class cuộc gọi và mục lớp gõ gợi ý đối số đối tượng của bạn.
  • Nó sẽ không cho phép phản chiếu.
  • Bạn sẽ không thể khai báo các đối số được chuyển bởi tham chiếu.
  • Nó rõ ràng sẽ tạo ra mã ít sạch hơn.

Vì lý do hiển nhiên, bạn sẽ muốn đảm bảo cả khai báo arginfo và kết quả cuộc gọi zend_parse_parameters của bạn.

+0

Cảm ơn bạn @netcoder về thông tin và nỗ lực nhằm làm rõ mục đích của macro đó. Nó có ý nghĩa rất nhiều, và thực sự tôi đã phát hiện ra rằng trước khi đặt câu hỏi. Tuy nhiên, điều chính gây ra sự khó hiểu của tôi và khiến tôi đi đến SO, là tham số 'required_num_args'. Nó có vẻ như tự động xác nhận của args num, nhưng trong thực tế nó không có gì. Nó có thể được, mà bạn biết mục đích của nó? –

+0

@AndreyTserkus: 'required_num_args' được sử dụng để phản ánh và biểu thị thời điểm dừng tham số đếm theo yêu cầu (ví dụ: khi gọi' isOptional() '). Nó không có bất kỳ hiệu ứng nào khác ngoài điều đó. (Tôi đã cập nhật câu trả lời với thông tin này.) – netcoder

+0

tuyệt vời, cảm ơn bạn! –

Các vấn đề liên quan