我试图找到一种方法,仅当该接口可用时才实现该接口。
有问题的接口是
PrestaShop\PrestaShop\Core\Module\WidgetInterface
来自 Prestashop。它在模块中使用。
问题是,为了兼容多个版本的 Prestashop,代码必须处理
WidgetInterface
不存在的情况。
我想测试一下接口是否存在,然后导入它,就像这样:
if (interface_exists('PrestaShop\PrestaShop\Core\Module\WidgetInterface')) {
use PrestaShop\PrestaShop\Core\Module\WidgetInterface
} else {
interface WidgetInterface {}
}
但是,当然,不可能在 if 语句中使用
use
。
然后我尝试做一些 try/catch,但这是同样的问题(可惜它不是 Python)。
只有在可用时我才能做
implements WidgetInterface
?
您无法像您所说的那样动态实现接口,但您可以编写自己的接口,并且仅在另一个接口不存在时才
require
。
即:您的界面将类似于
widget_interface.php
,或者您想称呼它的任何名称,只要它不符合 PSR-0/4,或者以您通常采用的任何方式自动加载即可。
<?php
namespace PrestaShop\PrestaShop\Core\Module;
/**
* This is the replacement interface, using the same namespace as the Prestashop one
*/
interface WidgetInterface
{
}
然后,在课堂上,您可以执行以下操作:
<?php
namespace App;
if (!interface_exists('\PrestaShop\PrestaShop\Core\Module\WidgetInterface')) {
require __DIR__ . '/path/to/widget_interface.php';
}
class WhateverClass implements \PrestaShop\PrestaShop\Core\Module\WidgetInterface
{
}
仅当 Prestashop 界面不存在时才会加载您的替换界面。
确实,您不能将
use
放入 if
块中,但 use
只是为类设置一个别名。它不会尝试加载该类。所以它可以安全地位于 if
区块之外。
并且您可以在
if
内定义类或接口本身。
这就是 Symfony 处理这个问题的方式,继承自一个可能不存在的接口:
namespace Symfony\Contracts\EventDispatcher;
use Psr\EventDispatcher\EventDispatcherInterface as PsrEventDispatcherInterface;
if (interface_exists(PsrEventDispatcherInterface::class)) {
interface EventDispatcherInterface extends PsrEventDispatcherInterface
{
public function dispatch($event);
}
} else {
interface EventDispatcherInterface
{
public function dispatch($event);
}
}
就我个人而言,为了保持事物干净并包含在一个地方,我会像这样定义您自己的接口,该接口继承自
PrestaShop
接口(如果可用)或提供自己的实现,然后让您的类继承该接口。
我必须为 Laravel 应用程序执行此操作才能支持版本 9 和 10。这并不完全相同,因为两个版本中都存在接口。但是,我没有创建垫片接口或处理加载文件,而是这样做了:
<?php
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule; // 9.0 interface
use Illuminate\Contracts\Validation\ValidationRule; // 10.0 interface
if (!interface_exists(ValidationRule::class)) {
class_alias(Rule::class, ValidationRule::class);
}
class MyRule implements ValidationRule {
// ...
}
现在当我提到
ValidationRule
时,它要么是10.0中的实际接口,要么是9.0中的别名。
我认为文件中包含非类代码违反了 PSR-2 或 12,但当规则妨碍时我并不坚持这些规则。