在PHP中模拟朋友类

时间:2012-07-25 07:21:03

标签: php private friend private-members

我有一个类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应该叫什么?

或者我的方法完全错了?你如何解决这个问题呢?

2 个答案:

答案 0 :(得分:4)

如果您使用PHP&gt; = 5.4,traits似乎最能解决您的问题。

如果没有,我想到了以下解决方案:

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;

这段代码绝对不是最佳做法:)但是因为我可以把它放在这里。

答案 1 :(得分:2)

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 
{

}

编辑:嘿,所以没有告诉我已经有答案了。是的,也考虑过特质,但直到现在才使用它们所以不能真正评论它们