Stefano php, milano

How to hide a class method in PHP

Normally, when you extend a class and ovveride one method, you can change its visibility, but only to widen it. You can make a private method protected or public, and a protected method public. This is because restricting the visibility of a method would break the Liskov substitution principle as it would not allow to use the subclass in place of its superclass.

This is also true for PHP at least when you use classical inheritance, and will fail badly if you even try to override a public method with a private or protected one:

class Utility { 
    public function methodTwo()
    {

    }
}
class Driver extends Utility 
{ 
    protected function methodTwo()
    {

    }
}

The code above will throw a fatal error:

PHP Fatal error:  Access level to Utility::methodTwo() must be public (as in class Utility) in php shell code on line 1

So, if you're trying to reduce the visibility of a method of an existing class, you're out of luck. You'll have to either override the method to make it throw a BadMethodException, change the code of the superclass or, perhaps, just live with it.

It turns out though, that PHP supports reducing the visibility of a method defined inside a trait. So, if you know that you'll need to hide methods of a superclass, you might consider to implement such superclass as a trait:

trait Utility {
    public function methodOne() 
    {

    }
    public function methodTwo() 
    {

    }
}

class Driver {

    use Utility;

    protected function methodTwo()
    {

    }
}

And here we go:

php > $driver = new Driver;
php > $driver->methodTwo();

PHP Fatal error:  Call to protected method Driver::methodTwo() from context '' in php shell code on line 1

As you see, the method has been hidden and it's unreachable from the outer context.

Nota bene

As usual with protected and private methods, you cannot use method_exists to check if a method is callable or not, as it will return true no matter what the visibility is. You have to use is_callable:

php > var_dump(is_callable([$driver, 'methodOne']));
bool(true)
php > var_dump(is_callable([$driver, 'methodTwo']));
bool(false)

That's it, have fun!

Tags: php