FUDforum
Fast Uncompromising Discussions. FUDforum will get your users talking.

Home » Imported messages » comp.lang.php » Strange but true! Working with interfaces in PHP
Show: Today's Messages :: Unread Messages :: Show Polls :: Message Navigator
| Subscribe to topic | Bookmark topic 
Switch to threaded view of this topic Create a new topic Submit Reply
Strange but true! Working with interfaces in PHP [message #185450] Mon, 31 March 2014 18:31 Go to next message
Mirco is currently offline  Mirco
Messages: 1
Registered: March 2014
Karma: 0
Junior Member
add to buddy list
ignore all messages by this user
I was working on a software of arbitrary complexity when I stumbled upon this strange behavior of the PHP compiler.

Problem:
I have these interfaces and classes:

interface IBaseA {

}

interface IA extends IBaseA {

}

interface IBaseB {

public function match( IBaseA $subject );

}

interface IB extends IBaseB{
}

class A implements IA{

}

class B implements IB{
public function match( IA $subject ){
echo "Am I working? o_O<hr>";
}
}

$a = new A();
$b = new B();
$b->match($a);

Running the above code, this is what I get:
Fatal error: Declaration of B::match() must be compatible with that of IBaseB::match()

This behavior is very odd, because A implements IA that extends from IBaseA. So IA is an interface of type IBaseA. Methods I will put in IBaseA will be also in IA.
Class B accepts, in the match() method, an instance of IA.
Class B extends from IBaseB that in turn accepts an instance of IBaseA.

B should accept IA. In fact the interface that B implements accepts a more specific version of IA, but the Fatal Error still pops up.

The things become more strange if we look at another example.
This one:

interface IBaseA {

}

interface IA extends IBaseA {

}

interface IBaseB {

public function match( IA $subject );

}

interface IB extends IBaseB{
}

class A implements IBaseA{

}

class B implements IB{
public function match( IA $subject ){
echo "Am I working? o_O<hr>";
}
}

$a = new A();
$b = new B();
$b->match($a);

Here, what I get it's not a Fatal Error, but a Catchable Fatal Error.
This is an error that could be catched by this simple function:

function myErrorHandler($errno, $errstr, $errfile, $errline) {
if ( E_RECOVERABLE_ERROR===$errno ) {
echo "'catched' catchable fatal error<br>";
return true;
}
return false;
}
set_error_handler('myErrorHandler');

This time though, the compiler should not let me continue with the execution because:

B implements IB that extends from IBaseB.
IBaseB accepts instances of IA.
IA extends from IBaseA.
A implements IBaseA.

What i'm passing to the match() method of B is an instance of A, that is more strict that IA.
The compiler should throw a Fatal Error and it shouldn't let me continue with the execution! The inner details of B's match() implementation require an instance of IA with its own specific methods that could not be provided by IA's father, IBaseA.

Would you please shed a light onto this one?
What do you think about it?
Re: Strange but true! Working with interfaces in PHP [message #185456 is a reply to message #185450] Tue, 01 April 2014 12:43 Go to previous messageGo to next message
Jerry Stuckle is currently offline  Jerry Stuckle
Messages: 2598
Registered: September 2010
Karma: 0
Senior Member
add to buddy list
ignore all messages by this user
On 3/31/2014 6:31 PM, Mirco wrote:
> I was working on a software of arbitrary complexity when I stumbled upon this strange behavior of the PHP compiler.
>
> Problem:
> I have these interfaces and classes:
>
> interface IBaseA {
>
> }
>
> interface IA extends IBaseA {
>
> }
>
> interface IBaseB {
>
> public function match( IBaseA $subject );
>
> }
>
> interface IB extends IBaseB{
> }
>
> class A implements IA{
>
> }
>
> class B implements IB{
> public function match( IA $subject ){
> echo "Am I working? o_O<hr>";
> }
> }
>
> $a = new A();
> $b = new B();
> $b->match($a);
>
> Running the above code, this is what I get:
> Fatal error: Declaration of B::match() must be compatible with that of IBaseB::match()
>
> This behavior is very odd, because A implements IA that extends from IBaseA. So IA is an interface of type IBaseA. Methods I will put in IBaseA will be also in IA.
> Class B accepts, in the match() method, an instance of IA.
> Class B extends from IBaseB that in turn accepts an instance of IBaseA.
>
> B should accept IA. In fact the interface that B implements accepts a more specific version of IA, but the Fatal Error still pops up.
>
> The things become more strange if we look at another example.
> This one:
>
> interface IBaseA {
>
> }
>
> interface IA extends IBaseA {
>
> }
>
> interface IBaseB {
>
> public function match( IA $subject );
>
> }
>
> interface IB extends IBaseB{
> }
>
> class A implements IBaseA{
>
> }
>
> class B implements IB{
> public function match( IA $subject ){
> echo "Am I working? o_O<hr>";
> }
> }
>
> $a = new A();
> $b = new B();
> $b->match($a);
>
> Here, what I get it's not a Fatal Error, but a Catchable Fatal Error.
> This is an error that could be catched by this simple function:
>
> function myErrorHandler($errno, $errstr, $errfile, $errline) {
> if ( E_RECOVERABLE_ERROR===$errno ) {
> echo "'catched' catchable fatal error<br>";
> return true;
> }
> return false;
> }
> set_error_handler('myErrorHandler');
>
> This time though, the compiler should not let me continue with the execution because:
>
> B implements IB that extends from IBaseB.
> IBaseB accepts instances of IA.
> IA extends from IBaseA.
> A implements IBaseA.
>
> What i'm passing to the match() method of B is an instance of A, that is more strict that IA.
> The compiler should throw a Fatal Error and it shouldn't let me continue with the execution! The inner details of B's match() implementation require an instance of IA with its own specific methods that could not be provided by IA's father, IBaseA.
>
> Would you please shed a light onto this one?
> What do you think about it?
>

Mirco,

You didn't say what version of PHP you're running, so it's hard to
pinpoint exactly. However, Zend has had problems with inheritance in
the past; I would consider the first of these to be a bug. I think
you're correct - the code should work.

In the second case, I agree that this could be a runtime error, but I
also agree this should not be a catchable error. However when you set
an error handler, what happens after that is your responsibility. PHP
allows you to continue after a runtime error. Note the statement in the
PHP doc under set_error_handler:

"Also note that it is your responsibility to die() if necessary. If the
error-handler function returns, script execution will continue with the
next statement after the one that caused an error."

So this would be correct operation, IMHO.

I would suggest you submit a bug on the first problem and see what they
say. See http://bugs.php.net.

--
==================
Remove the "x" from my email address
Jerry Stuckle
jstucklex(at)attglobal(dot)net
==================
Re: Strange but true! Working with interfaces in PHP [message #185480 is a reply to message #185450] Thu, 03 April 2014 07:20 Go to previous messageGo to next message
Christoph Michael Bec is currently offline  Christoph Michael Bec
Messages: 207
Registered: June 2013
Karma: 0
Senior Member
add to buddy list
ignore all messages by this user
Mirco wrote:

> I was working on a software of arbitrary complexity when I stumbled
> upon this strange behavior of the PHP compiler.
>
> Problem: I have these interfaces and classes:
>
> [code sample]
>
> Running the above code, this is what I get: Fatal error: Declaration
> of B::match() must be compatible with that of IBaseB::match()

Confirmed on PHP 5.5.11.

> This behavior is very odd, because A implements IA that extends from
> IBaseA. So IA is an interface of type IBaseA. Methods I will put in
> IBaseA will be also in IA. Class B accepts, in the match() method, an
> instance of IA. Class B extends from IBaseB that in turn accepts an
> instance of IBaseA.
>
> B should accept IA. In fact the interface that B implements accepts a
> more specific version of IA, but the Fatal Error still pops up.

What you are assuming here is that type hints support covariance.
However, current PHP supports only invariance reliably. Consider the
following example:

class A {}
class B extends A {}
class C {function foo(A $var) {}}
class D extends C {function foo(B $var) {}}

The last line gives the following notice:

Strict standards: Declaration of D::foo() should be compatible with
C::foo(A $var)

It would be nice, if PHP accepts covariant type hints for function
parameters, but not doing it is not a bug. In this case it might be a
documentation bug, or rather a documentation omission -- at least I was
not able to find this behavior documented.

> The things become more strange if we look at another example. This
> one:
>
> [code sample]
>
> Here, what I get it's not a Fatal Error, but a Catchable Fatal
> Error.

PHP 5.5.11 gives:

Catchable fatal error: Argument 1 passed to B::match() must implement
interface IA, instance of A given

> This is an error that could be catched by this simple
> function:
>
> [error handler sample]
>
> This time though, the compiler should not let me continue with the
> execution because:
>
> B implements IB that extends from IBaseB. IBaseB accepts instances of
> IA. IA extends from IBaseA. A implements IBaseA.
>
> What i'm passing to the match() method of B is an instance of A, that
> is more strict that IA. The compiler should throw a Fatal Error and
> it shouldn't let me continue with the execution! The inner details of
> B's match() implementation require an instance of IA with its own
> specific methods that could not be provided by IA's father, IBaseA.

One might argue whether a Fatal Error is more appropriate here. After
all PHP is a dynamically typed language, and what is given here is only
a type *hint*, not a type declaration. In this case the program *could*
run without errors, because the $subject parameter is not used by the
function, and even if it was used, that doesn't necessarily imply that
the argument $a would be "incompatible". So a Catchable Fatal Error
might be more inline with PHP's dynamic typing.

PS: Please avoid overlong lines, because Google Groups can't properly
handle them.

--
Christoph M. Becker
Re: Strange but true! Working with interfaces in PHP [message #185482 is a reply to message #185450] Thu, 03 April 2014 10:19 Go to previous messageGo to next message
Daniel Pitts is currently offline  Daniel Pitts
Messages: 68
Registered: May 2012
Karma: 0
Member
add to buddy list
ignore all messages by this user
On 3/31/14 3:31 PM, Mirco wrote:
> I was working on a software of arbitrary complexity when I stumbled upon this strange behavior of the PHP compiler.
>
> Problem:
> I have these interfaces and classes:
>
> interface IBaseA {
>
> }
>
> interface IA extends IBaseA {
>
> }
>
> interface IBaseB {
>
> public function match( IBaseA $subject );
>
> }
>
> interface IB extends IBaseB{
> }
>
> class A implements IA{
>
> }
>
> class B implements IB{
> public function match( IA $subject ){
> echo "Am I working? o_O<hr>";
> }
> }
>
> $a = new A();
> $b = new B();
> $b->match($a);
>
> Running the above code, this is what I get:
> Fatal error: Declaration of B::match() must be compatible with that of IBaseB::match()
>
> This behavior is very odd, because A implements IA that extends from IBaseA. So IA is an interface of type IBaseA. Methods I will put in IBaseA will be also in IA.
> Class B accepts, in the match() method, an instance of IA.
> Class B extends from IBaseB that in turn accepts an instance of IBaseA.

The error here has nothing to do with "A" or the type of "A". What it is
saying is that "B::match(IA $subject)" is not compatible with
IBaseB::match(IBaseA $subject).

Think about it this way. If I ask for any "IBaseB" object, then I am
expecting to be able to pass in *any* IBaseA object to the match method.
However, your B::match won't accept just any old IBaseA object, but only
ones that implement IA as well.

So this is expected *and* desired.
OT: "overlong lines" Re: Strange but true! Working with interfaces in PHP [message #185494 is a reply to message #185480] Sat, 05 April 2014 04:50 Go to previous messageGo to next message
Luuk is currently offline  Luuk
Messages: 329
Registered: September 2010
Karma: 0
Senior Member
add to buddy list
ignore all messages by this user
On 3-4-2014 13:20, Christoph Michael Becker wrote:
> PS: Please avoid overlong lines, because Google Groups can't properly
> handle them.

But my client can.....

So, i do not get the point of this statement...
Re: OT: "overlong lines" Re: Strange but true! Working with interfaces in PHP [message #185495 is a reply to message #185494] Sat, 05 April 2014 06:00 Go to previous messageGo to next message
Tim Streater is currently offline  Tim Streater
Messages: 328
Registered: September 2010
Karma: 0
Senior Member
add to buddy list
ignore all messages by this user
In article <4ns41b-hje(dot)ln1(at)luuk(dot)invalid(dot)lan>, Luuk <luuk(at)invalid(dot)lan>
wrote:

> On 3-4-2014 13:20, Christoph Michael Becker wrote:
>> PS: Please avoid overlong lines, because Google Groups can't properly
>> handle them.
>
> But my client can.....
>
> So, i do not get the point of this statement...

I think some extra words crept into the PS above, which should have
read:

PS: Please avoid Google Groups.

--
Tim

"That excessive bail ought not to be required, nor excessive fines imposed,
nor cruel and unusual punishments inflicted" -- Bill of Rights 1689
Re: OT: "overlong lines" Re: Strange but true! Working with interfaces in PHP [message #185496 is a reply to message #185495] Sat, 05 April 2014 05:28 Go to previous messageGo to next message
Luuk is currently offline  Luuk
Messages: 329
Registered: September 2010
Karma: 0
Senior Member
add to buddy list
ignore all messages by this user
On 5-4-2014 12:20, Tim Streater wrote:
> In article <4ns41b-hje(dot)ln1(at)luuk(dot)invalid(dot)lan>, Luuk <luuk(at)invalid(dot)lan>
> wrote:
>
>> On 3-4-2014 13:20, Christoph Michael Becker wrote:
>>> PS: Please avoid overlong lines, because Google Groups can't properly
>>> handle them.
>>
>> But my client can.....
>>
>> So, i do not get the point of this statement...
>
> I think some extra words crept into the PS above, which should have
> read:
>
> PS: Please avoid Google Groups.
>

that makes more sence .....
"overlong lines" (was: OT: "overlong lines" Re: Strange but true! Working with interfaces in PHP) [message #185497 is a reply to message #185495] Sat, 05 April 2014 08:21 Go to previous messageGo to next message
Christoph Michael Bec is currently offline  Christoph Michael Bec
Messages: 207
Registered: June 2013
Karma: 0
Senior Member
add to buddy list
ignore all messages by this user
Tim Streater wrote:

> In article <4ns41b-hje(dot)ln1(at)luuk(dot)invalid(dot)lan>, Luuk <luuk(at)invalid(dot)lan>
> wrote:
>
>> On 3-4-2014 13:20, Christoph Michael Becker wrote:
>>> PS: Please avoid overlong lines, because Google Groups can't properly
>>> handle them.
>>
>> But my client can.....

Does your client really wrap overlong lines without distorting code
sections? I doubt so, because I'm using Thunderbird, too.

>> So, i do not get the point of this statement...
>
> I think some extra words crept into the PS above, which should have
> read:
>
> PS: Please avoid Google Groups.

IMHO, posting via Google Groups is okay, as long as one would be able to
work around its flaws, and adheres to generally agreed netiquette.

--
Christoph M. Becker
Re: "overlong lines" [message #185498 is a reply to message #185497] Sat, 05 April 2014 09:00 Go to previous messageGo to next message
Luuk is currently offline  Luuk
Messages: 329
Registered: September 2010
Karma: 0
Senior Member
add to buddy list
ignore all messages by this user
On 5-4-2014 14:21, Christoph Michael Becker wrote:
> Tim Streater wrote:
>
>> In article <4ns41b-hje(dot)ln1(at)luuk(dot)invalid(dot)lan>, Luuk <luuk(at)invalid(dot)lan>
>> wrote:
>>
>>> On 3-4-2014 13:20, Christoph Michael Becker wrote:
>>>> PS: Please avoid overlong lines, because Google Groups can't properly
>>>> handle them.
>>>
>>> But my client can.....
>
> Does your client really wrap overlong lines without distorting code
> sections? I doubt so, because I'm using Thunderbird, too.
>

I did not notice any such lines in the code that is snipped away now ;)

And i dont mind my news reader doing that, because if i want to look at
the source code, i copy/paste this in an editor (like Notepad++ ), so i
get syntax highlighting
Re: "overlong lines" [message #185499 is a reply to message #185498] Sat, 05 April 2014 09:28 Go to previous message
Christoph Michael Bec is currently offline  Christoph Michael Bec
Messages: 207
Registered: June 2013
Karma: 0
Senior Member
add to buddy list
ignore all messages by this user
Luuk wrote:

> On 5-4-2014 14:21, Christoph Michael Becker wrote:
>> Tim Streater wrote:
>>
>>> In article <4ns41b-hje(dot)ln1(at)luuk(dot)invalid(dot)lan>, Luuk <luuk(at)invalid(dot)lan>
>>> wrote:
>>>
>>>> On 3-4-2014 13:20, Christoph Michael Becker wrote:
>>>> > PS: Please avoid overlong lines, because Google Groups can't properly
>>>> > handle them.
>>>>
>>>> But my client can.....
>>
>> Does your client really wrap overlong lines without distorting code
>> sections? I doubt so, because I'm using Thunderbird, too.
>>
>
> I did not notice any such lines in the code that is snipped away now ;)

The longest line in the body of the OP[1] had 248 characters.

> And i dont mind my news reader doing that, because if i want to look at
> the source code, i copy/paste this in an editor (like Notepad++ ), so i
> get syntax highlighting

ACK. However, it is a problem to *reply* to such messages. In this
case I worked around the problem by snipping the code samples and
automatically reformatting the rest of the message.

[1] <news:bdfad044-74c3-4256-9ae2-2b6035d87ecc(at)googlegroups(dot)com>

--
Christoph M. Becker
Quick Reply
Formatting Tools:   
  Switch to threaded view of this topic Create a new topic
Previous Topic: Need help accessing the key array.
Next Topic: MYSQL PHP Query Not Working
Goto Forum:
  

-=] Back to Top [=-
[ Syndicate this forum (XML) ] [ RSS ]

Current Time: Thu Oct 19 23:34:41 EDT 2017

Total time taken to generate the page: 0.00825 seconds