我可以/如何在PHP中调用类外的受保护函数

26

我有一个在某个类中定义的受保护函数。我想能够在该类外的另一个函数中调用此受保护函数。是否可能实现这一点,如果可以,如何实现?

class cExample{

   protected function funExample(){
   //functional code goes here

   return $someVar
   }//end of function

}//end of class


function outsideFunction(){

//Calls funExample();

}

2
你不能这样做。这会背离一开始设定受保护函数的目的。你可以创建一个公共方法来代表你调用受保护的方法,但是这样一来,为什么还要有受保护方法呢? - Marc B
一个重复的问题,链接为http://stackoverflow.com/q/12255740/2088851 - Voitcus
8个回答

69

在技术上,使用反射API可以调用私有和受保护的方法。但99%的情况下,这么做都是一个很糟糕的主意。如果你可以修改类,那么正确的解决方案可能就是将方法声明为公共的。毕竟,如果你需要在类外部访问它,那么标记为受保护的意义就不存在了。

以下是一个快速的反射示例,以防这是极少数真正必要的情况之一:

<?php
class foo { 
    protected function bar($param){
        echo $param;
    }
}

$r = new ReflectionMethod('foo', 'bar');
$r->setAccessible(true);
$r->invoke(new foo(), "Hello World");

18
对于知道他们在做什么的人来说,这是正确的答案。 - Andras Gyomrey
附注:此功能在PHP 5.4+中可用(耶!) - Lucas Bustamante
2018年有哪些变化/新可能性? - beppe9000
1
这是纯金(也是问题的实际答案) - CptAJ

22
这就是面向对象编程的要点 - 封装: 私有
Only can be used inside the class. Not inherited by child classes.

受保护的

Only can be used inside the class and child classes. Inherited by child classes.

公共的

Can be used anywhere. Inherited by child classes.

如果您仍然想在外部触发该函数,您可以声明一个公共方法来触发您的受保护方法:

protected function b(){

}

public function a(){
  $this->b() ;
  //etc
}

3
如果两个实例都继承同一个抽象类,那么您可以访问另一个实例的受保护成员。我不相信直到我看到它发生。 - Daniel W.

9
如果父类的方法是受保护的,您可以使用匿名类:
class Foo {
    protected function do_foo() {
        return 'Foo!';
    }
}

$bar = new class extends Foo {
    public function do_foo() {
      return parent::do_foo();
    }
}

$bar->do_foo(); // "Foo!"

https://www.php.net/manual/en/language.oop5.anonymous.php


我喜欢这种方法,因为它保持了面向对象编程的语义。 - KalenGi

5

另一个选择(PHP 7.4)

<?php
class cExample {
   protected function funExample(){
       return 'it works!';
   }
}

$example = new cExample();

$result = Closure::bind(
    fn ($class) => $class->funExample(), null, get_class($example)
)($example);

echo $result; // it works!

在 PHP 7.3 上,我遇到了以下错误:syntax error, unexpected '=>' (T_DOUBLE_ARROW), expecting ')'。我不得不使用这个语法:$result = Closure::bind(function ($class) { return $class->funExample(); }, null, get_class($example))($example); - GuyPaddock

4
您可以通过另一个类重写此类,并将其设置为公共访问。
class cExample2 extends cExample {
  public function funExample(){
    return parent::funExample()
  }
}

注意,这将不适用于私有成员。
但是,私有和受保护的成员的思想是不应该从外部调用。

2
如果您想在类之间共享代码,可以使用traits,但这取决于您如何使用函数/方法。
无论如何,
trait cTrait{
   public function myFunction() {
      $this->funExample();
   }
}

class cExample{
   use cTrait;

   protected function funExample() {
   //functional code goes here

   return $someVar
   }//end of function

}//end of class

$object = new cExample();
$object->myFunction();

这个方法可以实现,但要记住,这样你并不知道你的类由什么组成。如果更改特性,则使用它的所有类也会被改变。编写每个使用的特性的接口也是一个好习惯。

2

我可以给你举一个例子,如下所示:

<?php
    class dog {
        public $Name;
        private function getName() {
            return $this->Name;
        }
    }

    class poodle extends dog {
        public function bark() {
            print "'Woof', says " . $this->getName();
        }
    }

    $poppy = new poodle;
    $poppy->Name = "Poppy";
    $poppy->bark();
?>

另一种使用最新PHP的方法是使用Reflection。要调用受保护或私有方法,请使用setAccessible()方法http://php.net/reflectionmethod.setaccessible (将其设置为TRUE即可)。


0

我正在使用Laravel。在访问外部的受保护方法时,我遇到了问题。

   $bookingPriceDetails = new class extends BookingController {
        public function quotesPrice( $req , $selectedFranchise) {
           return parent::quotesPrice($req , $selectedFranchise);
        }
    };

     return $bookingPriceDetails->quotesPrice($request , selectedFranchisees());

这里的 BookingController 是一个名,我想要从中获取protected方法。quotesPrice($req, $selectedFranchise)是我想在不同的类中访问的方法。


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