PHP: what's the reason some people "fake" abstract methods by exclusively throwing an exception in the body? PHP: what's the reason some people "fake" abstract methods by exclusively throwing an exception in the body? symfony symfony

PHP: what's the reason some people "fake" abstract methods by exclusively throwing an exception in the body?


In this particular case, the comments explain:

/** * Executes the current command. * * This method is not abstract because you can use this class * as a concrete class. In this case, instead of defining the * execute() method, you set the code to execute by passing * a Closure to the setCode() method. * * @return int|null null or 0 if everything went fine, or an error code * * @throws LogicException When this abstract method is not implemented * * @see setCode() */protected function execute(InputInterface $input, OutputInterface $output){    throw new LogicException('You must override the execute() method in the concrete command class.');}

You could argue with the overall design as it is perhaps a bit hacky but it works well in practice. Take a look at Command::run to see where the decision to use a closure or execute is made. Bit of a niche case to say the least.

I know quite a bit of this was discussed in the comments of the other answer but I thought it might help to summarize. I also did a quick search through the Symfony framework code looking to see where the closure approach was used. Did not find anything. The closure support goes all the way back to the original 2.0 release so it might have one of those "seemed a good idea at the time" bits of functionality.


A possible use case is optional methods. If you make it abstract then all child classes need to implement it:

abstract class Database{    abstract public function export();}class MySQL extends Database{}

Fatal error: Class MySQL contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (Database::export)

If you make a regular method then child classes only need to implement the method if they plan to support it.

abstract class Database{    public function export(){        throw new \LogicException(__CLASS__ . ' driver does not support ' . __FUNCTION__);    }}class MySQL extends Database{}

... yet you get a nice error if you attempt to use it:

$s = new MySQL();$s->export();

Fatal error: Uncaught exception 'LogicException': MySQL driver does not support export


only abstract classes can have abstract methods.

You can't create object from abstract classes.

All abstract methods must be implemented in non-abstract classes.

Constructed Example:

Imagine the following:

abstract class Repository {    public abstract function read();    public abstract function write($object);    public abstract function delete($object);    public function connection() {        //this is implemented for you by the framework so you don't have to do it every time    }

Now you want to implement a repository for logging user-actions (logged-in, logged-out, ...)

You don't want any of those entries to be deleted and that's when you don't want to implement the delete function. But you have to, because your UserActionRepository is not abstract, because you actually need instances of it. that's when you throw an exception.