$ _POST, $ _GET, v.v có vi phạm nguyên tắc đóng gói không?


9

Sử dụng toàn cầu làm cho mã của bạn khó kiểm tra do đó dễ bị lỗi hơn, không an toàn và không thể đoán trước. Đó là lý do tại sao chúng ta truyền các biến mà chúng ta muốn bên trong một hàm / đối tượng. Vì vậy, câu hỏi của tôi rất đơn giản:

$ _POST, $ _GET, v.v có vi phạm nguyên tắc đóng gói không?

Tôi nghĩ rằng, để duy trì quyền kiểm soát các biến đó theo cách OO, một giải pháp lý tưởng sẽ là thêm một số dòng như thế này vào mã:

// Convert the $_GET array to an object
$get = json_decode(json_encode($_GET), FALSE);  // stackoverflow.com/a/1869147
// Stop it from being included from anywhere
unset($_GET);

// Small example of what could be done later on
$DB = new PDO(/* ... */);
$Person = new Person($DB, $get->id);

Tôi chưa thấy điều này ở bất cứ đâu, thậm chí không có hướng dẫn cũng như khuyến nghị. Ngoài ra, chúng ta có thể thấy rõ cách mã ở trên dễ kiểm tra hơn nhiều so với mã bao gồm $Person = new Person($DB, $_GET['id']);hoặc thậm chí (xấu xí) $Person = new Person($DB);khi bạn có thể sử dụng một $getđối tượng giả .

Là mã ở trên đúng hướng hay tôi đang thiếu một cái gì đó?

EDIT: Sau một số cuộc điều tra ( khung ZendCake PHP ) như Alexander Kuzmin đề xuất, có vẻ như đó là điều đúng đắn. Chúng có thể quá lớn đối với tôi để đào sâu vào mã ATM, nhưng tôi sẽ ghi nhớ nó.


1
Đóng gói luôn có vẻ ngớ ngẩn đối với tôi để tuân thủ như một "nguyên tắc". Nó chỉ là một tính năng; hoặc một ngôn ngữ có nó, hoặc nó không.
Ignacio Vazquez-Abrams

Tôi không phải người bản xứ nên tôi không biết phải gọi nó như thế nào và kết thúc việc viết nguyên tắc . Xin vui lòng chỉnh sửa tiêu đề / văn bản nếu bạn thấy nó có thể có một từ ngữ tốt hơn.
Francisco Presencia

6
Đây là thông minh và cũng là cách mà hầu hết các khung công tác PHP giải quyết nó. Vì vậy, yeah, tôi nghĩ rằng bạn đang vào một cái gì đó.
Alexander Kuzmin

Tôi chỉ đang điều tra ở đó, @AlexanderKuzmin! Nó dường như là tốt nhất, cập nhật.
Francisco Presencia

Tôi có thể hỏi tại sao nó có ý kiến ​​dựa trên thẻ đóng? Mặc dù câu hỏi phụ thứ hai tôi đồng ý dựa trên ý kiến ​​của mình (nhưng chỉ cho ví dụ cụ thể), tôi nghĩ rằng câu hỏi chính là hợp lệ.
Francisco Presencia

Câu trả lời:


8

Tôi không chắc chắn lý do tại sao bạn áp dụng json_decodeđể $_GETchuyển đổi nó thành một mảng MẠNH; $_GETđã một mảng.

Sử dụng siêu toàn cầu ( $_GET, $_POSTv.v.) vi phạm nguyên tắc đóng gói. Nhưng đã có một dòng được vẽ trong đó bạn ngừng đóng gói mọi thứ. Dữ liệu yêu cầu là một ứng cử viên tốt cho việc đóng gói, nhưng đừng bị hút xuống hố thỏ khi cố gắng gói gọn tất cả mọi thứ .

Hầu hết các khung công tác thường bao bọc các siêu toàn cầu của PHP vào một số dạng đối tượng yêu cầu. Làm điều này sau đó giúp dễ dàng giả hơn cho các bài kiểm tra, vv Cách tiếp cận đơn giản nhất sẽ là:

<?php
class Request
{
    public $get;
    public $post;
    public $session;
    public $cookie;

