PHP的“friend”或“internal”相当于什么?

38

在 PHP 中是否有类似于“friend”或“internal”的等效功能?如果没有,是否有任何模式可以遵循以实现此行为?

编辑: 抱歉,但标准的 PHP 并不是我要找的。我正在寻找类似于 ringmaster 所做的东西。

我有一些类在后端执行 C 风格的系统调用,而且调用次数已经变得非常繁琐。在对象 A 中有一些函数,它们将对象 B 作为参数,并必须调用对象 B 中的一个方法并将自身作为参数传递。如果最终用户调用了 B 中的方法,则系统将崩溃。

5个回答

49

PHP不支持任何类似于“friend”的声明。使用PHP5的__get和__set方法并检查仅允许的友好类的回溯,可以模拟它,尽管实现代码有点笨拙。

PHP网站上关于这个主题有一些样例代码和讨论:sample code

class HasFriends
{
    private $__friends = array('MyFriend', 'OtherFriend');

    public function __get($key)
    {
        $trace = debug_backtrace();
        if(isset($trace[1]['class']) && in_array($trace[1]['class'], $this->__friends)) {
            return $this->$key;
        }

        // normal __get() code here

        trigger_error('Cannot access private property ' . __CLASS__ . '::$' . $key, E_USER_ERROR);
    }

    public function __set($key, $value)
    {
        $trace = debug_backtrace();
        if(isset($trace[1]['class']) && in_array($trace[1]['class'], $this->__friends)) {
            return $this->$key = $value;
        }

        // normal __set() code here

        trigger_error('Cannot access private property ' . __CLASS__ . '::$' . $key, E_USER_ERROR);
    }
}

(tsteiner 在 nerdclub dot net 上证明的代码,在 bugs.php.net 上)


20
这是一个可爱的妙招!我喜欢它,但又讨厌它。不过很聪明。+1 - Allain Lalonde
1
这个的性能如何?会有明显的影响吗?这实际上正是我要找的。 - smack0007
2
请记住,需要实现这样的代码很可能意味着您在代码/应用程序设计方面做出了错误的决策。 - halfpastfour.am
2
@halfpastfour.am,完全不行。假设我们有一个使用AbstractNode的AVLTree类。我们想要在节点本身中存储节点的高度,因此我们在节点中公开了一个名为“setHeight”的公共方法。尽管它是公共的,但在AVL树之外没有用处,因此AVL Tree类应该是AbstractNode的“Friend”。 - Nicolas
1
@Nicolas 我理解你的意思。但是,越少依赖于魔术方法和检查调用堆栈,就越好。 - halfpastfour.am
显示剩余4条评论

10

使用php >=5.3.3中的握手和闭包,也可以提升权限,即有选择地泄漏数据。

基本上,交互过程如下:类A具有一个公共方法,该方法接受一个类B对象,并调用B->grantAccess(或您接口定义的任何内容),传递一个闭包。 闭包use($that,$anythingelseyouneed)其中$that=$this,并且您需要确定哪些属性允许被访问。闭包只有一个参数-要返回的属性;如果它是在$that上的属性并且一切都很好,则闭包返回该属性。否则,它将返回'',或抛出异常,或者可能是默认值。

类B->grantAccess接受可调用对象并存储它,在其他方法中使用它来挑选闭包允许泄漏的私有属性。 将类B的默认构造函数设置为private。使用带有类A参数的静态工厂方法构建B,以确保握手发生。

要参考代码,请单击此处:https://gist.github.com/mcamiano/00592fb400e5043d8acd


0
也许是这样?仅仅是一个hack,不是C++中真正的友元关键字,在这种情况下只用于构造函数...
<?php

class FooWithFriend {

    private function guardOnlyFriend(): void 
    {
        if (( is_a($this, BarFriendOfFoo::class) ) === false ) {
         throw new Exception('Only class BarFriendOfFoo he can create me');
        }
    }

    protected function __construct() 
    {
        $this->guardOnlyFriend();
        echo 'Hello friend - ';
    }
}


final class BarFriendOfFoo extends FooWithFriend {
    public function __construct()
    {
        parent::__construct();
    }
}

final class Bar2FriendOfFoo extends FooWithFriend {
    public function __construct()
    {
        parent::__construct();
    }
}

$bar = new BarFriendOfFoo();
$bar = new Bar2FriendOfFoo();
$dummy = new FooWithFriend();

-1

现在的PHP有一个类友谊选项:

class Person
{
    friend HumanResourceReport;
 
    protected $id;
    protected $firstName;
    protected $lastName;
 
    public function __construct($id, $firstName, $lastName)
    {
        $this->id = $id;
        $this->firstName = $firstName;
        $this->lastName = $lastName;
    }
 
    public function makeReport()
    {
        return new HumanResourceReport($this);
    }
}

class HumanResourceReport
{
    private $person;
 
    public function __construct(Person $person)
    {
        $this->person = $person;
    }
 
    public function getFullName()
    {
        // HumanResourceReport would not have access to protected 
        // members of Person if not explicitly listed as a friend.
        return $this->person->firstName . ' ' . $this->person->lastName;
    }
 
    public function getReportIdentifier()
    {
        return "HR_REPORT_ID_{$this->person->id}";
    }
}

更多细节请查看这里:PHP RFC:类友谊


4
简而言之,未实现!我很感激您提供的信息,并喜欢阅读您的建议,但是如果您向下滚动到最后一个链接,您会发现PHP实现社区最终投票反对它。似乎您可以下载一个补丁来使其在您自己的PHP中工作,但没有计划将其纳入主要发布版本。 - Matmarbon
此功能被拒绝并不可用于PHP。 - Creech

-20
我相信你要找的是“protected”或“private”,这取决于你的用例。
如果你正在定义一个类中的函数,并且只想让它对自身可用,那么你应该这样定义:
private function foo($arg1, $arg2) { /*function stuff goes here */ }

如果您正在类中定义一个函数,希望该函数对继承自该类的其他类可用,但不希望公开可用,请按如下方式定义:
protected function foo($arg1, $arg2)

我相信在PHP5中,默认情况下函数是公共的,这意味着您不必使用以下语法,但这是可选的:

public function foo($arg1, $arg2) { /*function stuff goes here */ }

在使用公共函数之前,您仍需实例化对象。因此,我将非常详细地向您介绍,在不实例化对象的情况下使用类中的函数,请确保使用以下语法:

static function foo($arg1, $arg2) { /*function stuff goes here */ }

这将允许您仅通过引用类来使用函数,如下所示:

MyClass::foo($a1, $a2);

否则,您需要执行以下操作:
$myObject = new MyClass();
$myObject->foo($a1, $a2);

7
我认为OP想问的是如何在PHP中实现类似于C++中的“friend”关键字,即使某些私有/受保护的数据/方法可以被_某些未继承它的类所使用_。 - Lux

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接