summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Marr <gron@php.net>2011-12-17 14:26:39 +0000
committerStefan Marr <gron@php.net>2011-12-17 14:26:39 +0000
commit525dd55eed41ce7adef1aa1ab7f55b2591f83c33 (patch)
treee77289272087ae7048443f2226b9a7232e770333
parent5da241ca99a7788ec1ffc5719598ac073e2f0e1f (diff)
downloadphp-git-525dd55eed41ce7adef1aa1ab7f55b2591f83c33.tar.gz
Fixed inconsistent and broken handling of private properties in traits.
# The handling of private properties in classes is now consistent with private properties in traits. # Perviously, privates could cause strict warnings, are were not properly merged into the class when # the parent class had a private property of the same name. Now, we introduce it without notice, # since it is a new and independent property, just like in normal classes. # This problem was diagnosed while working on Bug #60536.
-rw-r--r--Zend/tests/bug60536_001.phpt1
-rw-r--r--Zend/tests/bug60536_003.phpt5
-rw-r--r--Zend/tests/bug60536_004.phpt2
-rw-r--r--Zend/tests/traits/property005.phpt16
-rw-r--r--Zend/tests/traits/property006.phpt37
-rw-r--r--Zend/tests/traits/property007.phpt38
-rw-r--r--Zend/tests/traits/property008.phpt62
-rw-r--r--Zend/tests/traits/property009.phpt59
-rw-r--r--Zend/zend_compile.c65
9 files changed, 235 insertions, 50 deletions
diff --git a/Zend/tests/bug60536_001.phpt b/Zend/tests/bug60536_001.phpt
index 5a7008e393..916646727d 100644
--- a/Zend/tests/bug60536_001.phpt
+++ b/Zend/tests/bug60536_001.phpt
@@ -22,5 +22,4 @@ $a->x();
echo "DONE";
?>
--EXPECTF--
-Strict Standards: X and T define the same property ($x) in the composition of Y. This might be incompatible, to improve maintainability consider using accessor methods in traits instead. Class was composed in %sbug60536_001.php on line %d
DONE
diff --git a/Zend/tests/bug60536_003.phpt b/Zend/tests/bug60536_003.phpt
index 8ddca352af..d944a0a41e 100644
--- a/Zend/tests/bug60536_003.phpt
+++ b/Zend/tests/bug60536_003.phpt
@@ -1,5 +1,5 @@
--TEST--
-Private (relevant to #60536)
+Properties should be initialized correctly (relevant to #60536)
--FILE--
<?php
error_reporting(E_ALL | E_STRICT);
@@ -32,9 +32,6 @@ var_dump($b);
?>
--EXPECTF--
-Strict Standards: BaseWithPropA and AHelloProperty define the same property ($hello) in the composition of SubclassA. This might be incompatible, to improve maintainability consider using accessor methods in traits instead. Class was composed in %sbug60536_003.php on line %d
-
-Strict Standards: BaseWithTPropB and AHelloProperty define the same property ($hello) in the composition of SubclassB. This might be incompatible, to improve maintainability consider using accessor methods in traits instead. Class was composed in %sbug60536_003.php on line %d
object(SubclassA)#%d (2) {
["hello":"SubclassA":private]=>
int(0)
diff --git a/Zend/tests/bug60536_004.phpt b/Zend/tests/bug60536_004.phpt
index 4ae326ef7c..4f20836093 100644
--- a/Zend/tests/bug60536_004.phpt
+++ b/Zend/tests/bug60536_004.phpt
@@ -31,8 +31,6 @@ echo "POST-CLASS-GUARD2\n";
?>
--EXPECTF--
PRE-CLASS-GUARD
-
-Strict Standards: Base and THello1 define the same property ($hello) in the composition of SameNameInSubClassNoNotice. This might be incompatible, to improve maintainability consider using accessor methods in traits instead. Class was composed in %sbug60536_004.php on line %d
POST-CLASS-GUARD
Strict Standards: Notice and THello1 define the same property ($hello) in the composition of Notice. This might be incompatible, to improve maintainability consider using accessor methods in traits instead. Class was composed in %sbug60536_004.php on line %d
diff --git a/Zend/tests/traits/property005.phpt b/Zend/tests/traits/property005.phpt
index 3c80a1f26a..899a332acc 100644
--- a/Zend/tests/traits/property005.phpt
+++ b/Zend/tests/traits/property005.phpt
@@ -13,18 +13,11 @@ trait THello1 {
}
echo "PRE-CLASS-GUARD\n";
-class NoticeForBase extends Base {
- use THello1;
-}
-echo "POST-CLASS-GUARD\n";
-
-// now the same with a class that defines the property itself
-
class Notice extends Base {
use THello1;
private $hello;
}
-echo "POST-CLASS-GUARD2\n";
+echo "POST-CLASS-GUARD\n";
// now we do the test for a fatal error
@@ -33,7 +26,7 @@ class TraitsTest {
public $hello;
}
-echo "POST-CLASS-GUARD\n";
+echo "POST-CLASS-GUARD2\n";
$t = new TraitsTest;
$t->hello = "foo";
@@ -41,10 +34,7 @@ $t->hello = "foo";
--EXPECTF--
PRE-CLASS-GUARD
-Strict Standards: Base and THello1 define the same property ($hello) in the composition of NoticeForBase. This might be incompatible, to improve maintainability consider using accessor methods in traits instead. Class was composed in %s on line %d
-POST-CLASS-GUARD
-
Strict Standards: Notice and THello1 define the same property ($hello) in the composition of Notice. This might be incompatible, to improve maintainability consider using accessor methods in traits instead. Class was composed in %s on line %d
-POST-CLASS-GUARD2
+POST-CLASS-GUARD
Fatal error: TraitsTest and THello1 define the same property ($hello) in the composition of TraitsTest. However, the definition differs and is considered incompatible. Class was composed in %s on line %d
diff --git a/Zend/tests/traits/property006.phpt b/Zend/tests/traits/property006.phpt
new file mode 100644
index 0000000000..1a709199a9
--- /dev/null
+++ b/Zend/tests/traits/property006.phpt
@@ -0,0 +1,37 @@
+--TEST--
+Introducing new private variables of the same name in a subclass is ok, and does not lead to any output. That is consitent with normal inheritance handling.
+--FILE--
+<?php
+error_reporting(E_ALL | E_STRICT);
+
+class Base {
+ private $hello;
+}
+
+trait THello1 {
+ private $hello;
+}
+
+// Now we use the trait, which happens to introduce another private variable
+// but they are distinct, and not related to each other, so no warning.
+echo "PRE-CLASS-GUARD\n";
+class SameNameInSubClassNoNotice extends Base {
+ use THello1;
+}
+echo "POST-CLASS-GUARD\n";
+
+// now the same with a class that defines the property itself,
+// that should give the expected strict warning.
+
+class Notice extends Base {
+ use THello1;
+ private $hello;
+}
+echo "POST-CLASS-GUARD2\n";
+?>
+--EXPECTF--
+PRE-CLASS-GUARD
+POST-CLASS-GUARD
+
+Strict Standards: Notice and THello1 define the same property ($hello) in the composition of Notice. This might be incompatible, to improve maintainability consider using accessor methods in traits instead. Class was composed in %s on line %d
+POST-CLASS-GUARD2
diff --git a/Zend/tests/traits/property007.phpt b/Zend/tests/traits/property007.phpt
new file mode 100644
index 0000000000..0f7c3b3948
--- /dev/null
+++ b/Zend/tests/traits/property007.phpt
@@ -0,0 +1,38 @@
+--TEST--
+Introducing new private variables of the same name in a subclass is ok, and does not lead to any output. That is consitent with normal inheritance handling.
+--FILE--
+<?php
+error_reporting(E_ALL | E_STRICT);
+
+class Base {
+ protected $hello;
+}
+
+trait THello1 {
+ protected $hello;
+}
+
+// Protected and public are handle more strict with a warning then what is
+// expected from normal inheritance since they can have easier coliding semantics
+echo "PRE-CLASS-GUARD\n";
+class SameNameInSubClassProducesNotice extends Base {
+ use THello1;
+}
+echo "POST-CLASS-GUARD\n";
+
+// now the same with a class that defines the property itself, too.
+
+class Notice extends Base {
+ use THello1;
+ protected $hello;
+}
+echo "POST-CLASS-GUARD2\n";
+?>
+--EXPECTF--
+PRE-CLASS-GUARD
+
+Strict Standards: Base and THello1 define the same property ($hello) in the composition of SameNameInSubClassProducesNotice. This might be incompatible, to improve maintainability consider using accessor methods in traits instead. Class was composed in %s on line %d
+POST-CLASS-GUARD
+
+Strict Standards: Notice and THello1 define the same property ($hello) in the composition of Notice. This might be incompatible, to improve maintainability consider using accessor methods in traits instead. Class was composed in %s on line %d
+POST-CLASS-GUARD2
diff --git a/Zend/tests/traits/property008.phpt b/Zend/tests/traits/property008.phpt
new file mode 100644
index 0000000000..e263692d60
--- /dev/null
+++ b/Zend/tests/traits/property008.phpt
@@ -0,0 +1,62 @@
+--TEST--
+Handling of private fields with traits needs to have same semantics as with normal inheritance.
+--FILE--
+<?php
+error_reporting(E_ALL | E_STRICT);
+
+class BaseWithPropA {
+ private $hello = 0;
+}
+
+// This is how privates are handled in normal inheritance
+class SubclassClassicInheritance extends BaseWithPropA {
+ private $hello = 0;
+}
+
+// And here, we need to make sure, that the traits behave the same
+
+trait AHelloProperty {
+ private $hello = 0;
+}
+
+class BaseWithTPropB {
+ use AHelloProperty;
+}
+
+class SubclassA extends BaseWithPropA {
+ use AHelloProperty;
+}
+
+class SubclassB extends BaseWithTPropB {
+ use AHelloProperty;
+}
+
+$classic = new SubclassClassicInheritance;
+var_dump($classic);
+
+$a = new SubclassA;
+var_dump($a);
+
+$b = new SubclassB;
+var_dump($b);
+
+?>
+--EXPECTF--
+object(SubclassClassicInheritance)#1 (2) {
+ ["hello":"SubclassClassicInheritance":private]=>
+ int(0)
+ ["hello":"BaseWithPropA":private]=>
+ int(0)
+}
+object(SubclassA)#2 (2) {
+ ["hello":"SubclassA":private]=>
+ int(0)
+ ["hello":"BaseWithPropA":private]=>
+ int(0)
+}
+object(SubclassB)#3 (2) {
+ ["hello":"SubclassB":private]=>
+ int(0)
+ ["hello":"BaseWithTPropB":private]=>
+ int(0)
+} \ No newline at end of file
diff --git a/Zend/tests/traits/property009.phpt b/Zend/tests/traits/property009.phpt
new file mode 100644
index 0000000000..135129d31f
--- /dev/null
+++ b/Zend/tests/traits/property009.phpt
@@ -0,0 +1,59 @@
+--TEST--
+Handling of public fields with traits needs to have same semantics as with normal inheritance, however, we do add strict warnings since it is easier to run into something unexpeted with changing traits.
+--FILE--
+<?php
+error_reporting(E_ALL | E_STRICT);
+
+class BaseWithPropA {
+ public $hello = 0;
+}
+
+// This is how publics are handled in normal inheritance
+class SubclassClassicInheritance extends BaseWithPropA {
+ public $hello = 0;
+}
+
+// And here, we need to make sure, that the traits behave the same
+
+trait AHelloProperty {
+ public $hello = 0;
+}
+
+class BaseWithTPropB {
+ use AHelloProperty;
+}
+
+class SubclassA extends BaseWithPropA {
+ use AHelloProperty;
+}
+
+class SubclassB extends BaseWithTPropB {
+ use AHelloProperty;
+}
+
+$classic = new SubclassClassicInheritance;
+var_dump($classic);
+
+$a = new SubclassA;
+var_dump($a);
+
+$b = new SubclassB;
+var_dump($b);
+
+?>
+--EXPECTF--
+Strict Standards: BaseWithPropA and AHelloProperty define the same property ($hello) in the composition of SubclassA. This might be incompatible, to improve maintainability consider using accessor methods in traits instead. Class was composed in %s on line %d
+
+Strict Standards: BaseWithTPropB and AHelloProperty define the same property ($hello) in the composition of SubclassB. This might be incompatible, to improve maintainability consider using accessor methods in traits instead. Class was composed in %s on line %d
+object(SubclassClassicInheritance)#1 (1) {
+ ["hello"]=>
+ int(0)
+}
+object(SubclassA)#2 (1) {
+ ["hello"]=>
+ int(0)
+}
+object(SubclassB)#3 (1) {
+ ["hello"]=>
+ int(0)
+} \ No newline at end of file
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c
index f3fb1ed53c..80c35c6e5a 100644
--- a/Zend/zend_compile.c
+++ b/Zend/zend_compile.c
@@ -4234,6 +4234,7 @@ static void zend_do_traits_property_binding(zend_class_entry *ce TSRMLS_DC) /* {
ulong prop_hash;
const char* class_name_unused;
zend_bool prop_found;
+ zend_bool parent_prop_is_private = 0;
zend_bool not_compatible;
zval* prop_value;
@@ -4271,40 +4272,44 @@ static void zend_do_traits_property_binding(zend_class_entry *ce TSRMLS_DC) /* {
if (coliding_prop->flags & ZEND_ACC_SHADOW) {
/* this one is inherited, lets look it up in its own class */
zend_hash_quick_find(&coliding_prop->ce->properties_info, prop_name, prop_name_length+1, prop_hash, (void **) &coliding_prop);
+ parent_prop_is_private = (coliding_prop->flags & ZEND_ACC_PRIVATE) == ZEND_ACC_PRIVATE;
}
- if ( (coliding_prop->flags & (ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC))
- == (property_info->flags & (ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC))) {
- /* flags are identical, now the value needs to be checked */
- if (property_info->flags & ZEND_ACC_STATIC) {
- not_compatible = (FAILURE == compare_function(&compare_result,
- ce->default_static_members_table[coliding_prop->offset],
- ce->traits[i]->default_static_members_table[property_info->offset] TSRMLS_CC))
- || (Z_LVAL(compare_result) != 0);
+
+ if (!parent_prop_is_private) {
+ if ( (coliding_prop->flags & (ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC))
+ == (property_info->flags & (ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC))) {
+ /* flags are identical, now the value needs to be checked */
+ if (property_info->flags & ZEND_ACC_STATIC) {
+ not_compatible = (FAILURE == compare_function(&compare_result,
+ ce->default_static_members_table[coliding_prop->offset],
+ ce->traits[i]->default_static_members_table[property_info->offset] TSRMLS_CC))
+ || (Z_LVAL(compare_result) != 0);
+ } else {
+ not_compatible = (FAILURE == compare_function(&compare_result,
+ ce->default_properties_table[coliding_prop->offset],
+ ce->traits[i]->default_properties_table[property_info->offset] TSRMLS_CC))
+ || (Z_LVAL(compare_result) != 0);
+ }
} else {
- not_compatible = (FAILURE == compare_function(&compare_result,
- ce->default_properties_table[coliding_prop->offset],
- ce->traits[i]->default_properties_table[property_info->offset] TSRMLS_CC))
- || (Z_LVAL(compare_result) != 0);
+ /* the flags are not identical, thus, we assume properties are not compatible */
+ not_compatible = 1;
}
- } else {
- /* the flags are not identical, thus, we assume properties are not compatible */
- not_compatible = 1;
- }
- if (not_compatible) {
- zend_error(E_COMPILE_ERROR,
- "%s and %s define the same property ($%s) in the composition of %s. However, the definition differs and is considered incompatible. Class was composed",
- find_first_definition(ce, i, prop_name, prop_name_length, prop_hash, coliding_prop->ce)->name,
- property_info->ce->name,
- prop_name,
- ce->name);
- } else {
- zend_error(E_STRICT,
- "%s and %s define the same property ($%s) in the composition of %s. This might be incompatible, to improve maintainability consider using accessor methods in traits instead. Class was composed",
- find_first_definition(ce, i, prop_name, prop_name_length, prop_hash, coliding_prop->ce)->name,
- property_info->ce->name,
- prop_name,
- ce->name);
+ if (not_compatible) {
+ zend_error(E_COMPILE_ERROR,
+ "%s and %s define the same property ($%s) in the composition of %s. However, the definition differs and is considered incompatible. Class was composed",
+ find_first_definition(ce, i, prop_name, prop_name_length, prop_hash, coliding_prop->ce)->name,
+ property_info->ce->name,
+ prop_name,
+ ce->name);
+ } else {
+ zend_error(E_STRICT,
+ "%s and %s define the same property ($%s) in the composition of %s. This might be incompatible, to improve maintainability consider using accessor methods in traits instead. Class was composed",
+ find_first_definition(ce, i, prop_name, prop_name_length, prop_hash, coliding_prop->ce)->name,
+ property_info->ce->name,
+ prop_name,
+ ce->name);
+ }
}
}