2008-09-28 38 views
60

Vì vậy, tôi đang lập trình cùng một kiểu dáng đẹp, cập nhật, hướng đối tượng. Tôi thường xuyên sử dụng các khía cạnh khác nhau của OOP mà PHP thực hiện nhưng tôi tự hỏi khi nào tôi có thể cần phải sử dụng các bao đóng. Bất kỳ chuyên gia nào ở đó có thể làm sáng tỏ khi nào sẽ hữu ích khi triển khai đóng cửa?Đóng cửa trong PHP ... những gì, chính xác, là họ và khi nào bạn sẽ cần phải sử dụng chúng?

Trả lời

61

PHP sẽ hỗ trợ đóng cửa tự nhiên trong 5.3. Một đóng cửa là tốt khi bạn muốn có một chức năng địa phương chỉ được sử dụng cho một số mục đích nhỏ, cụ thể.Các RFC for closures đưa ra một ví dụ điển hình:

function replace_spaces ($text) { 
    $replacement = function ($matches) { 
     return str_replace ($matches[1], ' ', ' ').' '; 
    }; 
    return preg_replace_callback ('/(+) /', $replacement, $text); 
} 

này cho phép bạn xác định replacement chức năng tại địa phương bên replace_spaces(), do đó nó không phải là:
1) cluttering lên không gian tên toàn cầu
2) Làm người ba năm xuống dòng tự hỏi tại sao có một hàm được xác định trên toàn cầu chỉ được sử dụng bên trong một hàm khác

Nó giữ mọi thứ được tổ chức. Chú ý rằng bản thân hàm không có tên, nó đơn giản được định nghĩa và gán như một tham chiếu đến $replacement. Tuy nhiên, hãy nhớ, bạn phải đợi PHP 5.3 :)

+1

Đây là một lời giải thích tuyệt vời. +1 –

+2

Tôi rất thích lời giải thích của ** lý do tại sao ** bạn sẽ sử dụng các bao đóng. Hầu hết mọi người không thực sự hiểu điều đó. +1 –

+7

Đây là giải thích về các chức năng ẩn danh, không phải là giải thích về đóng cửa. Các hàm ẩn danh, như bạn nói, giống như các hàm được đặt tên, ngoại trừ chúng không phải là toàn cục. Đóng cửa, mặt khác, là các hàm có chứa các biến miễn phí lexically-scoped (được khai báo với "use"); I E. họ có thể sao chép và tham chiếu các giá trị từ phạm vi mà chúng được khai báo, ngay cả sau khi mọi thứ khác đã được thu thập rác. – Warbo

14

Khi nào bạn sẽ cần một chức năng trong tương lai thực hiện nhiệm vụ mà bạn đã quyết định ngay bây giờ. Ví dụ: nếu bạn đọc tệp cấu hình và một trong các thông số cho bạn biết rằng hash_method cho thuật toán của bạn là multiply thay vì square, bạn có thể tạo bao đóng sẽ được sử dụng ở bất cứ đâu bạn cần băm.

Có thể tạo bao đóng trong (ví dụ) config_parser(); nó tạo ra một hàm gọi là do_hash_method() sử dụng các biến cục bộ thành config_parser() (từ tệp cấu hình). Bất cứ khi nào do_hash_method() được gọi, nó có quyền truy cập vào các biến trong phạm vi địa phương là config_parser() mặc dù nó không được gọi trong phạm vi đó.

Một hy vọng tốt giả dụ:

function config_parser() 
{ 
    // Do some code here 
    // $hash_method is in config_parser() local scope 
    $hash_method = 'multiply'; 

    if ($hashing_enabled) 
    { 
     function do_hash_method($var) 
     { 
      // $hash_method is from the parent's local scope 
      if ($hash_method == 'multiply') 
       return $var * $var; 
      else 
       return $var^$var; 
     } 
    } 
} 


function hashme($val) 
{ 
    // do_hash_method still knows about $hash_method 
    // even though it's not in the local scope anymore 
    $val = do_hash_method($val) 
} 
+0

tôi không thể chỉ cần sao chép dán ví dụ này và chạy nó. Ưu tiên một ví dụ mà tôi có thể chỉ cần chạy. –

+14

-1 cho mã không hoạt động. – deceze

+1

Câu trả lời này rất kém. Đây là một tuyên bố vô nghĩa: "Khi bạn sẽ cần một chức năng trong tương lai mà thực hiện một nhiệm vụ mà bạn đã quyết định ngay bây giờ." – Puzbie

14

Ngoài các chi tiết kỹ thuật, đóng cửa là một điều kiện tiên quyết cơ bản cho một phong cách lập trình được gọi là lập trình chức năng định hướng. Một đóng được sử dụng gần như cho cùng một điều khi bạn sử dụng một đối tượng trong lập trình hướng đối tượng; Nó liên kết dữ liệu (các biến) cùng với một số mã (một hàm), sau đó bạn có thể chuyển đến một nơi khác. Như vậy, chúng ảnh hưởng đến cách bạn viết chương trình hoặc - nếu bạn không thay đổi cách bạn viết chương trình của bạn - chúng không có bất kỳ tác động nào cả.

