2009-10-23 37 views
7

Tôi có chức năng tạo khóa gồm 4 ký tự phải là duy nhất cho mỗi lần. Để làm điều đó, hàm đầu tiên tạo ra một khóa, và sau đó kiểm tra một bảng cơ sở dữ liệu để xem nó có đang được người khác sử dụng hay không.Cách gọi một hàm bên trong chính nó?

Nếu nó không được sử dụng, nó trả về khóa, ngược lại, nó tự gọi lại, nhưng điều này làm cho hàm thực hiện một vòng lặp vô hạn, đó là một không. Đây là toàn bộ chức năng:

function key_generator($length = 4) 
{ 
    // I've subsequently left out the generating code, 
    // which is not necesarry in this case 

    $key = 'xxxx'; 

    if ($this->user_model->valid_key($key) == true) 
    { 
     return $key; 
    } 
    else 
    { 
     $this->key_generator(4); 
    } 
} 

Cách chính xác để gọi lại hàm là gì?

Nhân tiện, tôi đang sử dụng CodeIgniter, do đó $this.

+2

Nó được gọi là đệ quy – Makach

+1

Ngoài ra, $ này không dành riêng cho CodeIgniter. –

+1

Tôi nghĩ anh ta chỉ giải thích nơi $ này đến từ đâu và tại sao nó không được định nghĩa trong đoạn mã. – JAL

Trả lời

25

tôi sẽ không sử dụng chức năng đệ quy cho retry-kịch bản (kể từ khi bạn don' t sử dụng lại kết quả của hàm, nó là vô nghĩa để sử dụng đệ quy) ... Nó bổ sung thêm rất nhiều chi phí không cần thiết. Làm điều gì đó như thế này:

do { 
    $key = ...; // Generate your key here... 
} while (!$this->user_model->valid_key($key)); 

return $key; 

Nếu bạn ở gần số lượng khóa tối đa, điều này sẽ dẫn đến thời gian vòng lặp rất dài, vì vậy bạn có thể muốn đặt một số giới hạn tối đa. Oh, và nếu điều này xảy ra trên nhiều chủ đề cùng một lúc và bạn đang kiểm tra cơ sở dữ liệu, bạn nên thực hiện khóa ghi bảng để không thể chèn cùng một khóa hai lần.Tốt hơn là chức năng kiểm tra xem khóa có khả dụng hay không khóa, kiểm tra và nếu có sẵn viết trong cùng một giao dịch để tránh mọi xung đột.

+0

Bạn nói đúng. Điều này có vẻ như là giải pháp tốt nhất (và đơn giản nhất). Cảm ơn! –

+0

Giải pháp lý tưởng trong nhiều trường hợp chỉ cần cẩn thận để đặt một số cơ chế tại chỗ để ngăn chặn một vòng lặp quá dài. – Stuart

1

Bạn có thể đặt mã của bạn vào một vòng lặp và xác định phím lặp đi lặp lại thay vì đệ quy.

Ví dụ:

function key_generator($length = 4) 
{ 
    do { 
    $key = 'xxxx'; //TODO 
    if (timeOutReached()) return InvalidKey; 
    } while (!$this->user_model->valid_key($key)) 

    return $key; 
} 

Vòng lặp tự nó không ngăn chặn một vòng lặp infinte, nhưng không giống như một cuộc gọi chức năng, điều này không ăn lên không gian ngăn xếp, vì vậy bạn không có nguy cơ một chồng tràn.

Ngoài ra, nó đơn giản hóa mọi thứ một chút. Tùy thuộc vào loại khóa, bạn cũng có thể điều chỉnh phương pháp tạo khóa, ví dụ với các phím số, bạn có thể tăng theo cấp số nhân với mỗi lần lặp.

Ghi chú: Nếu có thể, hãy sử dụng tính năng tự động tăng của cơ sở dữ liệu thay vì sử dụng tính năng tạo khóa của riêng bạn.

Cũng đảm bảo bạn bảo vệ mã của mình chống lại quyền truy cập đồng thời. Nếu hai trường hợp của hàm này cố gắng tạo ra một khóa và cả hai đều xác định như vậy? Sử dụng các phần quan trọng hoặc giao dịch để đảm bảo không có gì xấu xảy ra.

2

nhưng điều này gây ra các chức năng để thực hiện một vòng lặp vô hạn,

Nếu bạn hoàn toàn muốn giữ chiến lược đệ quy của bạn, bạn phải xác định một trường hợp kết thúc. Ví dụ, bạn có thể xác định một bộ đếm, như thế này:

function key_generator($length = 4, $limit=5) 
{ 
    if($limit === 0) { 
     throw new YourException(); 
    } 

    // I've subsequently left out the generating code, 
    // which is not necesarry in this case 

    $key = 'xxxx'; 

    if ($this->user_model->valid_key($key) == true) 
    { 
     return $key; 
    } 
    else 
    { 
     return $this->key_generator(4, ($limit-1)); 
    } 
} 

Đó là tuy nhiên cũng có thể làm mã của bạn lặp đi lặp lại ...

5

Bạn cần phải trả lại kết quả của cuộc gọi tự, nếu không khóa hợp lệ sẽ không được trả lại khi nó đệ quy.

return $this->key_generator($length); 
+0

Điểm tốt =) Tôi sẽ không khuyên anh ta sử dụng đệ quy trong trường hợp này. – Blixt

