2013-07-21 36 views
5

Tôi hiện đang sử dụng phương pháp sau đây băm resource s để tra cứu:Sử dụng tài nguyên như chỉ số mảng trong PHP

$foo = socket_create(...); 
$bar = socket_create(...); 

$map[(int)$foo] = 'foo'; 
$map[(int)$bar] = 'bar'; 

echo $map[(int)$foo]; // "foo" 

integer đúc lựa chọn tốt nhất cho việc này? Nếu không, phương pháp băm nào khác sẽ tốt hơn hoặc hiệu quả hơn? Những tra cứu sẽ được thực hiện trong một bộ sưu tập vào hàng trăm, nhiều lần mỗi giây trong một vòng lặp chặt chẽ (socket polling), vì vậy tôi đã loại trừ các giải pháp dựa trên lặp lại.

Edit:

Để giải thích hoàn cảnh của tôi tốt hơn một chút, các socket_select() hàm lấy mảng tài nguyên ổ cắm bằng cách tham khảo và sửa đổi chúng như rằng sau khi gọi hàm, họ sẽ chỉ chứa các nguồn lực đó đã thay đổi (ví dụ sẵn sàng để được đọc từ). Tôi sử dụng một lớp Socket như là một wrapper cho nguồn tài nguyên ổ cắm, để làm cho mã của tôi trừu tượng hơn và kiểm chứng:

$socketObject = new Socket($socketResource); 

Một lớp học của tôi giữ một danh sách của tất cả các nguồn tài nguyên ổ cắm cần được thăm dò ý kiến ​​mỗi khi chúng ta gọi là socket_select():

$reads = [$socketResource1, $socketResource2, ...]; 
socket_select($reads, null, null, 0); 

Sau khi cuộc gọi đến socket_select(), tôi biết đó là ổ cắm nguồn đã thay đổi, nhưng để làm bất cứ điều gì có ý nghĩa trong mã của tôi, tôi cần phải biết ổ cắm đối tượng những nguồn lực tương ứng với . Vì vậy, tôi cần một số cách để lập bản đồ tài nguyên ổ cắm vào các đối tượng của họ:

foreach ($reads as $socketResource) { 
    // Which socket object does $socketResource correspond to here? 
    // Currently, I use a solution like this: 
    $socketObject = $this->map[(int)$socketResource]; 
    // Unfortunately, this behavior isn't guaranteed, so it isn't reliable... 
} 

Trả lời

6

Hành vi được quan sát khi casting resources to integer không xác định (xem Lưu ý thận trọng ở cuối trang). Vì vậy, ngay cả khi điều này works now and reliably did for a long time, bạn phải nhận thức được rằng nó không có gì bạn có thể dựa vào không thay đổi mà không cần thông báo.

Chỉnh sửa sau khi làm rõ:

Thay vì đặt các tài nguyên như chìa khóa, sử dụng hai mảng. Một ánh xạ các hash của các đối tượng Socket của bạn đến các đối tượng thực tế. Và một ánh xạ khác băm cùng một tài nguyên. Sau đó chuyển mảng sau đến socket_select. Dưới tiền đề rằng chức năng sẽ không thay đổi các phím mảng, sau đó bạn có thể lặp mảng và sử dụng chìa khóa để tìm kiếm Socket trong thời gian O (1):

$r1 = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); 
$r2 = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); 

$s1 = new Socket($foo); 
$s2 = new Socket($bar); 

$socketMap = array(
    spl_object_hash($s1) => $s1, 
    spl_object_hash($s2) => $s2 
); 

$reads = array(
    spl_object_hash($s1) => $r1, 
    spl_object_hash($s2) => $r2 
); 

socket_select($reads, null, null, 0); 

foreach (array_keys($reads) as $hash) { 
    $socketObject = $socketMap[$hash]; 
} 
+0

Tôi thực sự không bao giờ nghĩ đến việc truyền mảng kết hợp tới 'socket_select()'; nó có thể hoạt động. Tôi sẽ phải kiểm tra điều này sau. Tôi sẽ theo dõi và cho bạn biết. Cảm ơn! – FtDRbwLXw6

+2

Tôi vừa thử nghiệm điều này, và các phím được bảo tồn thông qua cuộc gọi 'socket_select()', và mọi thứ đều hoạt động tốt. Tôi đã chấp nhận câu trả lời của bạn và bắt đầu một tiền thưởng (24 giờ trước khi tôi có thể trao giải) bởi vì tôi thực sự đánh giá cao nỗ lực và sự giúp đỡ của bạn. Cảm ơn bạn! – FtDRbwLXw6

+0

@drrcknlsn yay! Happy nó hoạt động. Và đánh giá cao tiền thưởng! – Gordon

1

tôi sử dụng chức năng này với multi_curl, rất hiệu quả để phân loại để đảm bảo văn bản không xếp hàng một cách ngẫu nhiên:

function get_resource_id($resource) { 
    if (!is_resource($resource)) 
     return false; 

    return array_pop(explode('#', (string)$resource)); 
} 
0

Tôi đề nghị bạn thực hiện một đối tượng bộ sưu tập thay vì $map biến, ví dụ:

class ResourceCollection implements ArrayAccess { 

    private $map = array(); 

    /** 
    * returns index of element or FALSE if not existent 
    */ 
    protected function getIndex($offset){ 
    if(is_resource($offset)){ 
     $index = array_search($offset, $this->map); 
    } 
    else // you can add more tests if you need 
     if(isset($this->map[$offset])) 
     $index = $offset; 
     else 
     $index = false; 
    return $index; 
    } 

    /** 
    * required by ArrayAccess interface 
    */ 
    public function offsetExists($offset){ 
    return ($this->getIndex($offset) === false)? false : true; 
    } 



    /** 
    * required by ArrayAccess interface 
    */ 
    public function offsetGet($offset){ 
    $index = $this->getIndex($offset); 
    if($index === false) 
     throw new ... // or handle error of non-existent element 
    return $this->map[$index]; 
    } 

// etc., implement ArrayAccess interface, Iterator and anything you want 
} 

Mặc dù tôi đã không kiểm tra nó, điều này sẽ cho phép bạn truy cập vào các đối tượng như thể nó là một mảng và tôi hy vọng rằng cách này (không có tài liệu cho việc này) các nguồn lực có thể được sử dụng như các chỉ số mảng .

+0

Cảm ơn bạn đã trả lời, nhưng 'array_search()' sử dụng lặp lại, vì vậy đây là một giải pháp O (n), nơi mà tôi đang tìm kiếm một giải pháp O (1) thay thế. – FtDRbwLXw6

+0

Bạn có thể kết hợp cả hai giải pháp, do đó bạn sẽ không phải suy nghĩ về hai biến :-) – Voitcus

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