]> granicus.if.org Git - php/commitdiff
Require non-absolute trait method refs to be unambiguous
authorNikita Popov <nikita.ppv@gmail.com>
Tue, 3 Mar 2020 13:31:09 +0000 (14:31 +0100)
committerNikita Popov <nikita.ppv@gmail.com>
Tue, 10 Mar 2020 15:01:13 +0000 (16:01 +0100)
Currently, when writing something like

class X {
    use T1, T2 {
       func as otherFunc;
    }
    function func() {}
}

where both T1::func() and T2::func() exist, we will simply assume
that func refers to T1::func(). This is surprising, and it doesn't
really make sense that this particular method gets picked.

This commit validates that non-absolute method references are
unambiguous, i.e. refer to exactly one method. If there is
ambiguity, it is required to write T1::func as otherFunc or
similar.

Closes GH-5232.

UPGRADING
Zend/tests/bug62069.phpt [new file with mode: 0644]
Zend/tests/bug62069_2.phpt [new file with mode: 0644]
Zend/tests/traits/language011.phpt
Zend/zend_inheritance.c

index 41a72c280dad16ccbaff7763b9e99e026c26b7df..db8e2eb22ee51a1992839bcc8c6cd55110204168 100644 (file)
--- a/UPGRADING
+++ b/UPGRADING
@@ -149,6 +149,20 @@ PHP 8.0 UPGRADE NOTES
 
         function test($a = [], $b) {}       // Deprecated
         function test(Foo $a = null, $b) {} // Allowed
+  . Non-absolute trait method references in trait alias adaptations are now
+    required to be unambiguous:
+
+        class X {
+            use T1, T2 {
+               func as otherFunc;
+            }
+            function func() {}
+        }
+
+    If both T1::func() and T2::func() exist, this code was previously silently
+    accepted, and func as assumed to refer to T1::func. Now it will generate a
+    fatal error instead, and either T1::func or T2::func needs to be written
+    explicitly.
 
 - COM:
   . Removed the ability to import case-insensitive constants from type
diff --git a/Zend/tests/bug62069.phpt b/Zend/tests/bug62069.phpt
new file mode 100644 (file)
index 0000000..d434e27
--- /dev/null
@@ -0,0 +1,32 @@
+--TEST--
+Bug #62069: binding wrong traits if they have same name methods
+--FILE--
+<?php
+
+trait T1 {
+    public function func() {
+        echo "From T1\n";
+    }
+}
+
+trait T2 {
+    public function func() {
+        echo "From T2\n";
+    }
+}
+
+class Bar {
+    public function func() {
+        echo "From Bar\n";
+    }
+    use T1, T2 {
+        func as f1;
+    }
+}
+
+$b = new Bar();
+$b->f2();
+
+?>
+--EXPECTF--
+Fatal error: An alias was defined for method func(), which exists in both T1 and T2. Use T1::func or T2::func to resolve the ambiguity in %s on line %d
diff --git a/Zend/tests/bug62069_2.phpt b/Zend/tests/bug62069_2.phpt
new file mode 100644 (file)
index 0000000..c7c42ba
--- /dev/null
@@ -0,0 +1,35 @@
+--TEST--
+Bug #62069: binding wrong traits if they have same name methods (variation 2)
+--FILE--
+<?php
+
+trait T1 {
+    public function func() {
+        echo "From T1\n";
+    }
+}
+
+trait T2 {
+    public function func() {
+        echo "From T2\n";
+    }
+}
+
+class Bar {
+    public function func() {
+        echo "From Bar\n";
+    }
+    use T1 {
+        func as f1;
+    }
+    use T2 {
+        func as f2;
+    }
+}
+
+$b = new Bar();
+$b->f2();
+
+?>
+--EXPECTF--
+Fatal error: An alias was defined for method func(), which exists in both T1 and T2. Use T1::func or T2::func to resolve the ambiguity in %s on line %d
index 44de874705dd5e707212d9c1cf4d518df7c43cc0..1f5b4963088785621cabe26355d7320c1f801e77 100644 (file)
@@ -18,7 +18,7 @@ trait World {
 
 
 class MyClass {
-   use Hello, World { sayHello as sayWorld; }
+   use Hello, World { World::sayHello as sayWorld; }
 }
 
 $o = new MyClass();
index a031207b85e8b33960405a1642356cf0a0cee523..eab275e5094210311c6f3901e2fd7fdaf3921af2 100644 (file)
@@ -1858,8 +1858,12 @@ static void zend_traits_init_trait_structures(zend_class_entry *ce, zend_class_e
                                                                continue;
                                                        }
 
-                                                       // TODO: This is ambiguous! The first trait is assumed.
-                                                       break;
+                                                       zend_error_noreturn(E_COMPILE_ERROR,
+                                                               "An alias was defined for method %s(), which exists in both %s and %s. Use %s::%s or %s::%s to resolve the ambiguity",
+                                                               ZSTR_VAL(cur_method_ref->method_name),
+                                                               ZSTR_VAL(trait->name), ZSTR_VAL(traits[j]->name),
+                                                               ZSTR_VAL(trait->name), ZSTR_VAL(cur_method_ref->method_name),
+                                                               ZSTR_VAL(traits[j]->name), ZSTR_VAL(cur_method_ref->method_name));
                                                }
                                        }
                                }