Bug #67851 [Opn->Nab]: Extending method visibility with a trait does not work with interfaces

From: Date: Wed, 15 Apr 2015 14:00:05 +0000
Subject: Bug #67851 [Opn->Nab]: Extending method visibility with a trait does not work with interfaces
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-192100@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=67851&edit=1

 ID:                 67851
 Updated by:         jpauli@php.net
 Reported by:        awoody_02 at hotmail dot com
 Summary:            Extending method visibility with a trait does not
                     work with interfaces
-Status:             Open
+Status:             Not a bug
 Type:               Bug
 Package:            Class/Object related
 Operating System:   Windows 7 Ultimate SP1
 PHP Version:        5.5.15
 Block user comment: N
 Private report:     N

 New Comment:

Thank you for taking the time to write to us, but this is not
a bug. Please double-check the documentation available at
http://www.php.net/manual/ and the instructions on how to
report
a bug at http://bugs.php.net/how-to-report.php




Previous Comments:
------------------------------------------------------------------------
[2015-04-15 13:31:23] jpauli@php.net

You hit a tricky behavior of traits (and they provide many of them).

What happens to you, is that when you declare WritableObject, the interface will be honored BEFORE
the trait (it is always the case).

The trait declares the method as public, but at the time the interface is honnored (bound), the
trait is still unknown to the class, thus the setValue() into it is still private at that moment
(from its inheritence).

I don't think we can fix this in PHP5, but we can work on those tricky scenarios for PHP7

------------------------------------------------------------------------
[2014-08-16 22:41:15] awoody_02 at hotmail dot com

Description:
------------
Consider a class that implements an interface, thereby requiring a public method, and that inherits
a protected or private implementation of that method from a base class.

Normally it is possible to extend the visibility of the inherited method by overriding it with a
public method of the same name that simply defers the call to parent::method().

However if this overriding method is imported from a trait, PHP issues a fatal error complaining
that the visibility of the method in the base class is insufficient to meet the requirements of the
interface.

Removing the interface requirement from the class and using Reflection shows that it successfully
imports the public method from the trait and overrides the protected/private inherited method, so
the bug must be in the checking for consistency with the interface. The line on which the error is
reported is the line that contains the opening brace of the class definition that throws the error.

Test script:
---------------
interface IReadOnlyObject
{
	public function GetValue();
}

interface IWritableObject extends IReadOnlyObject
{
	public function SetValue($value);
}

trait ReadOnlyObjectMethods
{
	private $value = null;

	public function GetValue()
	{
		return $this->value;
	}

	protected function SetValue($value)
	{
		$this->value = $value;
	}
}

trait WritableObjectMethods
{
	public function SetValue($value)
	{
		parent::SetValue($value);
	}
}

class ReadOnlyObject implements IReadOnlyObject
{
	use ReadOnlyObjectMethods;
}

class WritableObject extends ReadOnlyObject implements IWritableObject
{
	use WritableObjectMethods;
}

$o = new WritableObject();
$o->SetValue('hello');
echo $o->GetValue();

Expected result:
----------------
hello

Actual result:
--------------
Fatal error: Access level to ReadOnlyObject::SetValue() must be public (as in class IWritableObject)
in test.php on line 42


------------------------------------------------------------------------



--
Edit this bug report at https://bugs.php.net/bug.php?id=67851&edit=1


Thread (4 messages)

« previous php.bugs (#192100) next »