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

Posted

技术标签:

【中文标题】我可以/如何...在 PHP 中的类之外调用受保护的函数【英文标题】:Can I/How to... call a protected function outside of a class in PHP 【发布时间】:2013-06-14 23:28:37 【问题描述】:

我有一个在某个类中定义的受保护函数。我希望能够在另一个函数中的类之外调用这个受保护的函数。这可能吗?如果可以,我该如何实现它

class cExample

   protected function funExample()
   //functional code goes here

   return $someVar
   //end of function

//end of class


function outsideFunction()

//Calls funExample();


【问题讨论】:

你不能。这首先会破坏具有受保护功能的目的。你可以有一个代表你调用受保护方法的公共方法,但是为什么要从一个受保护方法开始呢? ***.com/q/12255740/2088851的副本 【参考方案1】:

如果父类的方法是受保护的,可以使用匿名类:

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

【讨论】:

【参考方案2】:

我正在使用 Laravel。我在访问 class 之外的 protected 方法时遇到了问题。

   $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) 是我想在不同类中访问的方法。

【讨论】:

【参考方案3】:

另一种选择 (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 '=&gt;' (T_DOUBLE_ARROW), expecting ')' 我必须改用此语法:$result = Closure::bind(function ($class) return $class-&gt;funExample(); , null, get_class($example))($example);【参考方案4】:

从技术上讲,可以使用反射 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");

【讨论】:

对于知道自己在做什么的人来说,这是正确的答案。 旁注:这在 PHP 5.4+ 中可用(是的!) 2018 年有什么变化/新的可能性吗? 这是纯金(以及问题的实际答案)【参考方案5】:

这里我可以举一个例子,如下所示

<?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 的方式

在 PHP 中,您可以使用反射来做到这一点。要调用受保护或私有方法,请使用 setAccessible() 方法 http://php.net/reflectionmethod.setaccessible(只需将其设置为 TRUE)

【讨论】:

【参考方案6】:

如果您想在类之间共享代码,您可以使用特征,但这取决于您希望如何使用您的函数/方法。

不管怎样

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

这会起作用,但请记住,您不知道您的班级是由这种方式构成的。如果你改变了这个特征,那么你所有使用它的类也会被改变。为您使用的每个特征编写一个接口也是一个好习惯。

【讨论】:

【参考方案7】:

你可以用另一个你公开的类来覆盖这个类。

class cExample2 extends cExample 
  public function funExample()
    return parent::funExample()
  

(注意这不适用于私人会员)

但私有成员和受保护成员的想法是不能从外部调用。

【讨论】:

【参考方案8】:

这就是 OOP 的重点——封装:

私人

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

【讨论】:

如果它们都扩展同一个抽象类,您可以访问另一个实例的受保护成员。 I didn't believe it until I saw it.

以上是关于我可以/如何...在 PHP 中的类之外调用受保护的函数的主要内容,如果未能解决你的问题,请参考以下文章

如何从 Ruby 中的实例方法访问受保护的类方法?

PHP 受保护的类和属性,受谁保护?

从Ruby中的实例方法调用受保护的类方法

PHP访问控制

PHP受保护的类和私有类什么区别

为啥我不能在 PHP 中调用这个受保护的函数?