快速开始
5 分钟上手 Wirebox。
安装
通过 Composer 安装 Wirebox:
composer require ascetic-soft/wirebox
环境要求:
- PHP >= 8.4
- psr/container ^2.0
创建第一个容器
第一步:创建服务
// src/Mailer.php
namespace App;
class Mailer
{
public function send(string $to, string $message): void
{
// 发送邮件...
}
}
// src/UserService.php
namespace App;
class UserService
{
public function __construct(
private Mailer $mailer,
) {
}
public function register(string $email): void
{
// 创建用户...
$this->mailer->send($email, '欢迎!');
}
}
第二步:构建容器
// bootstrap.php
use AsceticSoft\Wirebox\ContainerBuilder;
require_once __DIR__ . '/vendor/autoload.php';
$builder = new ContainerBuilder(projectDir: __DIR__);
$builder->scan(__DIR__ . '/src');
$container = $builder->build();
第三步:获取并使用服务
$userService = $container->get(App\UserService::class);
$userService->register('user@example.com');
Wirebox 自动将 Mailer 作为 UserService 的依赖进行解析——无需手动配置。
自动装配原理
当你调用 $container->get(UserService::class) 时,Wirebox:
- 通过反射检查
UserService的构造函数 - 发现需要一个
Mailer实例 - 递归解析
Mailer(必要时创建) - 将其注入
UserService的构造函数 - 返回完全构造好的
UserService
一切自动完成,无需配置文件或手动绑定。
默认情况下,所有服务都是单例——每次调用 get() 返回相同的实例。使用 #[Transient] 属性可以在每次获取时创建新实例。
使用接口
当代码依赖接口时,如果只有一个实现类,Wirebox 会自动绑定:
// src/LoggerInterface.php
namespace App;
interface LoggerInterface
{
public function log(string $message): void;
}
// src/FileLogger.php
namespace App;
class FileLogger implements LoggerInterface
{
public function log(string $message): void
{
file_put_contents('/var/log/app.log', $message . "\n", FILE_APPEND);
}
}
// src/OrderService.php
namespace App;
class OrderService
{
public function __construct(
private LoggerInterface $logger,
) {
}
}
由于 FileLogger 是扫描目录中 LoggerInterface 的唯一实现,Wirebox 自动绑定该接口:
$builder->scan(__DIR__ . '/src');
$container = $builder->build();
$orderService = $container->get(App\OrderService::class);
// LoggerInterface 自动绑定到 FileLogger
如果有多个实现,则需要显式绑定:
$builder->bind(App\LoggerInterface::class, App\FileLogger::class);
添加环境变量
在项目根目录创建 .env 文件:
DB_HOST=localhost
DB_PORT=5432
APP_DEBUG=true
使用 #[Param] 属性注入环境变量:
use AsceticSoft\Wirebox\Attribute\Param;
class DatabaseService
{
public function __construct(
#[Param('DB_HOST')] private string $host,
#[Param('DB_PORT')] private int $port,
) {
}
}
或通过构建器定义参数:
$builder->parameter('db.host', '%env(DB_HOST)%');
$builder->parameter('db.port', '%env(int:DB_PORT)%');
完整 Bootstrap 示例
<?php
// bootstrap.php
use AsceticSoft\Wirebox\ContainerBuilder;
require_once __DIR__ . '/vendor/autoload.php';
$builder = new ContainerBuilder(projectDir: __DIR__);
// 排除非服务类
$builder->exclude('Entity/*');
$builder->exclude('Migration/*');
// 自动注册 src/ 下所有类
$builder->scan(__DIR__ . '/src');
// 歧义接口的显式绑定
$builder->bind(LoggerInterface::class, FileLogger::class);
$builder->bind(CacheInterface::class, RedisCache::class);
// 环境参数
$builder->parameter('db.host', '%env(DB_HOST)%');
$builder->parameter('db.port', '%env(int:DB_PORT)%');
$builder->parameter('app.debug', '%env(bool:APP_DEBUG)%');
// 复杂实例化的工厂
$builder->register(PDO::class, function ($c) {
return new PDO(
sprintf('mysql:host=%s;port=%d;dbname=app',
$c->getParameter('db.host'),
$c->getParameter('db.port'),
),
);
});
// 构建并运行
$container = $builder->build();
$app = $container->get(App\Kernel::class);
$app->run();