PhP5 multi-inheritance bug

Source: Internet
Author: User

<? Php </p> <p> class a extends B {</p> <p> }; </p> <p> class B extends c {</p> <p >}; </p> <p> class c {</p> <p> }; </p> <p >?> <Br/>

 

When the above code is executed, an error is returned:Fatal error: Class 'B' not found.

 

An error occurred in the running phase. After analyzing the PHP compilation and execution process, the following parsing sequence is obtained...

 
 
  1. Start:
  2. Top_statement_list
  3. ;
  4. Top_statement_list:
  5. Top_statement_list
  6. ... // Omitted
  7. ;
  8. Top_statement:
  9. ... // Omitted
  10. | Class_declaration_statement
  11. ... // Omitted
  12. ;
  13. Class_declaration_statement:
  14. Unticked_class_declaration_statement
  15. ;
  16. Unticked_class_declaration_statement:
  17. Class_entry_type T_STRING extends_from
  18. ... // Omitted
  19. ;
  20. Class_entry_type:
  21. T_CLASS
  22. ... // Omitted
  23. ;
  24. Extends_from:
  25. /* Empty */
  26. | T_EXTENDS fully_qualified_class_name
  27. ... // Omitted
  28. ;
  29. Fully_qualified_class_name:
  30. T_STRING {zend_do_fetch_class (& $, & $1 TSRMLS_CC );}
  31.  
 
 
  1. Zend_do_fetch_class will set opcode = ZEND_FETCH_CLAS

From this process, we can find that this should be a PHP5 bug. For fully_qualified_class_name, if the Delimiter is also inherited from a class, then an error will occur, because fully_qualified_class_name is just simple to fetch_class, if this class is not entered into class_table at this time, an error will occur. That is to say, a mechanism is required to ensure that the parent class is processed first.

The following is my conclusion after analyzing the source code:
For a, because it is a derived class, in the compilation phase, when it is defined, it will:

 
 
  1.  zend_do_begin_class_declaratio

In this function, it calls:

 
 
  1.  build_runtime_defined_function_key(&opline->op1.u.constant, lcname, name_len TSRMLS_CC)

To generate one:

 
 
  1.    sprintf(result->value.str.val, "%c%s%s%s", '/0', name, filename, char_pos_buf
    1. );

To store the classname of a compiler into class_table:

 
 
  1.     zend_hash_update(CG(class_table), opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len, &new_class_entry, sizeof(zend_class_entry *), NULL
    1. );

Finally, when the top_statement is absorbed, a class will be generated (filled with class_table );

 
 
  1. top_statement:
  2.         statement
  3.  ...
  4.     | class_declaration_statement { zend_do_early_binding(TSRMLS_C); }
  5. ...
  6. ...
  7. ;

When zend_do_early_binding:

 
 
  1. void zend_do_early_binding(TSRMLS_D){
  2. ...
  3. ...
  4.   switch (opline->opcode) {
  5.       case ZEND_DECLARE_FUNCTION:
  6.           if (do_bind_function(opline, CG(function_table), 1) == FAILURE) {
  7.               return;
  8.           }
  9.           table = CG(function_table);
  10.           break;
  11.       case ZEND_DECLARE_CLASS:
  12.       case ZEND_DECLARE_INHERITED_CLASS:
  13.           is_abstract_class = 1;
  14.           /* break missing intentionally */
  15.       case ZEND_VERIFY_ABSTRACT_CLASS: {
  16.               zend_op *verify_abstract_class_op = opline;
  17.               if (!is_abstract_class) {
  18.                   opline--;
  19.               }
  20.               if (opline->opcode == ZEND_DECLARE_CLASS) {
  21.                   if (do_bind_class(opline, CG(class_table), 1 TSRMLS_CC) == NULL) {
  22.                       return;
  23.                   }
  24.               } else if (opline->opcode == ZEND_DECLARE_INHERITED_CLASS) {
  25.                   zval *parent_name = &(opline-1)->op2.u.constant;
  26.                   zend_class_entry **pce;
  27.                     if (zend_lookup_class(Z_STRVAL_P(parent_name), Z_STRLEN_P(parent_name), &pce TSR
  28. MLS_CC) == FAILURE) {
  29.                         return;
  30.                     }
  31.                     if (do_bind_inherited_class(opline, CG(class_table), *pce, 1 TSRMLS_CC) == NULL)
  32.  {
  33.                         return;
  34.                     }
  35.                     /* clear unnecessary ZEND_FETCH_CLASS opcode */
  36. }

As you can see, if the parent class cannot be found, it will be returned directly. That is to say, if the parent class cannot be found in the derived class during compilation, it will not be initialized, but will be postponed to the execution period. An opline with the opcode ZEND_DECLARE_INHERITED_CLASS will be allocated to generate the defined class at runtime:

 
 
  1. ZEND_API zend_class_entry * do_bind_inherited_class (zend_op * opline, HashTable * class_table, zend_class_entry * parent_ce, zend_bool compile_time TSRMLS_DC)
  2. {
  3. .......
  4. // Attributes and methods of the hash_merg subclass and parent class
  5. If (zend_hash_add (class_table, opline-> op2.u. constant. value. str. val, opline-> op2.u. constant. value. str. len + 1, pce, sizeof (zend_class_entry *), NULL) = FAILURE)
  6. .....
  7. }

The problem arises at this time:
Because our B is also a derived class, when we execute do_bind_inherited_class of a, for B, we also need to create a ZEND_DECLARE_INHERITED_CLASS, that is, there is no B in the class_table at this time.
This explains that if the base class c is defined first, no errors will occur.

Well, this should be a Bug in PHP5.

I have reported a bug to the PHP development team and sent a letter asking Rasmus Lerdof (the creator of PHP) to see what they said:
Http://bugs.php.net/bug.php? Id = 45904

 

Address: http://www.laruence.com/2008/08/24/427.html

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.