【发布时间】:2021-11-02 11:16:02
【问题描述】:
我正在使用 Laravel 作为框架来构建一个应用程序框架,该框架可以被其他开发人员用来构建他们自己的应用程序。 现在我在开发的作曲家包中遇到了一点 PSR-4 命名空间问题。
我的应用程序框架的设计示例
- 应用程序
- 我的应用程序名称
- 映射器
-
BaseMapper.php(命名空间:App\MyApplicationName\Mapper)
-
- 映射器
- 我的应用程序名称
- 引导
- 配置
- ...
- 供应商
- 我的供应商名称
- 我的应用程序名称
- 源
- 控制器
BaseController.php
- 映射器
-
BaseMapper.php(命名空间:MyVendorName\MyApplicationName\Controller)
-
- 控制器
- 源
- 我的应用程序名称
- 我的供应商名称
这可以正常工作。我可以使app 文件夹中的BaseMapper.php 扩展vendor 中的BaseMapper.php,这样我可以向BaseMapper.php 添加额外的方法和属性,同时保留(或覆盖)基本映射器文件中的那些.
app中BaseMapper.php的内容:
namespace App\MyApplicationName\Mapper;
use MyVendorName\MyApplicationName\Mapper as FrameworkMapper;
class BaseMapper extends FrameworkMapper;
{
public function executeFunction(): string
{
return "bar";
}
}
BaseMapper.php 在vendor 中的内容:
namespace MyVendorName\MyApplicationName\Mapper;
class BaseMapper
{
public function executeFunction(): string
{
return "foo";
}
}
当我从 Laravel 项目中调用映射器时,例如:
$baseMapper = new \App\MyApplicationName\BaseMapper();
$result = $baseMapper->executeFunction(); // bar
结果我得到了bar,我很高兴。
但这是我的问题:
在vendor 中的BaseController.php 中,我调用了BaseMapper.php 的方法,例如:
$mapper = new \MyVendorName\MyApplicationName\Mapper\BaseMapper();
$result = $mapper->executeFunction(); // foo
现在$result 是foo 而我希望得到bar。
我可以通过添加来解决它:
$mapper = new \MyVendorName\MyApplicationName\Mapper\BaseMapper();
if (class_exists(\App\MyApplicationName\Mapper\BaseMapper::class)) {
$mapper = new \App\MyApplicationName\Mapper\BaseMapper();
}
$result = $mapper->executeFunction();
但我认为添加这样的检查很难看,而且当你实例化一个新类时很容易忘记添加这样的检查。
所以我想添加一些自定义自动加载逻辑(在我的包中),以便能够首先搜索 App 命名空间并将 MyVendorName\MyApplicationName 命名空间用作后备。
我已经在composer.json 中尝试过这样做:
"autoload": {
"psr-4": {
"MyVendorName\MyApplicationName": ["../../app/MyApplicationName/","src/"]
}
}
但这使得无法从 app 文件夹中覆盖类,因为我使用的是相同的命名空间。
所以我实现这一点的唯一想法是当有一种方法可以连接到 composer 的自动加载器以添加如下逻辑:
if (str_contains($className, "\\MyVendorName\\MyApplicationName\\")) {
$appClassName = str_replace("\\MyVendorName\\MyApplicationName\\", "\\App", $className);
if (class_exists($appClassName)) {
include_once $appClassName;
} else {
include_once $className;
}
}
您能否帮我解决如何实现这一点,为我的问题提供另一个(更好的)解决方案?
【问题讨论】:
标签: php laravel package autoload psr-4