Как вариант можно сбрасывать скоп внутри метода
$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());
}
}