我有一个班级
Foo
,其中包含许多公共和私人方法。其中一个方法变得相当大,我想将它分叉到一个专门用于该目的的单独类中。像这样的东西:
<?php
class Foo
{
// ...
public function doX( $a, $b )
{
$x = new FooXDoer;
$x->foo = $this;
return $x->run( $a, $b );
}
// ...
}
class FooXDoer
{
public $foo;
public function run( $a, $b )
{
// ...
}
// ...
}
FooXDoer
可以通过Foo
访问$this->foo
的公共方法和属性。
如何让
FooXDoer
访问Foo
的私有方法和属性,而不将它们公开给已经使用Foo
的其余代码?
我应该创建一个单独的类
FooPrivate
,它具有公共的私有方法,并且Foo
包装,然后让FooXDoer
引用它吗? FooPrivate
应该叫什么?
或者我的做法完全错误?你一般如何解决这个问题?
看起来 traits 在您使用 PHP >= 5.4 的情况下最好地解决您的问题。
如果不行,我想到了以下解决方案:
class A {
private static $allowedClasses = array('B');
private $a = 1;
public function __get($property) {
$caller = debug_backtrace(false);
if(!isset($caller[1]))
throw new Exception('Bla bla');
if(!in_array($caller[1]['class'], self::$allowedClasses))
throw new Exception('Bla bla');
return $this->$property;
}
public function testB() {
$b = new B();
$b->instA = $this;
echo $b->getA();
}
}
class B {
public $instA;
public function getA() {
return $this->instA->a;
}
}
class C {
public function getA() {
$instA = new A();
return $instA->a;
}
}
$a = new A();
$a->testB(); // Works ok;
$c = new C();
$c->getA(); // Throws exception here;
这段代码绝对不是最佳实践 :) 但既然有可能,我就把它放在这里。
PHP 没有友元类的概念,从我读过的内容来看,我不会说这是 php 设计者的错误决定...
恕我直言,没有通用策略,因为问题或问题太宽泛:需要考虑的因素太多:
Foo
需要多少个run()
的私有属性和方法?run()
与Foo
的纠缠有多紧密?独立班真的“值得”吗? FooXDoer
之外使用Foo
吗?两个解决思路:
将所需的数据从
foo
移交到 fooDoer
,无论是值对值还是通过在 compileRunData()
上实现 Foo
返回数组或对象
public function doX( $a, $b )
{
$x = new FooXDoer;
$workEnvironment = $this->compileRunData();
$x->setEnvironment( $workEnvironment );
$x->foo = $this;
return $x->run( $a, $b );
}
或者使用继承,尤其是受保护属性的概念:
abstract class FooAbstract
{
protected $_basicVar1;
protected function basicMethod1(/*...*/) {
//...
}
// ...
}
abstract class FooRunner extends FooAbstract
{
protected $_runVar1;
protected function runMethod1(/*...*/) {
//...
}
public function run($a, $b) {
// ...
}
}
public class Domain_Model_Foo extends FooRunner
{
}
edit:嘿,所以没有告诉我已经有答案了。是的,也考虑过 traits,但直到现在还没有使用过,所以不能真正评论它们
下面有一个易于使用的函数,可以防止函数被未在“friendClass()”中列出的类使用。在示例中,“Item”对象可能仅由“Foo”类构造。否则,将抛出异常。
函数 friendClass($classNames){ 如果(!is_array($classNames)) $classNames = [$classNames]; $trace = debug_backtrace(); $called = $trace[1]; $caller = $trace[2]; $calledFunction = $called['class']."::".$called['function']; $callerFunction = $caller['class']."::".$caller['function']; 如果(!in_array($caller['class'], $classNames)) 抛出新的异常( “$callerFunction() 未经授权使用 $calledFunction()” ); } 类项目{ 函数 __construct(){ friendClass('富'); // “好友类”声明 echo "Item 对象已创建 "; } }; 类 Foo{ 函数调用者(){ $项目=新项目(); } }; 酒吧类{ 函数调用者(){ $项目=新项目(); } }; $foo = new Foo(); $酒吧=新酒吧(); $foo->调用者(); //允许 $项目=新项目(); // 例外 $bar->caller(); //例外