    public function __construct($get, $post, $session, $cookie)
    {
        $this->get = $get;
        $this->post = $post;
        $this->session = $session;
        $this->cookie = $cookie;
    }
}

$request = new Request($_GET, $_POST, $_SESSION, $_COOKIE);

Nó đơn giản và thô sơ, nhưng thực hiện công việc. Bạn cũng nên lọc dữ liệu vào thời điểm này, để bảo vệ chống lại việc tiêm XSS.

Nhưng nó được bọc trong một Requestvật thể. Đối Requesttượng có bốn mảng và các mảng này có thể dễ dàng bị chế giễu:

$get = array(
    'foo' => 'bar'
);
$post = array();
$session = array(
    'user' => 1
);
$cookie = array();

$request = new Request($get, $post, $session, $cookie);

Tôi đang cố gắng chuyển đổi chúng thành các đối tượng, như đã nêu trong bình luận // Convert the $_GET array to an object. Hơn nữa, câu trả lời này stackoverflow.com/a/1869147 là lý do tại sao tôi làm điều đó. Ngoài chi tiết nhỏ đó, cảm ơn bạn rất nhiều vì một câu trả lời hoàn chỉnh như vậy với những lời khuyên bổ sung, rất giống với những gì tôi dự định làm.
Francisco Presencia

3
Tôi sẽ không chuyển đổi $_GETdữ liệu thành một đối tượng. Mảng không bẩn. Tôi cảm thấy mọi người né tránh các mảng vì họ cảm thấy họ không phải là OOP, giống như không ai dám sử dụng <table>HTML vì sợ không có ngữ nghĩa, ngay cả với dữ liệu dạng bảng. Lấy $_GETmảng. Điều gì xảy ra nếu tôi chuyển dữ liệu mảng từ biểu mẫu của mình, nghĩa là <input type="checkbox" name="foo[]" />hay <select name="bar[]" multiple="multiple">? Bạn sẽ chuyển đổi chúng thành các đối tượng hoặc để chúng như vậy? Chỉ cần để lại $_GETmảng như một mảng, như dự định.
Martin Bean

Tôi cũng nghĩ về trường hợp đó với nhiều mảng cấp độ và tôi cho rằng nó sẽ biến chúng thành các đối tượng phụ, nhưng các giả định không tốt. Tôi đã chuyển đổi nó (bẩn cho đến nay) thành một đối tượng để có thể sửa đổi getter và setter, điều này sẽ giúp tôi linh hoạt hơn, ví dụ, kiểm tra chống lại việc tiêm XSS trên đầu ra, nhưng điều đó cũng có thể được thực hiện trong sơ đồ đề xuất của bạn.
Francisco Presencia

Vâng, bạn cũng có thể chỉ để chúng là mảng đa chiều. Mảng không bẩn và không làm cho mã của bạn không phải là OOP nếu bạn sử dụng chúng làm cấu trúc dữ liệu. Đừng sợ chúng. Nếu dữ liệu của bạn không có bất kỳ phương thức hoặc thuộc tính nào (như GETPOSTdữ liệu) thì có lẽ nó không cần phải là một đối tượng.
Martin Bean

Một vấn đề phụ / niggle ... Tôi truy vấn quyết định đưa $ _SESSION vào đối tượng yêu cầu, vì cách xử lý đặc biệt của superglobal $ _SESSION (bạn cần triển khai getters / setters và đảm bảo phiên được bắt đầu sớm, v.v.) và nó không thực sự là một phần của "yêu cầu" IMO.
MrWhite

2

Sử dụng superglobals $_{POST,GET,SERVER}hoặc bất cứ điều gì chắc chắn vi phạm đóng gói.

Vấn đề này phát triển khi bạn muốn tạo "yêu cầu cục bộ" trong phía máy chủ của ứng dụng của bạn như nhiều khung công tác hiện nay.

Tôi không quen làm việc với các khung công tác, nhưng điều tôi thường làm là tạo một cặp Yêu cầu / Phản hồi khi bắt đầu xử lý. Yêu cầu chứa các giá trị các tham số toàn cầu này.

