Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

nolros's avatar
Level 23

parent:: inheritance question

// 1. To enforce or extend the parent __construct do I always need to inject parent:: i.e extends doesnt just inherit __contruct?
// 2. I need to pass through the parent constructors I want to inherit and this can be all or a subset?
// 3. Can I extend to grandchild using the following syntax?

MyChildClass extends ParentClass {

    protected $childVal = null;

    function __construct($parentContructVal1, $parentContructVal1, $childVal)
    {
        parent::__contruct($parentContructVal1, $parentContructVal1);
    }

}

MyGrandChildClass extends MyChildClass {

    protected $grandChildVal = null;

    function __construct($parentContructVal1, $parentContructVal1, $childVal)
    {
        parent::__contruct($parentContructVal1, $parentContructVal1);
    }

}

0 likes
7 replies
usman's avatar

Only subclasses having their own constructors need to call the parent class constructor explicitly . If a subclass does not implement its own constructor the parent constructor is called automatically.

Also if a class in inheritance chain does not implement its own constructor the parents are called implicitly. e.g:

<?php

class Foo {

    public function __construct()
    {
        echo 'Foo ';
    }
}

class Bar extends Foo {


}

class Baz extends Bar {

    public function __construct()
    {
        echo 'Baz ';
        parent::__construct();
    }
}

new Baz;
//output: Baz Foo.
2 likes
JarekTkaczyk's avatar
Level 53

@nolros

  1. No, you don't have to do this just to call parent::__construct(...) - it will be called/inherited like any other method. Yes, you have to call parent::__construct(...) if you want/need to define the constructor in child class = override it AND you need parent constructor to be called (most likely you do). To be clear it's not injecting.
  2. Clarify this question.
  3. No, it cannot be done, since MyChildClass requires 3rd parameter, so you have to pass it. However you can skip parent constructor and jump to the grandparent (must-read the comment below):
class Foo {
    public function __construct($foo)
    {
        echo 'foo: '.$foo.PHP_EOL;
    }
}

class Bar extends Foo{
    public function __construct($foo, $bar, $baz)
    {
        parent::__construct($foo);

        echo 'bar: '.$bar.PHP_EOL;
        echo 'baz: '.$baz.PHP_EOL;
    }
}

class Baz extends Bar {

    public function __construct($foo, $baz)
    {
        // call constructor in the inheritance chain
        Foo::__construct($foo);

        echo 'baz: '.$baz.PHP_EOL;
    }
}

// then:
[1] > new Bar('first', 'second', 'third');
foo: first
bar: second
baz: third

[2] > new Baz('first', 'third');
foo: first
baz: third

But consider it just as a curiosity, since you probably do not want to do that. Imagine you have a dependency in the Bar class, that you skipped, but half of the method rely on this dependency - you're screwed.

1 like
nolros's avatar
Level 23

@JarekTkaczyk dude you have great way of communicating. I absolutely get it, but like all your posts makes me want to ask just one more question :) Please don feel obligated to answer, I take no offense as this is for my edification only.

If that is the case and I want to create a prototype pattern for a large application to mimic mult level inheritance, lets say persistence architecture below below. Probably more of an academic question / example, but could I in PHP create multiple level inheritance (not really) with this type of approach or am I really just attempting to mimic an interface+.

Let's say in the example the constructor for all would require a UUID4, path, name, type, state, queue (for example). Can I maintain that consistency, or do I want to with this type of approach? or have I just illustrated a use case for Factory pattern?

Class FileRepository {}
Class FileSystemRepo extends FileRepository {} // parent::__construct from  FileRepository
Class AWSRepo extends FileSystemRepo {} // parent::__construct  FileSystemRepo

Class DBRepository {}  // parent::__construct from  FileRepository
Class EloquentRepo extends DBRepository {} // parent::__construct from  DBRepository
Class MongoRepo extends EloquentRepo {} // parent::__construct from  MongoRepo

Class CacheRepository {} // // parent::__construct from  DBRepository
Class LaravelRepo extends CacheRepository {} // parent::__construct from  CacheRepository
Class MEMECacheRepo extends LaravelRepo {}  // parent::__construct from  LaravelRepo

Class SuperStorageClass{
    private FileRepository;
    private DBRepository;
    private CacheRepository;

     function __construct(FileRepository $fileRepository, DBRepository $dBRepository, CacheRepository $cacheRepository)
    {
        // exclude init for brevity
    }

    function getFileRepository()
    {
        return clone $this->fileRepository;
    }

    function getDBRepository()
    {
        return clone $this->dBRepository;
    }

    function getCacheRepository()
    {
        return clone $this->cacheRepository;
    }

}
nolros's avatar
Level 23

