在随 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
。
我正在使用 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
。