ZF2迁移至ZF3:如何获取DBAdapter实例传入自定义函数
ZF3迁移:获取DbAdapter并传入自定义类的解决方案
嘿,我刚完成过ZF2到ZF3的迁移项目,这个问题我太有发言权了!ZF3彻底抛弃了ZF2里直接调用getServiceLocator()的方式,强制用**依赖注入(DI)**来管理服务,下面我给你分两种场景讲具体实现,保证能解决你的问题:
一、控制器里直接注入DbAdapter,实例化DBQuery
首先,你得把控制器改成通过构造函数接收DbAdapter,不能再像ZF2那样随手拿服务定位器了:
use Zend\Db\Adapter\AdapterInterface; use Zend\Mvc\Controller\AbstractActionController; class YourController extends AbstractActionController { private $dbAdapter; // 构造函数注入DbAdapter public function __construct(AdapterInterface $dbAdapter) { $this->dbAdapter = $dbAdapter; } public function yourAction() { // 现在直接用注入的适配器实例化你的DBQuery $dbQueryObj = new DBQuery($this->dbAdapter, 'tbl_user'); // 接下来该干嘛干嘛,和ZF2里的逻辑完全一致 } }
然后得给这个控制器写个工厂类,负责从服务容器里拿DbAdapter并传给控制器:
// 路径参考:module/YourModule/src/Factory/YourControllerFactory.php namespace YourModule\Factory; use Interop\Container\ContainerInterface; use Zend\ServiceManager\Factory\FactoryInterface; use YourModule\Controller\YourController; class YourControllerFactory implements FactoryInterface { public function __invoke(ContainerInterface $container, $requestedName, array $options = null) { // 这里的'db'就是你ZF2里配置的服务别名,ZF3里只要配置没改就能直接用 $dbAdapter = $container->get('db'); return new YourController($dbAdapter); } }
最后别忘了在模块的module.config.php里注册控制器和它的工厂:
return [ 'controllers' => [ 'factories' => [ YourModule\Controller\YourController::class => YourModule\Factory\YourControllerFactory::class, ], ], // ... 其他配置项 ];
二、更优雅的方案:给DBQuery做个工厂,直接注入实例
如果你的DBQuery会在多个控制器或服务里用到,我更推荐给它也整个工厂,直接把DbAdapter预注入,这样控制器里只需要拿DBQuery的实例就行,代码更清爽:
先改造你的DBQuery类,让它通过构造函数接收适配器和表名:
use Zend\Db\Adapter\AdapterInterface; class DBQuery { private $dbAdapter; private $tableName; public function __construct(AdapterInterface $dbAdapter, string $tableName) { $this->dbAdapter = $dbAdapter; $this->tableName = $tableName; } // ... 你原来的DBQuery方法都不用改 }
然后写DBQuery的工厂类:
namespace YourModule\Factory; use Interop\Container\ContainerInterface; use Zend\ServiceManager\Factory\FactoryInterface; use YourModule\DB\DBQuery; // 换成你实际的命名空间 class DBQueryFactory implements FactoryInterface { public function __invoke(ContainerInterface $container, $requestedName, array $options = null) { $dbAdapter = $container->get('db'); // 这里表名如果是固定的就直接写,要是需要动态传,后面可以用options参数调整 $tableName = 'tbl_user'; return new DBQuery($dbAdapter, $tableName); } }
接着在module.config.php里注册这个工厂到服务管理器:
return [ 'service_manager' => [ 'factories' => [ YourModule\DB\DBQuery::class => YourModule\Factory\DBQueryFactory::class, ], ], // ... 其他配置 ];
现在控制器里就可以直接注入DBQuery实例了:
use YourModule\DB\DBQuery; use Zend\Mvc\Controller\AbstractActionController; class YourController extends AbstractActionController { private $dbQuery; public function __construct(DBQuery $dbQuery) { $this->dbQuery = $dbQuery; } public function yourAction() { // 直接用$this->dbQuery就行,省得每次自己实例化 $result = $this->dbQuery->someMethod(); // ... } }
记得同步更新控制器的工厂,改成注入DBQuery:
class YourControllerFactory implements FactoryInterface { public function __invoke(ContainerInterface $container, $requestedName, array $options = null) { $dbQuery = $container->get(YourModule\DB\DBQuery::class); return new YourController($dbQuery); } }
最后检查下DbAdapter的配置
确保你ZF3里的Db服务配置和ZF2一致,别漏了别名,不然拿不到实例:
// module.config.php 或者 config/autoload/global.php 'db' => [ 'driver' => 'Pdo', 'dsn' => 'mysql:dbname=your_db;host=localhost', 'username' => 'your_user', 'password' => 'your_pass', 'driver_options' => [ PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\'' ], ], 'service_manager' => [ 'factories' => [ 'Zend\Db\Adapter\Adapter' => 'Zend\Db\Adapter\AdapterServiceFactory', ], 'aliases' => [ 'db' => 'Zend\Db\Adapter\Adapter', // 这个别名必须保留,不然$container->get('db')会报错 ], ],
这样操作下来,就能完美替代ZF2里的逻辑,完全符合ZF3的依赖注入规范,再也不用发愁拿不到DbAdapter啦!
内容的提问来源于stack exchange,提问作者Katty
相关产品推荐
相关产品推荐

