在随 Composer 安装的库中覆盖 class 的策略

Strategy to override a class in a library installed with Composer

我正在使用 Codeigniter 和 Composer。其中一项要求是 PHPExcel。现在我需要更改 classes 之一中的函数。最好的策略应该是什么?我应该更改供应商文件夹中的代码吗?如果是这样,如何在所有实例中维护更改?如果不是,我该如何覆盖那个特定的 class。虽然我提到了 PHPExcel,但我想要一个通用的解决方案。

我不确定这个论坛是否适合解决这个问题。如果没有,我会删除它。如果需要更多详细信息,请告诉我。

谢谢。

更改现有的 class 违反了 OOP 和 SOLID 原则(特别是对 extension/Closed 修改原则开放)。所以这里的解决方案不是直接更改代码,而是扩展代码以添加您的功能。

在理想情况下,您永远不应该更改不属于您的一段代码。 事实上,使用 composer 你不能,因为你的更改将在更新依赖项时被覆盖。

您的解决方案是在应用程序级别创建一个 class,然后扩展您要更改的 class(在库级别)以用您的代码覆盖。如果您不知道如何扩展,请查看 PHP 中的 class。

然后通常,你加载你的 class 而不是他们的 class,这样,你在他们的功能之上添加你的功能,并且在更新的情况下,没有任何中断(以防万一非中断更新)。

在composer.json中,在["autoload"]["psr-4"]下,添加一个以命名空间为键,路径为值的条目:

{
     "autoload": {

         "psr-4": {

             "BuggyVendor\Namespace\": "myfixes/BuggyVendor/Namespace"
         }
     }
}

在该路径下复制您想要覆盖的文件(保持 sub-namespace 目录结构)并在那里编辑它们。将优先选择它们而不是库包的原始 "classpath"。似乎以这种方式添加到 composer.json 的名称空间-> 路径映射被认为先于所需包添加的映射。注意:我只是尝试了它并且它起作用了,虽然我不知道它是否是一个预期的功能或者可能的陷阱是什么。

编辑:发现问题。有时当您随后需要另一个带有 composer require vendor/package 的包时,您将 "lose" 覆盖。如果发生这种情况,您必须手动发出 composer dump-autoload。这将根据您的覆盖恢复正确的自动加载顺序。

还有一个选项。 如果您需要重写唯一的 class,您可以像这样

在 composer.json 中使用 files
 "autoload": {
     "files": ["path/to/rewritten/Class.php"]
  }

所以如果你想重写 class Some\Namespace\MyClass 这样写

#path/to/rewritten/Class.php

namespace Some\Namespace;

class MyClass {
  #do whatever you want here
}

根据每个请求,作曲家都会将该文件加载到内存中,因此在使用 Some\Namespace\MyClass 时 - 将使用 path/to/rewritten/Class.php 的实现。

当我想只覆盖vendors目录:

"autoload": {        
    "classmap": [
        "database"
    ],
    "psr-4": {
        "App\": "app/"
    },
    "exclude-from-classmap": ["vendor/somepackagehere/blah/Something.php"],
    "files": ["app/Overrides/Something.php"]
},

请记住,app/Overrides/Something.php 中的命名空间需要与 vendor/somepackagehere/blah/Something.php 中的原始命名空间相匹配。

编辑composer.json后记得运行composer dump-autoload

文档:https://getcomposer.org/doc/04-schema.md#files