gpt4 book ai didi

php - 如何使供应商包类可通过 PSR-4 自动加载进行扩展?

转载 作者:行者123 更新时间:2023-12-04 14:51:14 25 4
gpt4 key购买 nike

我正在使用 Laravel 作为框架来构建一个应用程序框架,该框架可用于由其他开发人员构建自己的应用程序。
现在我在我正在开发的 Composer 包中遇到了一个小的 PSR-4 命名空间问题。
我的应用程序框架的设计示例

  • 应用程序
  • 我的应用程序名称
  • 映射器
  • BaseMapper.php (命名空间:App\MyApplicationName\Mapper)



  • bootstrap
  • 配置
  • ...
  • 小贩
  • 我的供应商名称
  • 我的应用程序名称
  • 源文件
  • Controller
  • BaseController.php

  • 映射器
  • BaseMapper.php (命名空间:MyVendorName\MyApplicationName\Controller)






  • 这工作正常。我可以制作 BaseMapper.phpapp文件夹扩展 BaseMapper.phpvendor这样我就可以向 BaseMapper.php 添加额外的方法和属性同时保留(或覆盖)基本映射器文件中的那些。 BaseMapper.php的内容在 app :
    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结果,我很高兴。
    但这是我的问题:
    BaseController.phpvendor我调用 BaseMapper.php的方法如:
    $mapper = new \MyVendorName\MyApplicationName\Mapper\BaseMapper();
    $result = $mapper->executeFunction(); // foo
    现在 $resultfoo而我希望得到 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;
    }
    }
    你能帮我解决这个问题吗?为我的问题提供另一个(更好的)解决方案吗?

    最佳答案

    这不应通过自定义自动加载器或在运行时换出类来解决。理想情况下,vendor/MyVendorName/MyApplicationName/Controller/BaseController将被写成它可以有 BaseMapper classed 在实例化时注入(inject),因此您只需将其传递给所需的类即可轻松更改其行为。

    namespace MyVendorName\MyApplicationName\Controller;

    class BaseController
    {
    protected $mapper;
    public function __construct($mapper)
    {
    $this->mapper = $mapper;
    }
    public function whateverThisMethodIsNamed()
    {
    $result = $this->mapper->executeFunction();
    }
    }
    然后,当您创建 Controller 类时,您会将您希望它使用的映射器传递给它:
    $mapper = new \MyApplicationName\Mapper();
    $controller = new \MyVendorName\MyApplicationName\BaseController($mapper);
    但是,如果您没有能力或希望单独更改该供应商存储库,那么最简单的解决方案可能是创建一个扩展 BaseController。在您的应用程序命名空间中,以便它扩展供应商 BaseController .然后提供一个具有更新逻辑的覆盖方法:
    创建 app/MyApplicationName/Controller/BaseController.php :
    namespace MyApplicationName\Controller;

    class BaseController extends \MyVendorName\MyApplicationName\Controller\BaseController
    {
    public function whateverThisMethodIsNamed()
    {
    $Mapper = new \MyApplicationName\Mapper\BaseMapper();
    $result = $Mapper->executeFunction();
    }
    }
    然后在您的应用程序中,使用新 Controller :
    //$controller = new \MyVendorName\MyApplicationName\Controller\BaseController();
    $controller = new \MyApplicationName\Controller\BaseController();

    关于php - 如何使供应商包类可通过 PSR-4 自动加载进行扩展?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69056344/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com