Nếu tôi muốn tạo một yêu cầu con phía máy chủ, tôi có hai tùy chọn: sử dụng bối cảnh hiện tại hoặc tạo một bối cảnh hoàn toàn mới. Vì vậy, tôi nghĩ rằng bạn không nên bỏ qua các biến siêu đối xứng này vì CÓ THỂ bạn muốn sử dụng lại chúng. Ngoài ra, vì lý do này, tôi không đồng ý rằng yêu cầu params phải là singletons.

Bằng cách chỉ chứa các giá trị, không tham chiếu đến các siêu lớp này, một thay đổi trong một đối tượng Yêu cầu sẽ không bao giờ ảnh hưởng đến một đối tượng khác, do đó, vấn đề với trạng thái toàn cầu được giải quyết.

Vì vậy, về cơ bản, tôi có hai lựa chọn:

// Using global context
$request = new Request(array(
    'post' => $_POST,
    'get' => $_GET
));

// or creating a new context

$request = new Request(array(
    'post' => ['someKey' => 'someValue'],
    'get' => ['queryParam' => 'queryValue'],
));

0

POST- và GET-vars được gửi đến máy chủ với số lượng lớn và php phải hiểu ý nghĩa của chúng. Theo một cách nào đó, thật hợp lý khi có sẵn chúng trên toàn cầu, vì vậy nhà phát triển có thể chọn nơi xử lý chúng.

Nhiều khung (như CakePHP chẳng hạn) đọc các Tham số và sau đó đặt tất cả chúng trong một số mảng, đối tượng hoặc cấu trúc tương tự. Sau đó, chúng được xử lý như mọi dữ liệu khác và được truyền cho tất cả các phương thức cần chúng.


1
Bạn có nghĩa là nó hoạt động theo cách đó bởi vì PHP không thể chèn một biến cục bộ trong tập lệnh chính hiện tại như thế index.phpnào?
Francisco Presencia

Không, nhưng việc cung cấp các biến thông qua mảng toàn cầu mang lại sự linh hoạt hơn cho việc triển khai một số hình thức phân tích cú pháp của nhà phát triển.

0

Đóng gói là một nguyên tắc tốt khi có cơ hội bạn có thể cần nhiều phiên bản của một cái gì đó. Nhưng chỉ có một bộ thông số cho một trang web. Nếu họ ở trong một lớp thay vì các biến toàn cục, họ có thể sẽ là người độc thân. Không có sự cải thiện đáng kể nào từ các biến toàn cầu sang các lớp đơn, đó chỉ là một cú pháp khác nhau để truy cập chúng. Chúng vẫn vốn là các đối tượng toàn cầu, nó chỉ cồng kềnh hơn vì bạn phải xử lý cá thể lớp và vượt qua nó.

Do các tham số này được truy cập rất thường xuyên, nên các nhà thiết kế PHP đã đưa ra quyết định làm cho chúng dễ truy cập, thay vì tuân thủ các nguyên tắc thiết kế cứng nhắc. Đó là một ý tưởng tốt để làm cho các hoạt động phổ biến nhất trở nên thuận tiện, nếu không các lập trình viên sẽ nguyền rủa bạn vì đã khiến họ gõ lại giống nhau, điều dài mỗi lần.


Mặc dù tôi đồng ý về việc truy cập thường xuyên vào chúng, tôi không đồng ý If they were in a class instead of global variables, they would probably be singletonsvì các singletons cũng nằm trong phạm vi toàn cầu . Tôi chỉ nói về việc xóa hoàn toàn trạng thái toàn cầu đó và biến nó thành địa phương, mượn ý tưởng này từ The Clean Code Talks - "Global State and Singletons" . Có mối quan tâm chính của tôi khi đặt câu hỏi này: thử nghiệm . Thật không may, có vẻ như bạn đã không đọc toàn bộ câu hỏi mà chỉ có tiêu đề
Francisco Presencia

1
Quan điểm của tôi là vì chỉ có một kết nối máy khách và một bộ thông số, nên chúng là toàn cầu.

Đó là một sự đánh đổi: sự thuận tiện so với việc tuân thủ nghiêm ngặt các nguyên tắc thiết kế. Nếu bạn thoát khỏi các siêu sao, bạn sẽ phải chuyển $gettừ chức năng này sang chức năng khác.
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.