我可以将接口绑定到我的服务并静态调用方法吗



已经有一个接口,我不想更改或编辑它。

<?php
namespace AppContracts;
interface MyInterface
{
public function set(array $data): bool;
}

我创建了一个服务。

<?php
namespace AppServices;
use AppContractsMyInterface;
class MyService implements MyInterface
{
protected $data;
public function set(array $data): bool
{
try {
$this->data = $data;
return true;
} catch (Throwable $th) {
return false;
}
}
}

问题是,有没有什么方法可以在不编辑MyInterface的情况下静态调用set方法?(例如在绑定中(

$service = app(MyInterface::class);
$service::set(["some-key"=> "some-value"]);

您最好使用两种不同的设计模式,单例和静态代理

首先,我们将设置现有的接口和服务(我添加了一个__toString用于演示目的(

interface MyInterface
{
public function set(array $data): bool;
}
class MyService implements MyInterface
{
protected $data;

public function set(array $data): bool
{
try
{
$this->data = $data;
return true;

}
catch (Throwable $th)
{
return false;
}
}

public function __toString()
{
return json_encode($this->data, JSON_PRETTY_PRINT);
}
}

第一块拼图,一个静态的单例工厂。所有这些实际上只是保存我们服务类的一个实例。当您调用getInstance时,会返回实例。我们在第一次调用该方法时创建实例。

/**
* Manage a singleton instance of MyService
*/
class MyServiceSingletonFactory
{
/**
* @var MyService|null Singleton instance
*/
private static ?MyService $instance;

/**
* @var bool initialization status
*/
private static bool $initialized = false;

/**
* Return the singleton instance, create if it has not been initialized
* @return MyService
*/
public static function getInstance(): MyService
{
/*
* We can't access a typed static property before it's initialized,
* so we need to track init with a boolean instead of relying on instanceof
*/
if (!self::$initialized)
{
self::$instance    = new MyService();
self::$initialized = true;
}

return self::$instance;
}
}

为了获得对服务实例的静态访问,这就是我们真正需要的,但为了最大限度地方便,我们可以添加一个静态代理层。

这种模式被称为facade,因为Laravel将本质上是静态代理的东西称为facades,但传统上facade模式被用来为一组复杂的类提供简化的接口,但事实并非如此。

我们将实现一个接口来强制执行与MyInterface的奇偶校验,尽管这不是绝对必要的。

/**
* This isn't really necessary because we don't pass instances of these,
* but it does enforce the implementation of a uniform interface
*/
interface MyServiceProxyInterface
{
public static function set(array $data): bool;

public static function print(): string;
}
/**
* Provides a static interface to MyService
*/
class MyServiceProxy implements MyServiceProxyInterface
{
/**
* Pass through to the set method on the singleton instance of MyService
* @param array $data
* @return bool
*/
public static function set(array $data): bool
{
return MyServiceSingletonFactory::getInstance()->set($data);
}

public static function print(): string
{
return MyServiceSingletonFactory::getInstance()->__toString();
}
}

现在,我们已经拥有了所需的一切,让我们通过它的步伐来运行这段代码。

$data = [
'foo'     => 'bar',
'wombats' => true
];
MyServiceSingletonFactory::getInstance()->set($data);
// Verify that our data is set
echo MyServiceSingletonFactory::getInstance() . PHP_EOL;
// Uses the same instance, will print the data we set previously
echo MyServiceProxy::print() . PHP_EOL;
$data2 = [
'foo'     => 'baz',
'wombats' => false
];
// Update via the static proxy
MyServiceProxy::set($data2);
// Inspect updated data
echo MyServiceProxy::print() . PHP_EOL;
/**
* Requires an instance of MyService
* @param MyService $myService
* @return void
*/
function useMyService(MyService $myService): void
{
$myService->set([
'foo'     => 'tree',
'wombats' => null
]);
}
// We can send the instance to something that requires a MyService instance...
useMyService(MyServiceSingletonFactory::getInstance());
// ...and our static singleton instance will reflect any changes made
echo MyServiceProxy::print() . PHP_EOL;

最新更新