views:

83

answers:

5

I am using php 5.3, and yes, there is a bug open for that, but some think this is not a bug, and this makes me wonder.

abstract class A{
   private function bobo(array $in){
     //do something
   }
}

class B extends A{
   private function bobo($shmoo,$shmaa){
     //do something
   }
}

This throws an error. Shouldn't inheritance ignore private methods?!

'Declaration of B::bobo() should be compatible with that of A::bobo()'

A: 

I guess this is a design decision of the language. The Java language developers decided that this should be possible.

nhnb
:-) this looks to me like someone was forgetting to implement something.
Itay Moav
In Java it is completely different as the method signature consists of the method name, and parameter types. In PHP signature is the method name as you can call methods with extra parameters and access the extra parameters inside method. So PHP can only tell the minimum number of arguments required for a function, but no more.
Jari
The private method should not at all be visible in the sub class (see my test results of your sample code). So the different ways method signatures are defined is not important.
nhnb
That is exactly my point, private method should **not** affect the subclass, but it is...
Itay Moav
A: 

Private methods should certainly not be ignored by inheritance, consider for example Template method pattern where you may override behavior of a function in a derived class, but the parent class can still call that function

public class Parent {
    public final function doThings() {
        $this->initialize();
        $this->customStuff();
        $this->cleanup();
    }

    private final function initialize() {
        // initialize processing
    }

    private final function cleanup() {
        // cleanup processing
    }

    private function customStuff() {
        // parent specific processing
    }
}

public class Derived extends Parent {
    private function customStuff() {
        parent::customStuff();
        // + derived class specific processing
    }
}

Calling doThings method on Derived class instance will do parent specific processing, but because of possibility to override private methods it is still possible to take advantage of the extension point provided by the non-final parent class customStuff method.

EDIT: Also PHP method signature consists of only the method name as you can define a method taking zero parameters and still call it with multiple parameters. Function can then access the arguments using func_get_args function.

Jari
but you **can't** add a parameter to the Derived::customStuff. I am sorry, but I don't see how is your example relates to my question.
Itay Moav
You asked whether or not inheritance should ignore private methods and I provided an example why they should not be ignored
Jari
$derived = new Derived(); $derived->doThings(); will execute the customStuff() method of Parent and not the one of Derived.
nhnb
$derived = new Derived(); $derived->customStuff(); will result in the error: Fatal error: Call to private method ParentClass::customStuff() from context 'Derived'
nhnb
You showed how I access a private method in the parent class from a subclass, which is exactly not inheritance. You don't inherit a private method, so why would I need to keep the same signature, it is not like I defined it as abstract or in an interface. See this (throws an error as it should) `abstract class boo{ abstract private function moo();}`
Itay Moav
Hmm, you are all right... I see where I went wrong, I was too much shaded by the c++ virtual function call resolution mechanism. Leaving customStuff public in my example changes the behavior so that Derived class customStuff is actually called from parent class. Which makes me wonder if template method pattern can actually even be implemented properly in PHP.
Jari
+1  A: 

Note that the bug report is slightly off, as PHP will log this message any time you have an error level of E_STRICT (or, more recently, regardless of your error level provided that you've set a custom error handler).

PHP's visibility rules clearly demonstrate that a child lacks the ability to see its parent's private members, which I doubt is all that surprising to anyone. If the child can't see its parent's methods, I don't understand how it can have a duty to obey their definitions.

I personally think that the bug being marked as bogus without any explanation of why it wasn't a real flaw (since it's non-obvious and I couldn't find any mention of it in the documentation) is a bit wrong, but yeah. That aside, I'm of the opinion line 2669 in zend_compile.c should actually read as follows:

} else if (child->prototype &&
    (EG(error_reporting) & E_STRICT || EG(user_error_handler))) {

...which would avoid the error popping up when the parent's method was marked private. Given that you always have the option not logging E_STRICT though, and it doesn't really negatively impact anything, I suppose it's not really a big deal. I definitely don't see how it could have been intentional, but I'm not a PHP engine developer either.

Tim Stone
A: 

I think there are two possibilities here. Either it's a bug or the documentation on PHP.net/manual is incorrect. Here are three sections of the PHP manual. First on inheritance:

Object Inheritance

Inheritance is a well-established programming principle, and PHP makes use of this principle in its object model. This principle will affect the way many classes and objects relate to one another.

For example, when you extend a class, the subclass inherits all of the public and protected methods from the parent class. Unless a class overrides those methods, they will retain their original functionality.

This is useful for defining and abstracting functionality, and permits the implementation of additional functionality in similar objects without the need to reimplement all of the shared functionality.

And on abstract classes:

Class Abstraction

PHP 5 introduces abstract classes and methods. It is not allowed to create an instance of a class that has been defined as abstract. Any class that contains at least one abstract method must also be abstract. Methods defined as abstract simply declare the method's signature they cannot define the implementation.

When inheriting from an abstract class, all methods marked abstract in the parent's class declaration must be defined by the child; additionally, these methods must be defined with the same (or a less restricted) visibility. For example, if the abstract method is defined as protected, the function implementation must be defined as either protected or public, but not private.

Finally, interfaces

Object Interfaces

Object interfaces allow you to create code which specifies which methods a class must implement, without having to define how these methods are handled.

Interfaces are defined using the interface keyword, in the same way as a standard class, but without any of the methods having their contents defined.

All methods declared in an interface must be public, this is the nature of an interface.

Suffice it to say: there is nothing in the documentation that mentions inheritance of private methods. If there is a relationship between the parent and child method signatures, then it is not documented and the bug report should at least show someone that the documentation needs to be updated (if the decision to have this behavior is intentional). And if there was not supposed to be a relationship, then well, it's a real bug.

That's my opinion...

Tim
A: 

Hey,

In the bug report when you remove the interface there isn't an error. That makes it "more" strange behavior because the interface is just empty.

Greets, Sander

Sander