简体   繁体   中英

Child class listening to static parent method

I'm pretty sure my question has been answered somewhere but it seems I can't find an answer, so here I try.

Is there a way for a child class to listen to a static method of its parent class and execute one of its static methods ? Or should it use an interface, and if so, how would you do it ?

The best example is with the Command class : you have that :

class Command {
    public static function execute($name, $args) {
        // Do something
    }
}

And when you call that method execute, all subclasses see if name corresponds to their name.

class Subcommand extends Command {
    public static $name = "command";

    public static function execute($name, $args) {
        if (self::$name === $name) {
            // Do something
        }
    }
}

The thing is there must be multiple classes such as Subcommand and I don't want to manually call all of them, there should be something to do that automatically.

For now, I've just put an array in the Command class like that :

$commands = [
    Subcommand1::class,
    Subcommand2::class,
    Subcommand3::class
    // …
]

And I iterate over it and call the execute method of each subclass but I was hoping there could be something more elegant to achieve that.

Actually, I think that your current approach is the elegant one (look at the Command design pattern).

As I understand, what you are trying to achieve is to execute a method of all registered subclasses of Command . This is not elegant at least by two points . Firstly , you have to filter out your subclasses from all declared classes (using get_declared_classes ). This can be pretty exhaustive. Secondly , in such case, you can control the number of commands to be executed only by adding or removing them classes. This actually defeats the purpose of OOP ( Object -Oriented Programming, not Class-Oriented Programming). The flow of your program should be defined by the interaction of object.

The $name parameter to execute() feels like it needs examining here:

  • What are its valid values? (Is it completely free-form, or selected from some enum?)
  • How do they relate to sub-commands? (1-to-1? 1-to-many? many-to-many?)
  • How does the caller choose it?

I'd be tempted to say that the caller of execute() shouldn't be passing in that information; if it knows which command to use, it should be constructing an object representing that command.

If each name corresponds 1-to-1 to a sub-command, then the caller can just instantiate the sub-command class. If it's a 1-to-many or many-to-many relationship, you would need some additional "command type" classes; or you could construct the same object each time, but with a list of sub-commands it should dispatch to.

You might also want a factory method which is given the name of the command, and constructs an appropriate sub-command or command type. That allows the choice of command to be dynamic, eg from user input, and keeps any complex the logic about what object to create in one place. That could be a hard-coded switch statement where you manage all the name-to-class relationships, or it could be a registry, where new sub-classes can register for particular command names.

The last case is essentially the Observer pattern: the command names are events, and the sub-classes have registered to observe them. As sevavietl this makes the relationships more explicit: the existence of a class shouldn't normally trigger behaviour if that class isn't actually listed anywhere. This is particularly true in PHP, where classes are generally only looked up on disk when they are first referenced, so you don't actually know at run-time how many classes your project contains.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM