PHP parameter passing principle-PHP Tutorial

Source: Internet
Author: User
Deeply understand the principle of passing parameters in PHP. First, let's talk about a question that comes to mind today. When writing php extensions, it seems that the parameter (that is, the variable passed to zend_parse_parameters) does not need to be free. Example: * (zend_parse_param first describes a question that comes to mind today. When writing php extensions, it seems that the parameter (that is, the variable passed to zend_parse_parameters) does not need to be free. Example:

* (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, , &str, &str_len) ==    
}

Running properly:

test("Hello World"); 

There is no need to worry about memory leakage of the test function. php will automatically help us reclaim the variables used to save parameters.

How exactly does php do it? To explain this problem, we still need to see how php transmits parameters.

Introduction to EG (argument_stack)

To put it simply, an EG in php stores a stack specifically used to store parameters, called argument_stack. Whenever a function call occurs, php will press the input parameter into EG (argument_stack ). Once the function call ends, EG (argument_stack) is cleared and waits for the next function call.

There are some differences between the implementation of php5.2 and 5.3 on the structure and purpose of the struct of EG (argument_stack. This article mainly takes 5.2 as an example. the changes of 5.3 + will be discussed later.

It is about argument_stack in 5.2, which looks simple and clear. The stack top and bottom are fixed to NULL. Parameters received by the function are pushed to the stack sequentially from left to right. Note that an additional long value will be pushed into the stack, indicating the number of parameters in the stack (10 in total ).

So what is the parameter pushed into argument_stack? Actually, they are zval type pointers. The zva they point to may be a CV variable, an is_ref = 1 variable, a constant number, or a constant string.

In php5.2, EG (argument_stack) is implemented as zend_ptr_stack:

typedef  ** **
Initialize argument_stack

The initialization of argument_stack occurs before php processes specific requests. more accurately, it is in the startup process of the php interpreter.

In the init_executor function, we find the following two rows:

zend_ptr_stack_init(&&EG(argument_stack), ( *) NULL);

These two lines represent the initialization of EG (argument_stack), followed by a NULL. Since EG is a global variable, all data in EG (argument_stack) is 0 before zend_ptr_stack_init is called.

Zend_ptr_stack_init is easy to implement.

ZEND_API  zend_ptr_stack_init(zend_ptr_stack *->top_element = stack->elements = ( **) emalloc(( *)*->max =->top = 

Once argument_stack is initialized, it is immediately pushed into NULL. I don't need to go into it here. this NULL actually has no meaning.

After NULL is added to the stack, the actual memory distribution of the entire argument_stack is as follows:

Parameter entry stack

After being pushed to the first NULL, once a parameter is added to the stack, argument_stack performs the following actions:

stack->top++*(stack->top_element++) =

We use a simple php code to illustrate the problem:

 foo( ("hello world");

The above code imports a string constant when calling foo. Therefore, what is actually pushed into the stack is a zval pointing to the storage of "hello world. Use vld to view the compiled opcode:

line     # *  op                           fetch          ext  return  operands---------------------------------------------------------------------------------   3     0  >   NOP   6     1      SEND_VAL                                                  OP1[  IS_CONST (458754) 'hello world' ]         2      DO_FCALL                                      1           OP1[  IS_CONST (458752) 'foo' ]  15     3    > RETURN                                                    OP1[  IS_CONST (0) 1 ]

What the SEND_VAL command actually does is to press "hello world" into argument_stack.

** = & Opline-> (!
Point to zval zend_ptr_stack_push (&}

The argument_stack after the stack entry is complete is:

Number of parameters

As mentioned above, not all parameters are actually finished in the stack. Php will also press an additional number to indicate the number of parameters, which does not happen in the SEND_XXX command. In fact, php will import the number of parameters into the stack before the function is actually executed.

Continue with the above example. the DO_FCALL command is used to call the foo function. Before calling foo, php will automatically fill in the last part of argument_stack.

 extended_value)        zend_ptr_stack_2_push(&EG(argument_stack), ( *)(zend_uintptr_t)opline-> (EX(function_state).function->type ==  (EX(function_state).function->type == { 

After the number of input parameters and NULL, the entire argument_stack for foo call has been completed.

GET parameters

Continue with the above example. Let's go deep into the foo function to see what foo's opcode looks like.

line     # *  op                           fetch          ext  return  operands---------------------------------------------------------------------------------   3     0  >   RECV                                                      OP1[  IS_CONST (0) 1 ]   4     1      SEND_VAL                                                  OP1[  IS_CONST (5) 123 ]         2      DO_FCALL                                      1           OP1[  IS_CONST (459027) 'print_r' ]   5     3    > RETURN                                                    OP1[  IS_CONST (0) null ]

The first command is RECV, which is literally used to obtain parameters in the stack. Actually, SEND_VAL and RECV are similar. Before each function call, SEND_VAL performs RECV within the function. The RECV command is not required. A recv is generated only when a user-defined function is called. The extended functions we have compiled, built-in php functions, do not have RECV.

Note that each SEND_VAL and RECV can only process one parameter. That is to say, if there are multiple parameters in the parameter passing process, several SEND_VAL and several RECV will be generated. Here is an interesting topic. what is the order of input parameters and parameters?

The answer is that SEND_VAL will press the stack from left to right, and get the parameters from left to right in the same way as RECV.

Stack bottom (zend_ptr_stack_get_arg (arg_num, (**) & param TSRMLS_CC) = ** zend_verify_arg_type (zend_function *) EG (active_op_array), arg_num, * = get_zval_ptr_ptr (& opline-> result, EX (Ts), & (PZVAL_IS_REF (**

Both zend_assign_to_variable_reference and zend_receive complete "GET parameters ". "Getting parameters" is not easy to understand. What exactly does it actually do?

In the end, it is easy to add the parameter to the symbol table during the current function execution, which corresponds to EG (current_execute_data)-> symbol_table. In this example, after RECV is completed, the symbol_table in the function contains a symbol 'str', whose value is "hello world ".

However, argument_stack does not have any changes, because RECV only reads parameters and does not generate pop-like operations on stacks.

Clear argument_stack

The print_r inside foo is also a function call, so it also produces a stack-> Clear operation. Therefore, the argument_stack before print_r execution is:

After print_r is executed, argument_stack returns to foo's RECV state.

The process of calling print_r is not the focus of this article. We are concerned about how php clears argument_stack after calling foo.

As shown in the do_fcall code snippet shown above

 inline  **p = EG(argument_stack).top_element-     delete_count = ()(zend_uintptr_t) *-= (delete_count+     (--delete_count>=*q = *(zval **)(--*p =&=

Note that zval pointer in the stack is cleared here, and zval_ptr_dtor is used. Zval_ptr_dtor will reduce the refcount by 1. Once the refcount is reduced to 0, the memory area where the variable is saved will be actually recycled.

In this example, after foo is called, the zval status of "hello world" is saved as follows:

value        "hello world"refcount     1type         6is_ref       0

Since refcount has only 1 left, zval_ptr_dtor will actually destroy "hello world" from the memory.

The argument_stack memory status after Stack cancellation is:

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.