-1

I have started using interface in PHP and after reading the docs, about both interface and abstract class, it was clear to me that:

  1. interface declares public methods. So any class implementing it, must also implement the methods.
  2. Abstract class is more like a partially completed class which needs more specifics when being extended.

So I am trying to create an abstract class, which implements the common methods, but for specialized method which may change based on child classes, are left abstract.

But instead of using abstract methods, I thought of using interface. The reason is, I do need a few static methods which I will use with late static binding. So I came up with the following pattern

<?php
interface Element {
    /**
     * Constructor function. Must pass existing config, or leave as
     * is for new element, where the default will be used instead.
     *
     * @param array $config Element configuration.
     */
    public function __construct( $config = [] );

    /**
     * Get the definition of the Element.
     *
     * @return array An array with 'title', 'description' and 'type'
     */
    public static function get_definition();

    /**
     * Get Element config variable.
     *
     * @return array Associative array of Element Config.
     */
    public function get_config();

    /**
     * Set Element config variable.
     *
     * @param array $config New configuration variable.
     *
     * @return void
     */
    public function set_config( $config );
}

abstract class Base implements Element {

    /**
     * Element configuration variable
     *
     * @var array
     */
    protected $config = [];

    /**
     * Get Element config variable.
     *
     * @return array Associative array of Element Config.
     */
    public function get_config() {
        return $this->config;
    }

    /**
     * Create an eForm Element instance
     *
     * @param array $config Element config.
     */
    public function __construct( $config = [] ) {
        $this->set_config( $config );
    }
}

class MyElement extends Base {

    public static function get_definition() {
        return [
            'type' => 'MyElement',
        ];
    }

    public function set_config( $config ) {
        // Do something here
        $this->config = $config;
    }
}

$element = new MyElement( [
    'foo' => 'bar',
] );

print_r( $element->get_config() );

This works good with PHP7. As you can see, I haven't declared something like

abstract public function set_config( $config );

in the abstract class.

Since the method is implemented in the MyElement class, it works just fine. If I do not implement the method in MyElement class, then I get an error

PHP Fatal error: Class MyElement contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (Element::set_config)

which is exactly what I want.

So my question, is the implementation pattern correct? This works with PHP 7.1, but will PHP 5.4+ all behave the same? Or am I doing something anti-pattern?

Swashata Ghosh
  • 988
  • 8
  • 15

1 Answers1

0

To answer my own question

An abstract class does not need to implement methods from an interface.

An abstract class is considered "incomplete" by nature, so an method it inherits from an interface is considered abstract by default, if it doesn't implement it.

This is also clear in the error message

PHP Fatal error: Class MyElement contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (Element::set_config)

But because the class Base is already declared abstract it does not need to implement the remaining methods, only non-abstract class inheriting from the Base class.

I have run tests here https://3v4l.org/8NqqW and as you can see starting PHP 5.4 upword, the outputs are just same.

Swashata Ghosh
  • 988
  • 8
  • 15