Alvaro Montoro
Alvaro Montoro

Reputation: 29695

Multiple constructors in an abstract class

I have an abstract class (simplified for demo):

abstract class MyClass {

    protected $id = "";
    protected $title = "";

    function __construct($title) {
        $this->id = strtolower($title);
        $this->titulo = $title;
    }

    abstract function render();
}

I want to add a second constructor in which to pass not only the title but also the id, but PHP doesn't seem to have method overloading. Searching online, I found a post on Stack Overflow where they suggest to create a static method which would create and return an instance of the same object, and function as an alternative constructor. Something like this:

static function create($id, $title) {
    $instance = new self($title);
    $this->id = $id;
    return $instance;
}

That works fine in regular classes, but it doesn't work with abstract classes like the one above. For example, when doing something like $myclass = MyClass::create("id", "title");, I get the error message:

Exception: Cannot instantiate abstract class MiClase

that happens in the line $instance = new self($title);, and which makes sense as it is trying to instantiate the own class that is an abstract class, which is not allowed.

Is it possible to have alternative constructors for abstract classes in PHP?

Upvotes: 1

Views: 428

Answers (2)

user1597430
user1597430

Reputation: 1146

<?php

abstract class MyClass
{
    protected $id    = '';
    protected $title = '';

    public function __construct(...$array)
    {
        switch (count($array))
        {
            case 2: $this->title = $array[1];
            case 1: $this->id    = $array[0]; break;
        }
    }
}

2nd way (for older PHP versions): you may replace ...$array with func_get_args inside the function (method) body to access to the list of passed variables.

3rd way: you may use simple arrays to pass arbitrary number of settings.

Upvotes: 1

Ermac
Ermac

Reputation: 1240

Here is a little approach:

<?php

abstract class MyClass {

    protected $id = "";
    protected $title = "";

    function __construct($title) {
        $this->id = strtolower($title);
        $this->title = $title;
    }

    static function createWithTitle($title) {
        $instance = new static($title);
        return $instance;
    }

    static function createWithIdAndTitle($id, $title) {
        $instance = new static($title);
        $instance->id = $id;
        return $instance;
    }

    abstract function render();
}

class Concrete extends MyClass {
    function render() {
        var_dump('id=' . $this->id, 'title=' . $this->title);
    }
}

Concrete::createWithTitle('Title')->render();

Concrete::createWithIdAndTitle(1, 'Title')->render();

Note the static keyword is very important here instead of self see Late Static Bindings

Upvotes: 1

Related Questions