PHP Overloading 怎么用?方法重载实现与示例详解

文章导读
Previous Quiz Next 在 C++ 或 Java 中,这个术语表示一个 class 可以定义同名的 class method 多次,但参数和/或返回值类型不同。在 PHP 中,overloading 的含义有所不同。它是一种特性,可以动态创建 properti
📋 目录
  1. Property Overloading
  2. 方法重载
  3. 重载中的访问控制
  4. 处理未定义的属性和方法
  5. 继承和重载
A A

PHP - 重载



Previous
Quiz
Next

在 C++ 或 Java 中,这个术语表示一个 class 可以定义同名的 class method 多次,但参数和/或返回值类型不同。在 PHP 中,overloading 的含义有所不同。它是一种特性,可以动态创建 properties 和 methods。PHP 的 magic methods(以双下划线开头的 method 名称)用于设置动态 properties 和 methods。

用于 overloading 目的的 magic methods 在与未声明或当前 scope 中不可见的 properties 或 methods 交互时会被调用。

因此在本章中,我们涵盖了以下主题 −

  • Property Overloading

  • Method Overloading

  • Overloading 中的访问控制

  • 处理未定义的 Properties 和 Methods

  • 继承与 Overloading

Property Overloading

PHP 的 magic methods 示例包括 __construct()、__destruct()、__tostring() 等。PHP 使用以下 magic methods 来实现 properties 的 overloading。

public __set ( string $name , mixed $value ) : void
public __get ( string $name ) : mixed
public __isset ( string $name ) : bool
public __unset ( string $name ) : void

这里,

  • __set() 在向受保护的、private 的或不存在的不可访问 properties 写入数据时运行。

  • __get() 从不可访问的 properties 读取数据。

  • __isset() 在对不可访问的 properties 调用 isset() 或 empty() 时被调用。

  • __unset() 在对不可访问的 properties 调用 unset() 时被调用。

上面使用的 $name 参数是要设置或获取的 property 的名称。__set() method 的 $value 参数指定要赋给 property 的值。

__isset() method 检查某个 property 是否已被设置。__unset() method 删除该 property。

Property overloading 仅在 object context 中有效。在任何 static context 中,这些 magic methods 不会被触发。因此它们不应被声明为 static。

示例

在以下代码中,设置并获取了一个在 class 中未声明的动态 property,名为 myprop。

<?php
   class myclass {
      public function __set($name, $value) {
         echo "setting $name property to $value \n";
         $this->$name = $value;
      }

      public function __get($name) {
         echo "value of $name property is ";
         return $this->$name;
      }
   }

   $obj = new myclass();

   # 这会调用 __set() method
   $obj->myproperty="Hello World!";

   # 这会调用 __get() method
   echo "Retrieving myproperty: " . $obj->myproperty . PHP_EOL;
?>

它将产生以下 输出

setting myproperty property to Hello World! 
Retrieving myproperty: Hello World!

__set()__get() magic methods 也可以设置和获取声明为 private 的 property。在 myclass 中(在 function 定义之前)添加以下语句

private $myproperty;

你可以通过在 myclass 中定义 __isset() method 来检查 property 是否存在 −

public function __isset($name) {
   return isset($this->$name);
}

使用此语句检查 property 是否已设置 −

var_dump (isset($obj->myproperty));

在这种情况下返回 true

要使用在 myclass 中定义的 __unset() method 取消动态创建的 property −

public function __unset($name) {
   unset($this->$name);
}

以下代码将返回 false

var_dump (isset($obj->myproperty));

方法重载

用于动态设置方法的两个魔术方法是 __call()__callStatic()

public __call (string $name , array $arguments) : mixed
public static __callStatic (string $name , array $arguments) : mixed

当在对象上下文中调用不可访问的(未定义或 private)方法时,会触发 __call()。另一方面,当在静态上下文中调用不可访问的方法时,会触发 __callStatic()。

示例

以下示例演示了 PHP 中的方法重载

<?php
   class myclass {
      public function __call($name, $args) {
	  
         // $name 的值区分大小写。
         echo "Calling object method $name with " . implode(" ", $args). "\n";
      }
      public static function __callStatic($name, $args) {
         echo "Calling static method $name with " . implode(" ", $args). "\n";
      }
   }
   $obj = new myclass();

   # 这会调用 __call() 魔术方法
   $obj->mymethod("Hello World!");

   # 这会调用 __callStatic() 方法
   myclass::mymethod("Hello World!");
?>

它将产生以下 输出

Calling object method mymethod with Hello World!
Calling static method mymethod with Hello World!

重载中的访问控制

这里的 __get 和 __set 方法可以访问 private 或 protected 属性,这可能会绕过封装。

<?php
   class Example {
      private $name;

      public function __set($property, $value) {
         $this->$property = $value;
      }

      public function __get($property) {
         return $this->$property;
      }
   }

   $obj = new Example();
   // 访问 private 属性
   $obj->name = "Radhika"; 

   echo $obj->name;
?> 

输出

以上代码的输出如下 −

Radhika

处理未定义的属性和方法

为了避免意外行为,请在魔术方法中添加测试或异常。请看下面的示例 −

<?php
   class SafeExample {
      public function __get($name) {
         if (!property_exists($this, $name)) {
            throw new Exception("Property '$name' does not exist.");
         }
      }
   }

   $obj = new SafeExample();
   try {
      echo $obj->unknownProperty;
   } catch (Exception $e) {
      echo $e->getMessage(); 
   }
?> 

输出

这将产生以下输出 −

Property 'unknownProperty' does not exist.

继承和重载

子类可以重写魔术方法,因此您可能需要使用 parent::__call() 来保持父类功能。

   class ParentClass {
      public function __call($name, $arguments) {
         echo "Parent method: $name\n";
      }
   }

   class ChildClass extends ParentClass {
      public function __call($name, $arguments) {
         echo "Child method: $name\n";
         parent::__call($name, $arguments);
      }
   }

   $obj = new ChildClass();
   $obj->testMethod();

输出

这将生成以下输出 −

Child method: testMethod
Parent method: testMethod

注意,使用 "->" 操作符表示该方法是 实例方法,而 "::" 操作符表示该方法是 静态方法