2

Nếu bạn bao gồm đủ độc đáo trong thói quen thế hệ chìa khóa của bạn, bạn có thể để tránh tình trạng này ở nơi đầu tiên. Ví dụ. có thường trình xem xét dấu thời gian hiện tại và tên máy chủ cục bộ và/hoặc PID.

Vòng lặp theo cách không xác định như vậy thường là bằng chứng về một số phần quá ngây thơ. Điều đó không tốt. :-)


Nhưng dù sao, nó sẽ ít nhất là thực hành tốt để bắt nó và đăng nhập một số loại lỗi như trái ngược với treo theo yêu cầu và cuối cùng là thời gian ra:

function key_generator($length = 4) 
    { 
     /* The $attempts_left clearly depends on how much trust 
      you give your key generation code combined with the key space size. */ 
     $attempts_left = pow(16, $length) * 2; 
     /* ... just guessing, in case your key base is 16, i.e. [0-9a-z] for example */ 

     do { 
      // ... key generation goes here ... 
      $key = 'xxxx'; 
     } while ($this->user_model->valid_key($key) == false && $attempts_left-- > 0); 

     if($attempts_left < 1) 
      return false; 
     else 
      return $key; 
    } 
1

Tại sao không bạn chỉ cần quét không gian giá trị khóa cho khóa không sử dụng đầu tiên? Cần chìa khóa để thực hiện các ràng buộc bổ sung trên đỉnh dài bốn ký tự và duy nhất?

Bạn có thể nhớ khóa được trả về cuối cùng để tiếp tục quét từ đó khi có cuộc gọi tiếp theo.

Nếu bạn muốn các cuộc gọi tiếp theo không trả về các khóa tương tự, trước tiên bạn có thể trộn cơ sở dữ liệu chính của mình. Điều này có nghĩa là bạn cần phải giữ một mảng phần tử 456976, 1679616, 7311616 hoặc 14776336 ở đâu đó (tùy thuộc vào việc bảng chữ cái được sử dụng là các ký tự đơn hoặc đôi, có hoặc không có chữ số).

0

Sử dụng một hàm bên trong bản thân

function test($val) { 
    /*initialize return value by using the conditions*/ 
    if($val>=5){ 
     /*do something with return statement*/ 
     return $val+10; 
    } else { 
     /*set the return default value for avoid the error throwing*/ 
     return "default value"; 
    } 
    /*return the function used for check the condition*/ 
    return test($val); 
} 

echo test(4); // output "default value"; 
echo test(6); //output 16 
Các vấn đề liên quan