所以上课:
class ToBeUsed
{
private $a;
public function setSomething($a)
{
$this->a = $a;
}
public function getSomething()
{
return $this->a;
}
}
它的beign创建和更新:
$obj = new ToBeUsed();
$obj->setSomething('a');
并传递给另一个对象
class UseIt
{
/**
* @var ToBeUsed
*/
private $obj;
public function __construct(ToBeUsed $obj)
{
$this->obj = $obj;
}
public function work()
{
$this->obj->getSomething();
$this->obj->setSomething(); //// !!!!! THIS IS BAD!
}
}
现在是一个经典的DI
示例,除了传递的对象应该是" dulled" - 只允许使用某些方法。例如。允许使用getSomething()
,但setSomething()
不允许。什么模式/实践可以逃脱它?曾经有friend
个类是C,但它的Php ......
答案 0 :(得分:1)
我可能会对Interfaces做一些事情,但它并没有阻止使用方法表单。但是"他们" (无论他们是谁)将在接口之外使用$obj
。
像这样:
class ToBeUsed implements ToBeUsedInterface
{
private $a;
public function getSomething()
{
return $this->a;
}
public function setSomething($a)
{
$this->a = $a;
}
}
interface ToBeUsedInterface{
public function getSomething();
}
class UseIt
{
/**
* @var ToBeUsed
*/
private $obj;
public function __construct(ToBeUsedInterface $obj)
{
$this->obj = $obj;
}
public function work()
{
$this->obj->getSomething();
$this->obj->setSomething(); //This now exists outside of the interface for $obj
}
}
就IDE而言,这也会阻止方法自动完成。
我能想到的唯一另一件事(除了另一个答案)是将方法设置为protected
,然后使用ReflectionMethod
来改变生存能力,当你想要使用它时。
class ToBeUsed
{
private $a;
public function getSomething()
{
return $this->a;
}
protected function setSomething($a)
{
$this->a = $a;
}
}
$ToBeUsed = new ToBeUsed();
$ReflectionMethod = new ReflectionMethod($ToBeUsed, 'setSomething');
$ReflectionMethod->setAccessible(true);
$ReflectionMethod->invoke($ToBeUsed, 'foo');
echo $ToBeUsed->getSomething();
输出:
foo
你可以看到它live here
显然感觉它在正常情况下受到保护,它无法在UseIt
内使用。如果我打算将它用于任何数量的代码,我会扩展或包装Reflection类。只是为了使调用更简洁,像这样:
class MyReflector
{
public static function invoke($class, $method, ...$args)
{
$ReflectionMethod = new ReflectionMethod($class, $method);
$ReflectionMethod->setAccessible(true);
$ReflectionMethod->invokeArgs($class, $args);
}
}
$ToBeUsed = new ToBeUsed();
MyReflector::invoke($ToBeUsed,'setSomething', 'foo');
请注意我很喜欢变量...$arg
,它适用于PHP 5.6+它只是让你做
MyReflector::invoke($ToBeUsed,'setSomething', 'foo', 'bar');
$args
在第一个示例中为['foo','bar']
,它只是['foo']
,可以用于invokeArgs
第二个参数,它接受一个数组传递给实际方法的参数。
答案 1 :(得分:1)
class ToBeUsed
{
private $a;
public function setSomething($a)
{
$dbg = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS,2);
if(count($dbg) > 1){
return;
}
$this->a = $a;
}
public function getSomething()
{
return $this->a;
}
}
class UseIt
{
/**
* @var ToBeUsed
*/
private $obj;
public function __construct(ToBeUsed $obj)
{
$this->obj = $obj;
}
public function work()
{
echo $this->obj->getSomething().PHP_EOL; // a
$this->obj->setSomething('b'); // this does nothing
echo $this->obj->getSomething().PHP_EOL; // a
}
}
$obj = new ToBeUsed();
$obj->setSomething('a');
$obj2 = new UseIt($obj);
$obj2->work();
或者,您可以对debug_backtrace()
输出执行更复杂的检查。