<?php declare(strict_types=1); ini_set('display_errors', 'On'); error_reporting(-1); /** * Human类 */ class Human { private string $name; private string $gender; private int $age; public function __construct(string $name, string $gender, int $age) { $this->name = $name; $this->gender = $gender; $this->age = $age; } public function profile(string $job): array { echo "俺叫{$this->name}({$this->gender}),今年{$this->age}岁,俺是一名{$job}。" . PHP_EOL; return [ 'name' => $this->name, 'gender' => $this->gender, 'age' => $this->age, 'job' => $job, ]; } } // 反射Animal类(类不存在) try { $reflectionClass = new ReflectionClass('Animal'); } catch (ReflectionException $e) { echo 'ReflectionException: ' . $e->getMessage() . PHP_EOL; // ReflectionException: Class "Animal" does not exist } // 反射Human类(类存在) try { $reflectionClass = new ReflectionClass('Human'); } catch (ReflectionException) { $reflectionClass = null; } // 如果反射Human类成功则进一步执行其它操作,如创建实例、调用方法、修改属性等操作 if ($reflectionClass instanceof ReflectionClass) { // 使用ReflectionClass::newInstanceArgs()创建实例,其中$args为构造方法的参数 $args = ['张三', '男', 18]; $instance = $reflectionClass->newInstanceArgs($args); // 获取实例的类名 echo '$instance::class is ' . $instance::class . PHP_EOL; // $instance::class is Human // 利用反射判断profile()方法是否存在 if ($reflectionClass->hasMethod('profile')) { // 利用反射获取profile()方法,并判断该方法是否为public,如果是public则调用 // 重要说明:通过反射调用方法其实不受private和protected的限制,但是通过实例调用方法会受到限制,所以需要判断一下。 $reflectionMethod = $reflectionClass->getMethod('profile'); if ($reflectionMethod->isPublic()) { // 调用profile()方法 ☛ 方式①:通过反射调用 $profile1 = $reflectionMethod->invokeArgs($instance, ['程序猿']); echo print_r($profile1, true); // 俺叫张三(男),今年18岁,俺是一名程序猿。 // Array // ( // [name] => 张三 // [gender] => 男 // [age] => 18 // [job] => 程序猿 // ) // 调用profile()方法 ☛ 方式②:通过实例调用 $profile2 = $instance->profile('攻城狮'); echo print_r($profile2, true); // 俺叫张三(男),今年18岁,俺是一名攻城狮。 // Array // ( // [name] => 张三 // [gender] => 男 // [age] => 18 // [job] => 攻城狮 // ) } } // 利用反射判断name、gender、age属性是否存在,若存在则修改 $reflectionClass->hasProperty('name') && $reflectionClass->getProperty('name')->setValue($instance, '李四'); $reflectionClass->hasProperty('gender') && $reflectionClass->getProperty('gender')->setValue($instance, '女'); $reflectionClass->hasProperty('age') && $reflectionClass->getProperty('age')->setValue($instance, 17); $profile3 = $reflectionClass->getMethod('profile')->invokeArgs($instance, ['IT民工']); echo print_r($profile3, true); // 俺叫李四(女),今年17岁,俺是一名IT民工。 // Array // ( // [name] => 李四 // [gender] => 女 // [age] => 17 // [job] => IT民工 // ) } //========== 总结 ==========// // 1、在以具体业务为导向的开发中,反射使用得并不多,一般都是写框架才会使用反射(如ThinkPHP这类框架)。 // 2、反射的运行效率是非常低的,如果能使用new创建实例,就不要使用反射创建实例。 // 3、反射是非常强大和灵活的工具,它可以绕过可见性限制(private和protected)直接修改属性值和调用方法,甚至还可以直接修改可见性, // 但是强烈不建议通过反射修改属性值,因为这种做法违反了封装原则,并可能导致运行时错误。
Copyright © 2024 码农人生. All Rights Reserved