PHP эквивалент друга или внутреннего - PullRequest
31 голосов
/ 25 ноября 2008

Есть ли какой-нибудь эквивалент "друга" или "внутреннего" в php? Если нет, есть ли какой-то шаблон, которому нужно следовать для достижения такого поведения?

Edit: Извините, но стандартный Php не то, что я ищу. Я ищу что-то похожее на то, что сделал Ringmaster.

У меня есть классы, которые выполняют системные вызовы в стиле C, и жонглирование стало громоздким. У меня есть функции в объекте A, которые принимают объект B в качестве параметра и должны вызывать метод в объекте B, передавая его в качестве аргумента. Конечный пользователь может вызвать метод в B, и система развалится.

Ответы [ 3 ]

44 голосов
/ 25 ноября 2008

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);
    }
}

(Код, подтвержденный Цтайнером в точечной сети nerdclub на bugs.php.net )

8 голосов
/ 08 августа 2014

Также возможно повысить привилегии, то есть выборочную утечку данных, используя рукопожатие и замыкания в php> = 5.3.3.

По сути, взаимодействие происходит: у класса A есть открытый метод, который принимает объект класса B и вызывает B-> grantAccess (или любой другой, определяемый вашим интерфейсом), передавая ему закрытие. Закрытие use($that,$anythingelseyouneed), где $ that = $ this, и все остальное, что вам нужно, чтобы определить, к каким свойствам разрешен доступ. Закрытие имеет один аргумент - свойство возвращать; если это свойство на $ that и все круто, замыкание возвращает свойство. В противном случае он возвращает '', либо выдает исключение, либо может быть значением по умолчанию.

Класс B-> grantAccess принимает вызываемый объект и сохраняет его, используя его в других методах для извлечения приватных свойств, которые закрытие позволяет пропускать. Сделайте конструктор класса B по умолчанию закрытым. Создайте B, используя статический фабричный метод, который принимает аргумент класса A, чтобы обеспечить рукопожатие.

Суть здесь: https://gist.github.com/mcamiano/00592fb400e5043d8acd

0 голосов
/ 25 ноября 2008

Я почти уверен, что вы ищете "защищенный" или "частный", в зависимости от вашего варианта использования.

Если вы определяете функцию в классе и хотите, чтобы она была доступна только для себя, вы определите ее следующим образом:

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);
...