Mastering PHP-DI: A Step‑by‑Step Guide to Dependency Injection in Webman
This tutorial explains what a Dependency Injection (DI) container is, shows how to install php-di, demonstrates basic usage including container creation, automatic wiring, constructor and annotation injection, and provides custom injection techniques for the Webman framework with concrete code examples.
What is a Dependency Injection Container?
A Dependency Injection (DI) container is an object that knows how to instantiate and configure a class together with all of its required dependencies.
Installation
composer require php-di/php-diBasic Usage
1. Write code without DI
class Mailer
{
public function mail($recipient, $content)
{
// send an email to the recipient
}
}
class UserManager
{
private $mailer;
public function __construct(Mailer $mailer)
{
$this->mailer = $mailer;
}
public function register($email, $password)
{
// ... create user account ...
$this->mailer->mail($email, 'Hello and welcome!');
}
}Here UserManager receives a Mailer instance via its constructor – that is the essence of DI.
2. Create a container
$container = new DI\Container();If you need to adjust options, use the builder:
$builder = new DI\ContainerBuilder();
$builder->... // configure definitions, autowiring, etc.
$container = $builder->build();3. Let the container create objects
$mailer = new Mailer();
$userManager = new UserManager($mailer);With php-di you can replace the manual wiring: $userManager = $container->get('UserManager'); The container automatically creates a Mailer and injects it into UserManager.
The container uses autowiring : it scans constructors, determines required parameters, and resolves them automatically. This technique is not unique to php-di but works very well.
Using php-di with the Webman Framework
Webman disables automatic DI by default. To enable it, install the required packages:
composer require psr/container ^1.1.1 php-di/php-di ^6 doctrine/annotations ^1.14Configure the container in config/container.php:
$builder = new \DI\ContainerBuilder();
$builder->addDefinitions(config('dependence', []));
$builder->useAutowiring(true);
$builder->useAnnotations(true);
return $builder->build();The returned instance complies with the PSR‑11 container interface. If you prefer another PSR‑11 implementation, you can return a different container here.
Constructor Injection in Webman
Create a service class app/service/Mailer.php:
<?php
namespace app\service;
class Mailer
{
public function mail($email, $content)
{
// 发送邮件代码省略
}
}And a controller app/controller/UserController.php that receives the service via its constructor:
<?php
namespace app\controller;
use support\Request;
use app\service\Mailer;
class UserController
{
private $mailer;
public function __construct(Mailer $mailer)
{
$this->mailer = $mailer;
}
public function register(Request $request)
{
$this->mailer->mail('[email protected]', 'Hello and welcome!');
return response('ok');
}
}When php-di is used, Webman will automatically instantiate UserController and inject a Mailer instance; no manual new calls are needed.
Note: Only objects created by the framework or php-di can receive automatic injection. Manually instantiated objects ( new ) will not be injected unless you use support\Container to create them.
use app\service\UserService;
use app\service\LogService;
use support\Container;
// Instances created with new cannot be injected
$user_service = new UserService;
$log_service = new LogService($path, $name);
// Instances created via the container can be injected
$user_service = Container::get(UserService::class);
$log_service = Container::make(LogService::class, [$path, $name]);Annotation Injection
You can also inject dependencies using annotations:
<?php
namespace app\controller;
use support\Request;
use app\service\Mailer;
use DI\Annotation\Inject;
class UserController
{
/**
* @Inject
* @var Mailer
*/
private $mailer;
public function register(Request $request)
{
$this->mailer->mail('[email protected]', 'Hello and welcome!');
return response('ok');
}
}This achieves the same result as constructor injection but with less boilerplate.
Note: Versions of Webman prior to 1.4.6 do not support controller‑parameter injection. The following code will not work on those versions:
<?php
namespace app\controller;
use support\Request;
use app\service\Mailer;
class UserController
{
// 1.4.6 之前不支持控制器参数注入
public function register(Request $request, Mailer $mailer)
{
$mailer->mail('[email protected]', 'Hello and welcome!');
return response('ok');
}
}Custom Constructor Injection for Primitive Parameters
If a constructor requires scalar values (e.g., SMTP host and port), php-di cannot infer them automatically. Define them manually in a definitions file, e.g., config/dependence.php:
return [
// ... other definitions ...
app\service\Mailer::class => new app\service\Mailer('192.168.1.11', 25),
];Now the container will use this definition when resolving app\service\Mailer. For more complex scenarios, you can still retrieve instances with Container::get() or Container::make() and pass the required arguments.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Open Source Tech Hub
Sharing cutting-edge internet technologies and practical AI resources.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
