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

 ID:                 46705
 Updated by:         fel...@php.net
 Reported by:        wrzasq at gmail dot com
 Summary:            Impossible to implement compatible interfaces
-Status:             Open
+Status:             Closed
 Type:               Feature/Change Request
 Package:            Scripting Engine problem
 Operating System:   Debian GNU/Linux
 PHP Version:        5.2.6
-Assigned To:        
+Assigned To:        felipe
 Block user comment: N
 Private report:     N

 New Comment:

Yes, it fixes this issue. Thanks for testing. :)


Previous Comments:
------------------------------------------------------------------------
[2011-12-03 17:47:17] clicky at erebot dot net

I was unable to reproduce the fatal errors from my initial testcases with PHP 
5.4.0RC2:

php-5.4.0RC2 -r 'interface A { public function foo(); } interface B { public 
function foo(); } class Foo implements A,B { public function foo() {} }; $foo = 
new Foo;'

php-5.4.0RC2 -r 'interface A { public function foo(); } interface B extends A { 
public function foo(); } class Foo implements B { public function foo() {} }; 
$foo = new Foo;'

php-5.4.0RC2 -r 'interface A { public function foo(); } interface B extends A { 
public function foo($bar=null); } class Foo implements B { public function 
foo($bar=null) {} }; $foo = new Foo;'

All those pass (don't raise any fatal error).
So I guess the patch for #43200 that landed in 5.4.0RC2 also fixed this issue.

------------------------------------------------------------------------
[2011-11-28 20:07:40] clicky at erebot dot net

tklingenberg at lastflood dot net:

I think you missed the point, or to rephrase it another way: the problem lies 
in the definition of "compatible":

<?php
interface A
{
public function foo();
}

interface B
{
public function foo();
}

class C implements A, B
{
public function foo(){}
}
?>

and

<?php
interface A
{
public function foo();
}

interface A
{
public function foo();
}

class C implements B
{
public function foo(){}
}
?>

should both be considered valid scripts because the two signatures for foo() 
[in interface A and interface B] do not contradict each other: it is possible 
to write a method that satisfies both.

The same argument also holds for the example smith gave:

<?php

interface fooI
{
    function ding();
}

interface barI extends fooI
{
    function ding($dong = null);
}

class bar implements barI
{
    public function ding($dong = null)
    {
        echo 'woho: '.$dong."\n";
    }
}

Note however that in this case, it would be invalid if bar implemented both 
fooI and barI because the two interfaces contradict each other (one expects an 
[optional] argument, while the other doesn't).

Of course your example (already) works because you simply defined an empty 
interface (which is rather pointless, unless you're actually extending from 
several interfaces).
Maybe another analogy will help. Let's suppose I define 2 interfaces, one for 
people, the other one for robots:

<?php

interface Person
{
  public function speak();
  public function walk();
}

interface Robot
{
  public function speak();
  public function roll();
}

?>

Now, imagine that I want to create a Humanoid class (a mix between a Person and 
a Robot). Quite naturally, I'd want to write something like this:

<?php
class Humanoid
implements Person, Robot
{
  public function speak() { echo "Hello world!"; }
  protected function goForward($speed) { /* ... */ }
  public function walk() { $this->goForward(1); }
  public function roll() { $this->goForward(3); }
  // some other methods...
}
?>

Unfortunately, this will give you an error such as this:
"PHP Fatal error:  Can't inherit abstract function Robot::speak() (previously 
declared abstract in Person) in Command line code on line 1"
... and that's what this bug is all about...

It's a PITA when you must work with interfaces defined by other people which 
are compatible (ex: both force you to define a "__toString" method) and yet PHP 
returns a fatal error when you try to use them in your own class.

------------------------------------------------------------------------
[2011-11-27 18:03:02] tklingenberg at lastflood dot net

Actually it's possible, you just need to make the interfaces compatible for 
that:

interface A
{
public function foo();
}

interface B extends A
{
}

and then you're done. This also prevents you from writing duplicate code ;)

However if interfaces definitions can not be changed, then this is not a 
solution. Probably this is fixed? - See bug #43200.

------------------------------------------------------------------------
[2011-08-01 12:11:11] smith at pooteeweet dot org

Note its also not possible to redefine while adding new optional parameters

<?php

interface fooI
{
    function ding();
}

interface barI extends fooI
{
    function ding($dong = null);
}

class bar implements barI
{
    public function ding($dong = null)
    {
        echo 'woho: '.$dong."\n";
    }
}

$bar = new bar;
$bar->ding('yeah!');

------------------------------------------------------------------------
[2011-03-22 23:33:03] clicky at erebot dot net

I think this use case, the one bug #43200 and the one below are all valid:

<?php
interface A
{
public function foo();
}

interface B
extends A
{
public function foo();
}

class C implements B
{
public function foo(){}
}

?>

The case above may seem odd (there's really no point in redefining the exact 
same interface), but I have a simple use case where this may prove handy.

I'm currently writing some code for a little project which is meant to teach 
some middle to advanced topics of PHP. The code is self-documented (using 
doxygen) and uses some interface from SPL (Countable). That interface is used 
several times in different files and I'd like to document the count() method 
only once (if possible, at the interface level -- then using doxygen's ability 
to copy/paste the doc from parent classes/interfaces into the current class).

I thought I could just define my own interface (Project_Countable), extending 
from SPL's Countable, "overriding" the method's signature (only so doxygen can 
pick up the method's declaration -- the prototype for the method was actually 
left unchanged) and then define a class that implements Project_Countable.
So in my case, A = SPL's Countable interface and B = Project_Countable.

However, this pattern can't be used as it results in the same error others 
noted here and in bug #43200.
I can't simply avoid Project_Countable extending from Countable, because then I 
would lose count()'s "magic" by doing so.

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


The remainder of the comments for this report are too long. To view
the rest of the comments, please view the bug report online at

    https://bugs.php.net/bug.php?id=46705


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

Reply via email to