我正在使用Codeigniter和Composer。其中一个要求是PHPExcel。现在我需要更改其中一个类中的函数。最好的策略应该是什么?我应该更改供应商文件夹中的代码吗?如果是这样,如何在所有实例中维护更改?如果不是,我该如何覆盖该特定类。虽然我提到PHPExcel,但我想要一个通用的解决方案。
我不确定这是否是这个问题的正确论坛。如果没有,我将删除它。如果需要更多详细信息,请告诉我。
谢谢。
在 composer.json 中,在 ["autoload"]["psr-4"] 下,添加一个条目,其中命名空间作为键,路径作为值:
{
"autoload": {
"psr-4": {
"BuggyVendor\Namespace\": "myfixes/BuggyVendor/Namespace"
}
}
}
在该路径下复制要覆盖的文件(保留子命名空间目录结构)并在那里编辑它们。将优先选择它们,而不是库包的原始"类路径"。似乎以这种方式添加到 composer.json 的命名空间>路径映射在所需包添加的映射之前被考虑。注意:我刚刚尝试过并且它起作用了,尽管我不知道它是否是预期的功能或可能的陷阱是什么。
编辑:发现了一个陷阱。有时,当您随后需要另一个带有composer require vendor/package
的软件包时,您将"丢失"覆盖。如果发生这种情况,您必须手动发出composer dump-autoload
。这将恢复正确的自动加载顺序,以遵循您的覆盖。
将最后 2 行添加到我composer.json
的 autoload
部分是我想只覆盖 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
选择。如果您需要重写唯一的类,则可以像这样在composer.json中使用文件
"autoload": {
"files": ["path/to/rewritten/Class.php"]
}
所以如果你想重写类SomeNamespaceMyClass
这样说
#path/to/rewritten/Class.php
namespace SomeNamespace;
class MyClass {
#do whatever you want here
}
根据每个请求,作曲家会将该文件加载到内存中,因此在使用SomeNamespaceMyClass
时 - 将使用path/to/rewritten/Class.php
的实现。
您也可以简单地复制文件并用自己的文件覆盖原始文件。假设创建一个目录,例如"供应商覆盖",你在其中放置你的固定文件,只需将其添加到你的作曲家:
"scripts": {
"post-install-cmd": [
"@php -r "copy('vendor-overrides/path/to/your/fixed/file.php', 'vendor/path/to/your/broken/file.php');""
],
"post-update-cmd": [
"@php -r "copy('vendor-overrides/path/to/your/fixed/file.php', 'vendor/path/to/your/broken/file.php');""
]
}
更改现有类违反了 OOP 和 SOLID 原则(对扩展开放/对修改原则关闭)。所以这里的解决方案不是直接更改代码,而是扩展代码以添加您的功能。
在理想的世界中,你永远不应该更改一段你不拥有的代码。事实上,使用 composer 您不能,因为在更新依赖项时您的更改将被覆盖。
在您的情况下,解决方案是在应用程序级别创建一个类,并扩展要更改的类(在库级别)以覆盖您的代码。如果您不知道如何扩展 PHP 中的类,请查看
。然后,通常,您加载您的类而不是它们的类,这样,您将功能添加到其功能之上,并且在更新的情况下,不会中断任何内容(在非中断性更新的情况下)。