Magento 2 - thực hành tốt để sử dụng / tránh ma thuật?


21

Magic getters trên Varien_Object(M1) và DataObject(M2) là cách làm phổ biến, nhưng với Magento 2, việc sử dụng nó là sai.

Tốt

  • dễ đọc / viết

Xấu

Câu hỏi

Với Magento 2, chúng tôi có hai phương pháp mới:

  • getDataByKey($key)
  • getDataByPath($path)

Có bất kỳ lý do tốt để vẫn sử dụng getData($key)hoặc bất kỳ getters ma thuật?


Chỉnh sửa:

@Vinai cảm ơn. Tôi không đề cập đến @methodphương pháp này, vì cách tiếp cận của tôi khá khác biệt.

Nó chỉ giúp IDE, nhưng không có tác động đến những thứ khác.

Có một số PR được hợp nhất trên đó là "tối ưu hóa vi mô" như truyền (int)thay vì intval()hoặc lấy kích thước mảng bên ngoài các vòng lặp (ngay cả đối với các mảng nhỏ).

Mặt khác có

  1. ma thuật, có một số "chi phí" như Marius đã mô tả ....

    strtolower(trim(preg_replace('/([A-Z]|[0-9]+)/', "_$1", $name), '_'));
  2. getData($key) mehtods cũng phải kiểm tra thêm 2-3 ...

    • if ('' === $key) {
    • if (strpos($key, '/')) {
    • if ($index !== null) {

Đối với mã riêng, hoàn toàn đồng ý thích các phương thức thực, nhưng trong trường hợp tương tự, không thể ... ví dụ: bạn đã tạo một sự kiện tùy chỉnh ...

$value = $observer->getVar_1();
$value = $observer->getData('var_1');
$value = $observer->getDataByKey('var_1');

Sử dụng thứ 3 với /** @var some $value */dường như tốt nhất với tôi. (?)


1
Bạn có thể thêm các phương thức trong khối tài liệu lớp để các công cụ phân tích mã sẽ không phàn nàn về các phương thức không tồn tại. Ngoài ra tôi nghĩ rằng việc sử dụng các chữ số trong các khóa tự nó là một cách làm xấu, vì vậy nó không nên được liệt kê là "Xấu" ở đây imo.
Lily Bergonzat

Câu trả lời:


20

Câu hỏi trên là về việc sử dụng các phương pháp ma thuật so với getDataByKeyhoặc getDataByPath. Tôi nghĩ rằng cũng có một lựa chọn thứ ba, và đó là thực hiện các phương thức getter và setter thực sự.

Tất getData*cả các phương pháp đều có nhược điểm là chúng phải được chú thích cho kiểu suy luận để làm việc.
Thông thường, điều đó được thực hiện với một /* @var string $foo */chú thích phía trên getData*cuộc gọi.
Đây là một chút mùi, bởi vì loại dữ liệu nên được khai báo trong lớp có chứa dữ liệu, không phải lớp gọi getData*.
Lý do cho điều đó là nếu dữ liệu thay đổi, lớp có khả năng được cập nhật nhất, không phải tất cả getData*các trang web gọi.
Đó là lý do tại sao tôi nghĩ rằng các phương pháp thực sự làm tăng khả năng bảo trì so với việc sử dụng các getData*phụ kiện.

Vì vậy, tôi nghĩ rằng nó có thể đánh đổi giữa khả năng duy trì và thực hiện nhanh hơn (viết ít mã hơn).

May mắn thay, ngày nay các IDE thực sự rất giỏi trong việc tạo ra các triển khai getter và setter cho chúng ta, vì vậy đối số đó không thực sự áp dụng nữa.

Thêm một lập luận chống lại các ma thuật và setters ma thuật bị thiếu trong câu hỏi trên là không thể tạo ra các plugin cho chúng.

Giá trị khác duy nhất tôi nghĩ rằng tôi có thể thêm vào chủ đề là cố gắng thu thập các lý do để sử dụng hoặc không sử dụng @methodchú thích, nếu thực hiện các phương pháp thực sự là không cần thiết vì một số lý do.

Ưu

  • Một @methodchú thích là một ít mã để viết so với việc thực hiện một getter và setter thực sự. Điều này hầu như không đúng mặc dù ngày nay vì IDE rất tốt trong việc tạo ra các phương thức truy cập, vì vậy đó không còn là lợi ích thực sự nữa.

Nhược điểm

  • Thật dễ dàng để mọi thứ đi sai.
    • Chú thích là các bình luận, chúng trở nên lỗi thời khi mã phát triển nhưng các chú thích không được cập nhật. Phương pháp thực sự mạnh mẽ hơn.
    • Có thể thêm nhiều chú thích với các chữ ký loại khác nhau mà không có lỗi trình thông dịch - hành vi phân tích mã tĩnh không được xác định và nó có thể dẫn đến các lỗi tinh vi khó theo dõi.
    • Nếu cả @methodchú thích và phương thức thực có cùng tên tồn tại, chữ ký loại chú thích sẽ ghi đè phương thức thực trong quá trình phân tích mã tĩnh, điều này trái ngược với những gì trình thông dịch PHP thực hiện. Điều này một lần nữa có thể dễ dàng dẫn đến lỗi tinh tế.

Vì những lý do trên, cá nhân tôi không sử dụng @methodchú thích nếu tôi có thể tránh chúng.
Đối với mã được dự định để sống lâu, tôi triển khai các phương thức getter và setter thực. Việc đạt được khả năng duy trì là giá trị của nỗ lực kích hoạt IDE để tạo ra chúng.

Để biết thêm mã thử nghiệm trong quá trình tăng đột biến hoặc để biết chi tiết triển khai đơn giản của mô-đun, tôi cũng sử dụng getData*các phương thức, vì tôi lười biếng.


Tóm tắt tốt đẹp. Cảm ơn Vinai. Đó là câu trả lời nhiều hơn tôi thực sự hỏi.
sv3n

1

Tất getData*cả các phương pháp đều có nhược điểm là chúng phải được chú thích cho kiểu suy luận để làm việc.

Thông thường, điều đó được thực hiện với một /*@var string $foo */chú thích phía trên getData*cuộc gọi. Đây là một chút mùi, bởi vì loại dữ liệu nên được khai báo trong lớp có chứa dữ liệu, không phải lớp gọi getData *.

Lý do cho điều đó là nếu dữ liệu thay đổi, lớp có khả năng được cập nhật nhất, không phải tất cả getData*các trang web gọi. Đó là lý do tại sao tôi nghĩ rằng các phương thức thực sự tăng khả năng bảo trì so với việc sử dụng các bộ truy cập getData *.

Vâng, nó có mùi, nhưng có thể (và nên?) Tránh được. Tôi nghĩ rằng đây là mã rất phổ biến và thường được đề xuất:

/** @var Foo $product */
$product = $model->getProduct()
if ($product->getId()) {
    $product->doSomething();
}

Vấn đề là bạn chỉ cần đoán rằng giá trị trả về là loại Foovới một getId()metode có thể gọi được .

Để duy trì tại sao không giả sử loại biến và thêm một InvalidArgumentException?

$product = $model->getProduct()
if ($product instanceof Foo && $product->getId()) {
    $product->doSomething();
}

Điều này cũng sửa lỗi phân tích mã tĩnh trong trường hợp $model->getProduct()có các kiểu trả về khác nhau - như Foo|false. Trong trường hợp đầu tiên, nó sẽ phàn nàn về việc gọi doSomething()vào có thể false.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.