class Node
{
protected function func1() { }
}
class NodeA extends Node
{
public function FUNC2() { }
}
class NodeB extends Node
{
// Функция инициализации
protected function onInit(ApiInit $api): void
{
// Добавить зависимость
$api->dependency(function (?NodeA $a) {
$a->FUNC2(); // Метод успешно вызывется так как он public
$a->func1(); // Метод также успешно вызывается хотя он и protected
});
}
abstract class Node
{
protected function onInit(): void
{
echo __METHOD__ . PHP_EOL;
}
}
spl_autoload_register(function ($classname) {
// Если $classname оканчивается на Dependency и является наследником Node,
// то сгенерировать динамический класс который в конструкторе принимает исходный объект
// и содержит только публичные методы этого объекта
// ..
});
class NodeA extends Node
{
public function FUNC2()
{
echo __METHOD__ . PHP_EOL;
}
protected function onInit(): void
{
parent::onInit();
echo __METHOD__ . PHP_EOL;
}
}
class NodeB extends Node
{
// Функция инициализации
protected function onInit(): void
{
parent::onInit();
echo __METHOD__ . PHP_EOL;
// Добавить зависимость
(function (NodeADependency $a) {
$a->FUNC2(); // Метод успешно вызывается так как он public
$a->onInit(); // Метод не получится вызвать так как его тут просто НЕТ!
})(new NodeA);
}
public function run()
{
$this->onInit();
}
}
(new NodeB)->run();
<?php
class Node
{
protected function func1() {
print "NODE PARENT; ";
}
}
class NodeA extends Node
{
public function FUNC2() {
print "NODE A; ";
}
// Используем метод родителя внутри этого класса
public function func1Overrided() {
print "From parent: " . parent::func1();
}
// Переопределяем метод так, чтобы его нельзя было использовать
protected function func1() {
throw new \Exception("Нельзя вызывать этот метод из NodeB");
}
}
class NodeB extends Node
{
// Функция инициализации
public function onInit(NodeA $a): void
{
// Сделал так, чтобы не мокать api )
(function (?NodeA $a) {
$a->FUNC2(); // Метод успешно вызывется так как он public
$a->func1(); // Метод теперь кидает исключение, использовать не получится
})($a);
}
}
$nodeA = new NodeA;
$nodeA->func1Overrided(); // Работает вызов метода funс1 из родителя
$nodeB = new NodeB;
$nodeB->onInit($nodeA); // Выдаёт ошибку, нельзя использовать метод func1 из класса NodeB
<?php
// Делаем общий трейт для всех классов
trait Func1 {
private function func1() {
print "FUNC1; ";
}
}
class Node
{
// Включаем трейт
use Func1;
}
class NodeA extends Node
{
// Включаем трейт
use Func1;
public function FUNC2() {
print "FUNC 2 NODEA; ";
}
}
class NodeB extends Node
{
// Включаем трейт
use Func1;
// Функция инициализации
public function onInit(NodeA $a): void
{
// Добавить зависимость
(function (?NodeA $a) {
$a->FUNC2(); // Метод успешно вызывется так как он public
$a->func1(); // Метод использовать не получится, т.к. он private
})($a);
}
}
$nodeA = new NodeA;
$nodeB = new NodeB;
$nodeB->onInit($nodeA); // Выдаёт ошибку, нельзя использовать метод func1 из класса NodeB
$api->dependency
class Node
{
protected function func1() {
}
}
class NodeA extends Node
{
public function FUNC2() {}
}
class NodeB extends Node
{
// Функция инициализации
public function __construct()
{
(new Api())->dependency(
function (?NodeA $a) {
$a->FUNC2(); // Метод успешно вызывется так как он public
$a->func1(); // Call to protected method Node::func1() from global scope
}
);
}
}
class Api {
function dependency(callable $dependency) {
if ($dependency instanceof Closure) {
$dependency = Closure::bind($dependency, null, null);
$dependency(new NodeA());
}
}
}
class Node
{
private array $whiteList = [
NodeA::class
];
protected function func1() {
$scope = debug_backtrace(2, limit: 2)[1]['class'];
if (!in_array($scope, $this->whiteList)) {
throw new Exception('Нельзя вызвать метод для данного класса '. $scope);
}
}
}
class NodeA extends Node
{
public function FUNC2() {}
}
class NodeB extends Node
{
// Функция инициализации
public function __construct()
{
(function (?NodeA $a) {
$a->FUNC2(); // Метод успешно вызывется так как он public
$a->func1(); // Нельзя вызвать метод для данного класса NodeB
})(new NodeA());
}
}