Trong lập trình hướng đối tượng, tính phản xạ là một khái niệm phức tạp hơn vẻ ngoài của nó. Thật vậy, API phản xạ trong hầu hết các ngôn ngữ thường bao gồm hai khía cạnh
- Nội quan, cho phép kiểm tra một đối tượng, khôi phục các thuộc tính, phương thức, giao diện, kế thừa,
- Tính phản xạ, cho phép sửa đổi hành vi của một đối tượng hoặc một lớp
Do đó, chúng ta có thể thấy rằng nội quan là một tổng thể toàn cầu hơn mà chúng ta gọi là tính phản thân.
Trong phần lớn các ngôn ngữ hướng đối tượng, có một API cho phép chúng ta áp dụng cả nguyên tắc hướng nội và tính phản xạ
💡 Chính nhờ nguyên tắc này mà hầu hết các thư viện
dumper
đều hoạt động. Ví dụ: thư viện PHPsymfony/var-dumper
sử dụng tính phản xạ để gỡ lỗi các biến, đối tượng,. Bằng cách hiển thị các thuộc tính của đối tượng này
Tuy nhiên, không nên nhầm lẫn nguyên tắc này với sự xem xét nội tâm.
Cuối cùng, áp dụng loại nguyên tắc này cho phép chúng ta
- Truy cập các thuộc tính của một đối tượng thông qua xem xét nội tâm,
- Sửa đổi hành vi của các đối tượng này tại thời điểm thực hiện chương trình thông qua tính phản xạ,
- Gọi một phương thức không tĩnh mà không tạo một đối tượng tương ứng với lớp
Do đó, ưu điểm chính của nguyên tắc như vậy là, lúc đầu, việc gỡ lỗi hành vi của một lớp hoặc một phương thức trở nên dễ dàng hơn, bởi vì nhờ tính phản xạ, và đặc biệt hơn là khả năng xem xét nội quan, có thể khôi phục các giao diện đã triển khai, các . Do đó, tương đối dễ dàng để phát hiện hành vi bất thường trên một phần của lớp chúng tôi đang kiểm tra
Một ưu điểm khác là nó có thể, vẫn nhờ vào tính phản thân, để sửa đổi hành vi của một lớp. Ví dụ: nếu chúng ta phải gọi một phương thức riêng tư trong một số điều kiện nhất định, nhờ tính phản xạ, có thể sửa đổi một cách có điều kiện hành vi của phương thức bằng cách đặt nó ở chế độ công khai
Thí dụ
Một ví dụ hoàn chỉnh có sẵn trong kho lưu trữ Github mà tôi đã tạo cho dịp này. https. //github. com/MrAnyx/ví dụ-phản xạ
nội tâm
Giả sử chúng ta có lớp sau
// src/Student.php
namespace App;
use App\Interfaces\StudentBehaviour;
use Exception;
use Stringable;
class Student extends SchoolPerson implements StudentBehaviour, Stringable
{
/**
* @param string $firstname
* @param string $lastname
* @param string $birth
* @param string $schoolName
* @param string $identifier
* @throws Exception
*/
public function __construct[
string $firstname,
string $lastname,
string $birth,
string $schoolName,
string $identifier
]{
parent::__construct[$firstname, $lastname, $birth, $schoolName, $identifier];
}
/**
* @return void
*/
public function study[]: void
{
echo "I'm studying for my maths exam";
}
/**
* @return string
*/
public function __toString[]: string
{
return parent::__toString[] . printf[" and I'm currently studying at the UQAC"];
}
}
Do đó, bằng cách áp dụng nguyên tắc hướng nội như được minh họa trong đoạn mã dưới đây
// introspection.php
use ReflectionClass;
use App\Student;
$reflection = new ReflectionClass[Student::class];
$constructor = $reflection->getConstructor[];
printf["To create an object of type %s, you must specify %d parameters\n",
$constructor->getDeclaringClass[]->getName[],
$constructor->getNumberOfParameters[]
];
if [$constructor->getNumberOfParameters[] !== 0] {
foreach [$constructor->getParameters[] as $parameter] {
printf[" > %s of type %s\n",
$parameter->getName[],
$parameter->getType[]->getName[]
];
}
}
Chúng tôi thu được kết quả sau
To create an object of type App\Student, you must specify 0 parameters
> firstname of type string
> lastname of type string
> birth of type string
> schoolName of type string
> identifier of type string
Sự phản xạ
Đối với sự phản ánh, giả sử chúng ta có lớp sau
// src/Foo.php
namespace App;
class Foo
{
/**
* @return void
*/
private function bar[]: void
{
echo "Initially, I was a private function";
}
}
Như vậy, nếu chúng ta áp dụng nguyên tắc phản chiếu với đoạn mã sau
use App\Foo;
// We create a reflection of the "bar" method from the Foo class
$method = new ReflectionMethod[Foo::class, 'bar'];
// We modify its behavior by making it accessible from the outside
// In other words, we make the method public
$method->setAccessible[true];
// We call the function
$method->invoke[new Foo];
// We make the method private again
$method->setAccessible[false];
Thay vì gặp lỗi khi chạy chương trình, chúng ta nhận được kết quả như sau
Initially, i was a private function
Nói cách khác, có thể gọi phương thức bar
của lớp Foo
mặc dù nó là private