1

So I’m kinda stuck wrapping my head around this whole parent-child dependency thing. My assumption was, once you declare all the dependencies in the parent (BaseController), the child (like IndexController) wouldn’t need to declare them again in its own constructor; it could just rely on parent::__construct(). Tried removing the four dependencies from IndexController, but got hit with an error. Basically, you still gotta re-declare those four deps in the child’s constructor so they can be passed up to parent::__construct(). At least that's what the AI told me. Lastly, are those use statements really necessary to be in every file?

BaseController.php

 <?php use App\Models\SiteSettings; use App\Services\{ AuthService, LoggerService, MessageService }; class BaseController { public function __construct( protected SiteSettings $siteSettings, protected AuthService $authService, protected LoggerService $loggerService, protected MessageService $messageService ) {} } 

IndexController.php

<?php use App\Models\SiteSettings; use App\Services\{ AuthService, LoggerService, MessageService }; class IndexController extends BaseController { public function __construct( SiteSettings $site_settings, AuthService $auth_service, LoggerService $logger_service, MessageService $message_service, private ServersRepository $serversRepository, private ServerFilter $serverFilter, private CategoriesRepository $categoriesRepository, private LanguagesRepository $languagesRepository ) { parent::__construct( $site_settings, $auth_service, $logger_service, $message_service ); } $this->messageService->get('MSG_LOGIN_SUCCESS'); } 

Container.php

<?php use App\Models\SiteSettings; use App\Services\{ AuthService, LoggerService, MessageService }; class Container { public function __construct() { $this->factories[IndexController::class] = function (Container $c) { return new IndexController( $c->get(SiteSettings::class), $c->get(AuthService::class), $c->get(LoggerService::class), $c->get(MessageService::class), $c->get(ServersRepository::class), $c->get(ServerFilter::class), $c->get(CategoriesRepository::class), $c->get(LanguagesRepository::class) ); }; } 
4
  • 1
    the code block delimiters ``` must be on a separate line, both top and bottom... please correct it Commented Sep 29 at 3:25
  • Is this PHP 8+? Are you using an autoloader? Commented Sep 29 at 4:57
  • 1
    I'd argue the term "dependency" is really more a logical thing that we talk about in relation to frameworks or programming patterns. At the PHP level itself, as shown here, we just have constructors with parameters and because you are calling the constructor via new IndexController it is your burden to satisfy the requirements. If you are using a framework it is possible that it has a pattern to resolve this for you automatically. For instance, instead of manually instantiating something you'd instead ask the framework for an instance for you, and it resolves the dependencies on your behalf. Commented Sep 29 at 14:56
  • 1
    Looking at the Container.php file, it appears you are the framework, so you are ultimately responsible for satisfying the PHP constructor. If you don't want that you might be able to get there via reflection, or you can switch your code to use dedicated properties instead of constructor promoted ones. Commented Sep 29 at 14:58

1 Answer 1

0

This whole parent-child dependency things is called inheritance, and what you call "dependencies" are simply parameters. If you want to use the constructor of your parent class, then you HAVE to provide the required parameters. This is simply how inheritance work.

If you don't want to have to specify the required dependencies in your "Child" controller, then maybe you could use your Container to import the dependencies required by your BaseController directly in it's constructor, rather than rely on the parameters:

class BaseController { protected SiteSettings $siteSettings; protected AuthService $authService; protected LoggerService $loggerService; protected MessageService $messageService; public function __construct() { $container = /** get the container somehow **/ $this->siteSettings = $container->get(SiteSettings::class); $this->authService = $container->get(AuthService::class); $this->loggerService = $container->get(LoggerService::class); $this->messageService = $container->get(MessageService::class); } } 

This allow you to load the required dependencies while keeping your constructor params empty. Then, your "child controller" only have to specify their parameters and call parent::__construct().

class IndexController extends BaseController { public function __construct( private ServersRepository $serversRepository, private ServerFilter $serverFilter, private CategoriesRepository $categoriesRepository, private LanguagesRepository $languagesRepository ) { parent::__construct(); } } 

Please note that

public function __construct(protected SiteSettings $siteSettings) {} 

is simply a shorter version of:

protected SiteSettings $siteSettings public function __construct(SiteSettings $siteSettings) { $this->siteSettings = $siteSettings; } 

So the constructor of the BaseController will behave exactly as in your first example.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.