php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login

Patch Fix-conflict-detection.patch for Class/Object related Bug #60717

Patch version 2012-01-30 23:00 UTC

Return to Bug #60717 | Download this patch
Patch Revisions:

Developer: gron@php.net

Index: Zend/zend_compile.c
===================================================================
--- Zend/zend_compile.c	(revision 322946)
+++ Zend/zend_compile.c	(working copy)
@@ -3645,22 +3645,19 @@
 		if (i == current) {
 			continue; /* just skip this, cause its the table this function is applied on */
 		}
-
+		
 		if (zend_hash_quick_find(function_tables[i], hash_key->arKey, hash_key->nKeyLength, hash_key->h, (void **)&other_trait_fn) == SUCCESS) {
 			/* if it is an abstract method, there is no collision */
 			if (other_trait_fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
 				/* Make sure they are compatible */
-				if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
-					/* In case both are abstract, just check prototype, but need to do that in both directions */
-					if (   !zend_do_perform_implementation_check(fn, other_trait_fn TSRMLS_CC)
-						|| !zend_do_perform_implementation_check(other_trait_fn, fn TSRMLS_CC)) {
-						zend_error(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s", //ZEND_FN_SCOPE_NAME(fn), fn->common.function_name, //::%s()
-													zend_get_function_declaration(fn TSRMLS_CC),
-													zend_get_function_declaration(other_trait_fn TSRMLS_CC));
-					}
-				} else {
-					/* otherwise, do the full check */
-					do_inheritance_check_on_method(fn, other_trait_fn TSRMLS_CC);
+				/* In case both are abstract, just check prototype, but need to do that in both directions */
+				if (   !zend_do_perform_implementation_check(fn, other_trait_fn TSRMLS_CC)
+					|| !zend_do_perform_implementation_check(other_trait_fn, fn TSRMLS_CC)
+					|| ((fn->common.scope->ce_flags & ZEND_ACC_FINAL) != (other_trait_fn->common.scope->ce_flags & ZEND_ACC_FINAL))  /* equal final qualifier */
+					|| ((fn->common.scope->ce_flags & ZEND_ACC_STATIC)!= (other_trait_fn->common.scope->ce_flags & ZEND_ACC_STATIC))) { /* equal static qualifier */
+					zend_error(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s", //ZEND_FN_SCOPE_NAME(fn), fn->common.function_name, //::%s()
+												zend_get_function_declaration(fn TSRMLS_CC),
+												zend_get_function_declaration(other_trait_fn TSRMLS_CC));
 				}
 				
 				/* we can savely free and remove it from other table */
@@ -3672,7 +3669,14 @@
 				if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
 					/* Make sure they are compatible.
 					   Here, we already know other_trait_fn cannot be abstract, full check ok. */
-					do_inheritance_check_on_method(other_trait_fn, fn TSRMLS_CC);
+					if (   !zend_do_perform_implementation_check(fn, other_trait_fn TSRMLS_CC)
+						|| !zend_do_perform_implementation_check(other_trait_fn, fn TSRMLS_CC)
+						|| ((fn->common.scope->ce_flags & ZEND_ACC_FINAL) != (other_trait_fn->common.scope->ce_flags & ZEND_ACC_FINAL))  /* equal final qualifier */
+						|| ((fn->common.scope->ce_flags & ZEND_ACC_STATIC)!= (other_trait_fn->common.scope->ce_flags & ZEND_ACC_STATIC))) { /* equal static qualifier */
+						zend_error(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s", //ZEND_FN_SCOPE_NAME(fn), fn->common.function_name, //::%s()
+								   zend_get_function_declaration(fn TSRMLS_CC),
+								   zend_get_function_declaration(other_trait_fn TSRMLS_CC));
+					}
 					
 					/* just mark as solved, will be added if its own trait is processed */
 					abstract_solved = 1;
Index: Zend/tests/traits/bugs/abstract-methods06.phpt
===================================================================
--- Zend/tests/traits/bugs/abstract-methods06.phpt	(revision 322946)
+++ Zend/tests/traits/bugs/abstract-methods06.phpt	(working copy)
@@ -23,4 +23,4 @@
 
 ?>
 --EXPECTF--	
-Fatal error: Declaration of THelloB::hello() must be compatible with THelloA::hello($a) in %s on line %d
\ No newline at end of file
+Fatal error: Declaration of THelloA::hello($a) must be compatible with THelloB::hello() in %s on line %d
\ No newline at end of file
Index: Zend/tests/traits/bug60717.phpt
===================================================================
--- Zend/tests/traits/bug60717.phpt	(revision 0)
+++ Zend/tests/traits/bug60717.phpt	(revision 0)
@@ -0,0 +1,73 @@
+--TEST--
+Bug #60717 (Order of traits in use statement can cause unexpected unresolved abstract method)
+--FILE--
+<?php
+
+namespace HTML
+{
+	interface Helper
+	{
+		function text($text);
+		function attributes(array $attributes = null);
+		function textArea(array $attributes = null, $value);
+	}
+
+	trait TextUTF8
+	{
+		function text($text) {}
+	}
+
+	trait TextArea
+	{
+		function textArea(array $attributes = null, $value) {}
+		abstract function attributes(array $attributes = null);
+		abstract function text($text);
+	}
+
+	trait HTMLAttributes
+	{
+		function attributes(array $attributes = null) {	}
+		abstract function text($text);
+	}
+
+	class HTMLHelper implements Helper
+	{
+		use TextArea, HTMLAttributes, TextUTF8;
+	}
+	
+	class HTMLHelper2 implements Helper
+	{
+		use TextArea, TextUTF8, HTMLAttributes;
+	}
+	
+	class HTMLHelper3 implements Helper
+	{
+		use HTMLAttributes, TextArea, TextUTF8;
+	}
+
+	class HTMLHelper4 implements Helper
+	{
+		use HTMLAttributes, TextUTF8, TextArea;
+	}
+	
+	class HTMLHelper5 implements Helper
+	{
+		use TextUTF8, TextArea, HTMLAttributes;
+	}
+	
+	class HTMLHelper6 implements Helper
+	{
+		use TextUTF8, HTMLAttributes, TextArea;
+	}	
+
+	$o = new HTMLHelper;
+    $o = new HTMLHelper2;
+    $o = new HTMLHelper3;
+    $o = new HTMLHelper4;
+    $o = new HTMLHelper5;
+    $o = new HTMLHelper6;
+    echo 'Done';
+}
+
+--EXPECT--
+Done
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Fri Apr 26 02:01:29 2024 UTC