2010-04-26 31 views
7

Tôi đã sử dụng PDO và chuẩn bị tất cả các tuyên bố của tôi chủ yếu vì lý do bảo mật. Tuy nhiên, tôi có một phần mã của tôi rằng không thực thi cùng một câu lệnh nhiều lần với các tham số khác nhau và tôi nghĩ đây sẽ là nơi các câu lệnh được chuẩn bị thực sự tỏa sáng. Nhưng họ thực sự phá vỡ mã ...Đệ quy trong các báo cáo đã chuẩn bị

Logic cơ bản của mã này.

function someFunction($something) { 
    global $pdo; 

    $array = array(); 

    static $handle = null; 
    if (!$handle) { 
    $handle = $pdo->prepare("A STATEMENT WITH :a_param"); 
    } 

    $handle->bindValue(":a_param", $something); 
    if ($handle->execute()) { 
    while ($row = $handle->fetch()) { 
     $array[] = someFunction($row['blah']); 
    } 
    } 

    return $array; 
} 

Có vẻ ổn với tôi, nhưng nó thiếu nhiều hàng. Cuối cùng tôi nhận ra rằng lệnh xử lý đã được thay đổi (được thực hiện với param khác nhau), có nghĩa là lệnh gọi trong vòng lặp while sẽ chỉ làm việc một lần, sau đó hàm sẽ tự động gọi lại và tập kết quả được thay đổi.

Vì vậy, tôi tự hỏi cách tốt nhất để sử dụng các câu lệnh chuẩn bị PDO theo cách đệ quy.

Một cách có thể là sử dụng fetchAll(), nhưng nó nói trong hướng dẫn có chi phí đáng kể. Toàn bộ vấn đề này là làm cho nó hiệu quả hơn.

Điều khác mà tôi có thể làm là không sử dụng lại tay cầm tĩnh và thay vào đó hãy tạo một cái mới mỗi lần. Tôi tin rằng kể từ khi chuỗi truy vấn là như nhau, trong nội bộ trình điều khiển MySQL sẽ được sử dụng một tuyên bố chuẩn bị anyway, do đó, chỉ là chi phí nhỏ của việc tạo ra một xử lý mới trên mỗi cuộc gọi đệ quy. Cá nhân tôi nghĩ rằng đánh bại quan điểm.

Hoặc có cách nào để viết lại điều này không?

+0

tôi chỉ làm một số (không phải siêu khoa học) thử nghiệm mã chức năng đệ quy rất giống nhau của tôi và có conc luded rằng cho các mục đích của tôi, báo cáo chuẩn bị chậm hơn tổng thể. Điểm chuẩn bị tuyên bố là gì nếu bạn phải chuẩn bị lại trước mỗi lần sử dụng? Chắc chắn là tôi đang thiếu gì đó. –

Trả lời

2

Bạn không thể lồng các chốt điều khiển câu lệnh: bạn cần đóng chốt điều khiển mở trước đó trước khi mở một chốt khác trong một phiên duy nhất.

Thực tế, PDO sẽ thực hiện nếu tự động khi bạn phát hành một chuẩn bị mới.

Khi bạn gọi hàm đệ quy:

  • Tay cầm ban đầu được phân bổ (1)
  • Kỷ lục đầu tiên là lấy của (1)
  • Các hàm được gọi đệ quy. Giá trị của (1) nằm trong ngăn xếp đệ quy.
  • Tay cầm mới được phân bổ (2), hủy bỏ hiệu lực (1)
  • Kỷ lục đầu tiên là lấy của (2)
  • Chức năng trả
  • Bạn cố gắng để lấy các bản ghi tiếp theo của (1) và thất bại vì nó không hợp lệ

Vì vậy, nói rằng, MySQL không hỗ trợ đệ quy về phía của nó và điều đó có nghĩa là bạn sẽ phải làm điều đó ở bên PHP, sử dụng fetchAll.

+0

Bạn đang đề cập đến xử lý nào? Bạn có thể có nhiều xử lý câu lệnh đã chuẩn bị trong một phiên duy nhất (tôi tin rằng có giới hạn khoảng 500 câu lệnh được chuẩn bị phía máy chủ mỗi phiên và 'max_prepared_stmt_count' tổng số câu lệnh, nhưng điều này không áp dụng cho các câu lệnh đã tạo được bằng thư viện phía máy khách). Kết quả không được xử lý riêng. – outis

0

Vấn đề thực tế là $handle là tĩnh. Các biến tĩnh có vấn đề cho đệ quy khi trạng thái cần được bảo tồn qua một cuộc gọi đệ quy, không chỉ cho các câu lệnh đã chuẩn bị. Trong trường hợp này, cuộc gọi đệ quy thực hiện truy vấn mới, loại bỏ trạng thái trước đó. PDO::fetchAll thực sự là lựa chọn duy nhất nếu bạn muốn có một truy vấn được chuẩn bị duy nhất.

Tùy thuộc vào tuyên bố là gì, bạn có khả năng viết lại nó để trả lại tất cả kết quả cùng một lúc, sau đó xây dựng cây.

+0

@outis: '$ handle' là tĩnh vì một lý do: chỉ có thể có một câu lệnh hoạt động trong một phiên. – Quassnoi

+0

@Quassnoi: Tôi nhận ra có một lý do cho '$ handle' là tĩnh. Tuy nhiên, các biến tĩnh đơn giản sẽ không hoạt động theo cách mà Rob muốn chúng trong các cuộc gọi đệ quy. – outis

+0

@Quassnoi: và ý của bạn là "hoạt động" là gì? Có thể có nhiều câu lệnh được chuẩn bị trong một phiên duy nhất, mặc dù mỗi câu lệnh sẽ chỉ có một tập kết quả duy nhất. – outis

0

Nếu bạn sử dụng cùng một biến, (vì pdo bindValue) mỗi giá trị thời gian giống nhau với giá trị đầu tiên. Vì vậy, đây sẽ thất bại:

foreach ($bind_params as $key => $value) { 
    $stmt->bindParam(":$key", $value); 
} 

kết quả:

$key[0] = $value[0]; 
$key[1] = $value[0]; 
$key[2] = $value[0]; 
$key[3] = $value[0]; 

Vì vậy, bạn muốn làm lừa xấu xí, sau đó:

 $i = 0; 
     foreach ($bind_params as $key => $value) { 
      $i++; 
      $$i = $value; 
      $stmt->bindParam(":$key", $$i); 
     } 

kết quả:

$key[0] = $value[0]; 
$key[1] = $value[1]; 
$key[2] = $value[2]; 
$key[3] = $value[3]; 
Các vấn đề liên quan