Forcing method override of parent PHP class

I have a situation that, despite a significant amount of googling / SO'ing, seems to have eluded me. Here's the problem in a nutshell:

Situation

PHP 5.3+ (but not defined yet - I am actually running 5.5 / 6, but the environment tends to be flexible).

I am trying to write a solid implementation that will get other developers to follow the best practices.

I have a parent class:

class A {
    public function doSomething() {
        // does something
    }
}

      

The standard use case is A::doSomething

.

Extension is required in special cases.

class B extends A {
    public function doSomething() {
        // does something .. AND
        $this->doSomethingElse()
    }

    private function doSomethingElse() {
        // does something else
    }
}

      

If I want to do something, then I can A::doSomething

.
If I want to do something and do something, then I can B::doSomething

.

To be consistent with other developers' forc [ing] transition to best practice, I implemented the interface:

interface C {

    public function doSomething() {
        // does something else
    }

    public function doSomethingElse() {
        // does something else
    }
}

      

Class B then implements interface C. Sounds simple enough?

class B implements C {
    public function doSomething() {
        // does something .. AND
        $this->doSomethingElse()
    }

    private function doSomethingElse() {
        // does something else
    }
}

      

I don't want to assume that the child B

implements C

.
There may be a number of well-founded reasons for expanding A

to E

where one E

does not want to implement C

.

My question is:

If I do the following and don't implement the method doSomething

, then the following has no errors:

class B implements C {
    private function doSomethingElse() {
        // does something else
    }
}

      

.. as expected; A

provides doSomething

for B

to meet the requirement for C

.

The problem is that this would allow someone to write an incomplete method that would not throw errors. In the above case, B::doSomething

does not call B::doSomethingElse

.

Is it possible for a method, interface (or similar method) to require a child in order to implement the method at the current inheritance level?

Of course I can write notes, documentation, etc., but the point of the interface is to get people to do it right!

Other people who asked similar questions were either (sometimes understandable) or misunderstood, or the response to stocks was "wrong architecture" ... Which I would like to dispute, as shown in the example below:

Here's an example with real world elements:

  • A = Shop for sale: ShopItem
  • B = Beer Shop Item: Beer
  • C = BoozeInterface: the interface that .. talks about the requirements for startup IDs
  • D = Vegetable shop item: Vegetables

A might have a method called for example ... A::attemptToBuy


C

will apply methods like id.

Beer

and Vegetable

- both ShopItem types.
This is standard and logical inheritance.

Beer

should use BoozeInterface

(or something suitable). This also applies to not yet implemented, but possibly future requirements Wine

, Spirit

etc. Etc.

Some elements are perfect for the general class ShopItem

. They don't need any additional functionality. ShopItem::attemptToBuy

is a common use case.

However - I have to rely on someone to remember the overrides Wine::attemptToBuy

and Spirit::attemptToBuy

.

As you can see - if I really want to block it, I would ideally be able to force it to override the current inheritance level. (I'm sure there are better examples of this, but I've tried to make it as obvious as possible.)

I'm glad if the answer is "no, you can't do that" ... I just want to know if you can. I'm working with code, but just with a direct override that is not provided. But I want it to be forced!

Thanks in advance. Rick

+3


source to share


2 answers


Why not do an abstraction of class A and require methods like this:

abstract class A
{
    abstract protected function doSomething() {}
    abstract protected function doSomethingElse() {}
}

      



Now any class that extends class A must define these two methods.

Hooray!

+1


source


I think you are going backwards on it - I am not sure if you want to apply override (easy to do with abstract methods) in subclasses created by the developer client, you want to provide a method that cannot be overridden in the abstract classes you provide. to ensure that it does what you want?

If you provide abstract classes ShopItem

and BoozeItem

thus:

<?php

// base ShopItem with default `attemptToBuy` functionality
abstract class ShopItem {

    public function attemptToBuy() {
        echo "buying ShopItem";
    }
}

// Booze sub-class, with an override on `attemptToBuy` 
// (e.g. applying age restrictions check)
abstract class BoozeItem extends ShopItem {

    final public function attemptToBuy() {
        echo "buying BoozeItem";
    }
}

?>

      

The client developer can then happily create their own class Beer

that extends the subclass BoozeItem

.



<?php

class Beer extends BoozeItem { }

$oBevvy = new Beer();
$oBevvy->attemptToBuy();

?>

      

Outputs: Buying BoozeItem

Since it is BoozeItem::attemptToBuy()

declared final

, it cannot be overridden Booze::attemptToBuy()

(trying to create this method will throw an error) - therefore the functionality of your object is locked.

Beer

can be extended to Lager

or Ale

(for example) and they inherit attemptToBuy()

from BoozeItem

(as Beer

extends BoozeItem

) , but they won't be allowed to override this method as it is declared final

- it just inherits with certain behavior. This is not what you want, but it is probably the closest thing you can think of.

0


source







All Articles