@usman sorry man, missed your post until now and I think you answered my lengthy question above :) In essence PHP can multi-chain inheritance but is still single tier as I can only extend 1 class? However, I can chain and extend the constructor as long as I want ... just one bridge at a time?

However, on a separate, but somewhat related topic, why does Jeff use ServiceProviders to do some of that bridging when it can be accomplished in PHP? Why would I use an SP to link RepoInterface to DBRepo to FileRep, etc. when PHP will let me do with the above example?

Again, don't feel compelled to answer no offense taken.

Cheers Nolan

JarekTkaczyk's avatar

@nolros

ServiceProviders are bootstrapping your application, ie. they create required connections, bindings etc so you can do this:

$foo = App::make('Namespace\FooInterface');

somewhere in your code and let IoC Container take care of the implementation (let it be MysqlFoo or MongoFoo, PaypalBilling or StripeBilling etc). With this in place you need only to change one binding (in a service provider or wherever you did that) whenever you change implementation (use different package to do some job etc):

App::bind('Namespace\FooInterface', 'Namespace\MySql\Foo`);
// to
App::bind('Namespace\FooInterface', 'Namespace\Mongo\Foo`);

instead of editing your whole codebase and replacing 'manually' all occurences of:

$foo = new Namespace\MySql\Foo;
// to
$foo = new Namespace\Mongo\Foo;

Of course this is just a sensible example of their job, SP often do more work than just binding to IoC.


Next, you can have multiple level inheritance of course. Prototype and Factory are similar patterns, you can use one or the other, depending on your needs and liking. There's never one and only, right way of doing anything in programming, and that's the beauty of it. So whenever someone tells you you must use pattern X here or you should do this, because I tell you. in terms of design, you may want to discuss it with someone else to form your opinion.

Anyway, while DbRepo and CacheRepo could be substitutes in some cases, I wouldn't consider FileRepo the same, so I think that your example does too much.

Like above, there's no right way, but you definitely want your code to be SOLID, because it makes it soo much easier to work with. These are basic principles everyone should understand for their own good (and their coworkers too).

Oh, and btw, another thing: constructor is supposed to do just one thing in mot cases - accept dependencies. If you stick to it, then your code will be much more consistent, and you can use IoC goodness too.

IoC won't instantiate an object with construtor like this:

// $bar & $baz are scalar types (number / string / bool)
public function __construct(FooInterface $foo, $bar, $baz) {..}

Only immutable instances (for example value objects) should (and must) accept config in the constructor, because of their immutability:

$fixedArray = new SplFixedArray(10);

SplFixedArray is 'real' array type in PHP, while simple array is a bit of misconception - it's a mix for developer's convenience.

1 like
nolros's avatar
Level 23

@JarekTkaczyk seriously you have a great way of communicating. I find that all too often when explaining new concepts people tend to communicate the functionality vs. context. The question that is very seldom answered is, "as opposed to what". Example, I'm building all that now without the use of ServiceProviders so why should I add more complexity? Your example brought it home for me. Yes, you can do it without a SP, but that means you are going to need to bind it to the namespace manually, i.e. use ... and then if anything changes you will walking through all occurrences. I also now get while you binding you can also add further logic to increase it's value add.

The other challenge as you stated is understanding when to apply what pattern, but that I think comes through time and experience. Example, I suppose I could use a SP or in certain cases I could, for example, Factory pattern to build classes. OOP and DDD are great, but sometimes I find myself lost in abstraction or over complicating something.

instead of editing your whole codebase and replacing 'manually' all occurences of:

$foo = new Namespace\MySql\Foo;
// to
$foo = new Namespace\Mongo\Foo;

Of course this is just a sensible example of their job, SP often do more work than just binding to IoC.

JarekTkaczyk's avatar

@nolros cheers! The important thing to consider is that you don't want to depend on external implementation (like MySql vs Mongo).

If you create an application using a framework, being one-man-army, you probably don't even think about it, because you treat it as a whole. However when you start building packages, that should be independent from each other, you begin to understand why and how that works.

Later on, or if you're part of a team, there's no way to build dependent code, because you can't be sure what the other modues will look like. You need to abstract the way these modules communicate (interfaces) and you don't have to care, how the others implement things, as long as these are based upon the abstraction you know.

Please or to participate in this conversation.