Skip to content

Commit

Permalink
Fix #77291: magic methods inherited from a trait may be ignored
Browse files Browse the repository at this point in the history
When adding methods from a trait, we must not assume that a method name
with the same length as the name of the using class is either a PHP 4
style constructor, or not a magic method at all – it may well be
another magic method.

We mostly preserve the spirit of the optimization which caused this
regression, and avoid string comparisons for all method names which can
never be magic methods.
  • Loading branch information
cmb69 committed Dec 16, 2018
1 parent 54739c7 commit 0061db5
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 12 deletions.
2 changes: 2 additions & 0 deletions NEWS
Expand Up @@ -8,6 +8,8 @@ PHP NEWS
(Valentin V. Bartenev)
. Fixed bug #76046 (PHP generates "FE_FREE" opcode on the wrong line).
(Nikita)
. Fixed bug #77291 (magic methods inherited from a trait may be ignored).
(cmb)

- CURL:
. Fixed bug #77264 (curl_getinfo returning microseconds, not seconds).
Expand Down
42 changes: 42 additions & 0 deletions Zend/tests/bug77291.phpt
@@ -0,0 +1,42 @@
--TEST--
Bug #77291 (magic methods inherited from a trait may be ignored)
--FILE--
<?php

trait AccessibleProperties
{
public function __isset($property)
{
return property_exists($this, $property);
}

public function __get($property)
{
if (property_exists($this, $property)) {
return $this->$property;
}
}
}

class Foo4567 {
use AccessibleProperties;

protected $a = 'Some value';
}

class Foo45 {
use AccessibleProperties;

protected $a = 'Some value';
}

$foo = new Foo4567;
var_dump(isset($foo->a));
$foo = new Foo45;
var_dump($foo->a);
?>
===DONE===
--EXPECT--
bool(true)
string(10) "Some value"
===DONE===
24 changes: 12 additions & 12 deletions Zend/zend_inheritance.c
Expand Up @@ -1126,18 +1126,7 @@ static zend_bool zend_traits_method_compatibility_check(zend_function *fn, zend_

static void zend_add_magic_methods(zend_class_entry* ce, zend_string* mname, zend_function* fe) /* {{{ */
{
if (ZSTR_LEN(ce->name) == ZSTR_LEN(mname)) {
zend_string *lowercase_name = zend_string_tolower(ce->name);
lowercase_name = zend_new_interned_string(lowercase_name);
if (!memcmp(ZSTR_VAL(mname), ZSTR_VAL(lowercase_name), ZSTR_LEN(mname))) {
if (ce->constructor && (!ce->parent || ce->constructor != ce->parent->constructor)) {
zend_error_noreturn(E_COMPILE_ERROR, "%s has colliding constructor definitions coming from traits", ZSTR_VAL(ce->name));
}
ce->constructor = fe;
fe->common.fn_flags |= ZEND_ACC_CTOR;
}
zend_string_release_ex(lowercase_name, 0);
} else if (ZSTR_VAL(mname)[0] != '_' || ZSTR_VAL(mname)[1] != '_') {
if (ZSTR_LEN(ce->name) != ZSTR_LEN(mname) && (ZSTR_VAL(mname)[0] != '_' || ZSTR_VAL(mname)[1] != '_')) {
/* pass */
} else if (zend_string_equals_literal(mname, ZEND_CLONE_FUNC_NAME)) {
ce->clone = fe;
Expand Down Expand Up @@ -1168,6 +1157,17 @@ static void zend_add_magic_methods(zend_class_entry* ce, zend_string* mname, zen
ce->__tostring = fe;
} else if (zend_string_equals_literal(mname, ZEND_DEBUGINFO_FUNC_NAME)) {
ce->__debugInfo = fe;
} else if (ZSTR_LEN(ce->name) == ZSTR_LEN(mname)) {
zend_string *lowercase_name = zend_string_tolower(ce->name);
lowercase_name = zend_new_interned_string(lowercase_name);
if (!memcmp(ZSTR_VAL(mname), ZSTR_VAL(lowercase_name), ZSTR_LEN(mname))) {
if (ce->constructor && (!ce->parent || ce->constructor != ce->parent->constructor)) {
zend_error_noreturn(E_COMPILE_ERROR, "%s has colliding constructor definitions coming from traits", ZSTR_VAL(ce->name));
}
ce->constructor = fe;
fe->common.fn_flags |= ZEND_ACC_CTOR;
}
zend_string_release_ex(lowercase_name, 0);
}
}
/* }}} */
Expand Down

0 comments on commit 0061db5

Please sign in to comment.