Trong ngữ cảnh của PHP, chúng hơi lạ, vì PHP đã nặng trên mô hình hướng đối tượng dựa trên lớp, cũng như mô hình thủ tục cũ hơn. Thông thường, các ngôn ngữ có đóng cửa, có phạm vi từ vựng đầy đủ. Để duy trì tính tương thích ngược, PHP sẽ không nhận được điều này, vì vậy điều đó có nghĩa là các bao đóng sẽ có một chút khác biệt ở đây, so với các ngôn ngữ khác. Tôi nghĩ chúng ta vẫn chưa biết chính xác chúng sẽ được sử dụng như thế nào.

8

Tôi thích ngữ cảnh do bài viết của troelskn cung cấp. Khi tôi muốn làm một cái gì đó giống như ví dụ của Dan Udey trong PHP, tôi sử dụng mẫu chiến lược OO. Theo tôi, điều này là tốt hơn nhiều so với giới thiệu một chức năng toàn cầu mới có hành vi được xác định trong thời gian chạy.

http://en.wikipedia.org/wiki/Strategy_pattern

Bạn cũng có thể gọi chức năng và phương pháp sử dụng một biến giữ tên method trong PHP, đó là rất tốt. rất khác mất trên ví dụ của Dan sẽ là một cái gì đó như thế này:

class ConfigurableEncoder{ 
     private $algorithm = 'multiply'; //default is multiply 

     public function encode($x){ 
       return call_user_func(array($this,$this->algorithm),$x); 
     } 

     public function multiply($x){ 
       return $x * 5; 
     } 

     public function add($x){ 
       return $x + 5; 
     } 

     public function setAlgorithm($algName){ 
       switch(strtolower($algName)){ 
         case 'add': 
           $this->algorithm = 'add'; 
           break; 
         case 'multiply':  //fall through 
         default:    //default is multiply 
           $this->algorithm = 'multiply'; 
           break; 
       } 
     } 
} 

$raw = 5; 
$encoder = new ConfigurableEncoder();       // set to multiply 
echo "raw: $raw\n";            // 5 
echo "multiply: " . $encoder->encode($raw) . "\n";    // 25 
$encoder->setAlgorithm('add'); 
echo "add: " . $encoder->encode($raw) . "\n";     // 10 

tất nhiên, nếu bạn muốn nó có sẵn ở khắp mọi nơi, bạn chỉ có thể làm cho mọi thứ tĩnh ...

1

Một đóng về cơ bản là một hàm mà bạn viết định nghĩa trong một ngữ cảnh nhưng chạy trong ngữ cảnh khác. Javascript đã giúp tôi rất nhiều với sự hiểu biết này, bởi vì chúng được sử dụng trong JavaScript trên tất cả các nơi.

Trong PHP, chúng kém hiệu quả hơn trong JavaScript, do sự khác biệt về phạm vi và khả năng truy cập của biến "toàn cầu" (hoặc "bên ngoài") từ bên trong các hàm. Tuy nhiên, bắt đầu với PHP 5.4, các bao đóng có thể truy cập vào $ this object khi chạy bên trong một đối tượng, điều này làm cho chúng hiệu quả hơn rất nhiều.

Đây là những gì đóng cửa là về, và nó sẽ là đủ để hiểu những gì được viết ở trên. Điều này có nghĩa là bạn có thể viết định nghĩa hàm ở đâu đó và sử dụng biến $ this bên trong định nghĩa hàm, sau đó gán định nghĩa hàm cho biến (một số khác đã đưa ra ví dụ về cú pháp), sau đó vượt qua điều này biến thành đối tượng và gọi nó trong ngữ cảnh đối tượng, sau đó hàm có thể truy cập và thao tác đối tượng thông qua $ this như thể nó chỉ là một phương thức khác, khi thực tế nó không được định nghĩa trong định nghĩa lớp của đối tượng đó, nhưng ở một nơi khác.

Nếu nó không rõ ràng, đừng lo lắng, nó sẽ trở nên rõ ràng khi bạn bắt đầu sử dụng chúng.

+0

Thành thật mà nói, tôi không rõ ràng, ngay cả đối với tôi, tác giả. Về cơ bản tôi đang nói: để tìm hiểu xem những gì đóng được kiểm tra chúng trong JavaScript, nhưng hãy nhớ rằng phạm vi biến là khác nhau giữa JavaScript và PHP. – Rolf

0

Dưới đây là ví dụ cho việc đóng cửa trong php

// Author: [email protected] 
// Publish on: 2017-08-28 

class users 
{ 
    private $users = null; 
    private $i = 5; 

    function __construct(){ 
     // Get users from database 
     $this->users = array('a', 'b', 'c', 'd', 'e', 'f'); 
    } 

    function displayUsers($callback){ 
     for($n=0; $n<=$this->i; $n++){ 
      echo $callback($this->users[$n], $n); 
     } 
    } 

    function showUsers($callback){ 
     return $callback($this->users); 

    } 

    function getUserByID($id, $callback){ 
     $user = isset($this->users[$id]) ? $this->users[$id] : null; 
     return $callback($user); 
    } 

} 

$u = new users(); 

$u->displayUsers(function($username, $userID){ 
    echo "$userID -> $username<br>"; 
}); 

$u->showUsers(function($users){ 
    foreach($users as $user){ 
     echo strtoupper($user).' '; 
    } 

}); 

$x = $u->getUserByID(2, function($user){ 

    return "<h1>$user</h1>"; 
}); 

echo ($x); 

Output:

0 -> a 
1 -> b 
2 -> c 
3 -> d 
4 -> e 
5 -> f 

A B C D E F 

c 
Các vấn đề liên quan