PHP 相当于朋友或内部

问题描述 投票:0回答:5

php 中是否有相当于“朋友”或“内部”的东西?如果没有,是否有任何模式可以遵循来实现这种行为?

编辑: 抱歉,但标准 Php 不是我想要的。我正在寻找与马戏团长所做的类似的东西。

我有一些类在后端进行 C 风格的系统调用,并且杂耍已经开始变得很麻烦。我在对象 A 中有函数,它接受对象 B 作为参数,并且必须调用对象 B 中的方法,将其自身作为参数传递。最终用户可以调用 B 中的方法,系统就会崩溃。

php oop friend
5个回答
49
投票

PHP 不支持任何类似友元的声明。可以使用 PHP5 __get 和 __set 方法来模拟这一点,并仅检查允许的友元类的回溯,尽管执行此操作的代码有点笨拙。

PHP 网站上有一些 示例代码 和有关该主题的讨论:

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 上证明


10
投票

还可以在 php >=5.3.3 中使用握手和闭包来提升权限,也称为选择性泄漏数据。

基本上,交互是这样的:类 A 有一个公共方法,它接受类 B 对象,并调用 B->grantAccess (或您的接口定义的任何内容),向其传递一个闭包。闭包

use($that,$anythingelseyouneed)
其中 $that=$this,以及确定允许访问哪些属性所需的任何其他内容。闭包有一个参数 - 要返回的属性;如果它是 $that 上的一个属性并且一切都很酷,则闭包将返回该属性。否则,它返回 '',或者抛出异常,或者可能是默认值。

B 类->grantAccess 接受一个可调用对象并存储它,在其他方法中使用它来提取闭包允许泄漏的私有属性。将 B 类的默认构造函数设为私有。使用采用 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();

0
投票

该语言不支持。有多种不同的方法可以近似它,具体取决于您的目标是什么。如果您只是想弄清楚预期调用的内容(例如,避免在 IDE 中自动完成用户不应该使用的方法),您可以使用更窄的接口或父类来键入对象:

abstract class Entity {
    protected $value = null;
    public function getValue() { return $this->value; }
}
class MutableEntity extends Entity {
    public function setValue( $value ) { $this->value = $value; }
}
function getEntity(): Entity {
    // returns a MutableEntity but says it's an Entity so
    // the IDE will not offer setValue()
    return new MutableEntity();
 }

如果您确实想强制执行访问限制,您可能必须使用闭包。但是,恶意用户可以使用反射轻松解决任何访问限制,因此没有太多尝试强制执行它。


-20
投票

我很确定您正在寻找的是“受保护”或“私有”,具体取决于您的用例。

如果您在类中定义函数,并且只希望它可供自身使用,则可以这样定义它:

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);
© www.soinside.com 2019 - 2024. All rights reserved.