在PHP中模拟好友类

在PHP中模拟好友类,php,private,friend,private-members,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
,包含许多公共和私有方法。其中一个方法变得相当大,为此,我想把它分成一个单独的类。大概是这样的:

<?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 )
  {
    // ...
  }

  // ...
}
如果您使用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没有friend类的概念,从我所读到的内容来看,我不会说这是PHP设计师的一个错误决定

IMHO,没有总体战略,因为问题太广泛:需要考虑的因素太多:

  • run()
    中需要多少
    Foo
    的私有属性和方法
  • 从抽象的角度来看:
    run()
    Foo
    的关系有多密切?独立上课真的“值得”吗
  • 您是否会在
    Foo
    之外使用
    FooXDoer
解决方案的两个想法:

将所需数据从
foo
移交给
fooDoer
,可以是值对值,也可以通过在
foo
上实现一个返回数组或对象的
compileRunData()

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 
{

}

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

很不清楚(至少对我来说)你想在这里做什么。你能用现实生活中的例子吗?如果你想在不同的类之间分离功能,请确保这些类有它们的信息。如果函数X依赖于对象y的数据并对其进行操作,我建议您将该功能保留在对象y中。我会说,将其公开,但在注释中警告其他编码器。虽然您可能可以通过编程方式构建一些阻止其他类访问的内容,但这并不美妙。如果您想访问私有属性,可以将它们传递给FooXDoe()的构造函数。然而,对于私有方法,你不能这样做。这是一个正确的,但却是可怕的问题解决方案。你能简单描述一下traits是如何解决这个问题的吗?traits可以访问它们所使用的类的方法和属性。因此,您可以在trait中实现您的大型函数,并使用您的Foo类的所有属性。当然,这不是最佳实践,对生产性代码也没有任何要求,但不知何故,我喜欢这一点……非常有创意地使用语言功能,就像类属性的访问控制一样。这很疯狂,但我喜欢!我认为继承是解决这个问题的最好办法。