2013-07-21 12 views
5

Obecnie używam następujący sposób mieszania resource s do poszukiwania:Korzystanie z zasobów jako indeksów tablicy w PHP

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

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

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

Czy integer odlewania najlepsze rozwiązanie dla tego? Jeśli nie, to jaka inna metoda haszowania byłaby lepsza lub bardziej wydajna? Te wyszukiwania będą wykonywane w zbiorze do setek, wiele razy na sekundę w ciasnej pętli (odpytywanie gniazd), więc wykluczyłem już rozwiązania oparte na iteracji.

Edit:

Aby wyjaśnić moją sytuację trochę lepiej, funkcja socket_select() bierze tablic zasobów gniazd przez odniesienie i modyfikuje je tak, że po wywołaniu funkcji, będą one zawierać tylko te środki, które zostały zmienione (np. gotowy do odczytania). Używam klasy Socket jako wrapper dla zasobów gniazd, aby mój kod bardziej abstrakcyjne i sprawdzalne:

$socketObject = new Socket($socketResource); 

Innym z moich klas przechowuje listę wszystkich zasobów gniazdowych, które muszą być odpytywany za każdym razem nazywamy socket_select():

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

Po wywołaniu socket_select(), wiem, które gniazdo zasoby uległy zmianie, ale do niczego sensownego w moim kodu, muszę wiedzieć, jakie gniazdo obiektów środki te odpowiadają . Zatem muszę jakiś sposób mapowania zasobów gniazd do ich obiektów:

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... 
} 

Odpowiedz

6

Obserwowane zachowanie, gdy casting resources to integer jest niezdefiniowane (patrz uwaga Uwaga na dole strony). Więc nawet jeśli to works now and reliably did for a long time, musisz mieć świadomość, że to nic, na czym możesz polegać, aby nie zmieniać się bez powiadomienia.

Edit po wyjaśnień:

Zamiast umieszczać zasobu jako klucz, użyj dwóch tablic. Jeden mapuje hasze obiektów Socket na rzeczywiste obiekty. I kolejne mapowanie tych samych skrótów do zasobu. Następnie przeprowadź tę ostatnią tablicę do socket_select. W założeniu, że funkcja nie zmieni kluczy tablicy, można następnie iterację tablicy i użyj klucza, aby zajrzeć do gniazda w czasie 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

Właściwie nigdy nie myślałem o przekazaniu tablicy asocjacyjnej do 'socket_select()'; może po prostu działać. Będę musiał to przetestować później. Pójdę za tobą i dam ci znać. Dzięki! – FtDRbwLXw6

+2

Właśnie przetestowałem to, a klucze są zachowywane przez wywołanie 'socket_select()', a wszystko działa świetnie. Przyjąłem twoją odpowiedź i rozpocząłem nagrodę (24 godziny przed przyznaniem nagrody), ponieważ naprawdę doceniam twój wysiłek i pomoc. Dziękuję Ci! – FtDRbwLXw6

+0

@drrcknlsn yay! Cieszę się, że działa. I doceń nagrodę! – Gordon

1

używam tej funkcji z multi_curl, bardzo skuteczny do sortowania, aby upewnić się, że tekst nie kolejce losowo:

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

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

proponuję Ci zrobić obiektu zbiórki zamiast $map zmienna, np.

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 
} 

Mimo, że nie byli to przetestowane, powinno to pozwolić na dostęp do obiektu, tak jakby były tablicą i mam nadzieję, że w ten sposób (nie ma dokumentacji na ten temat) zasoby mogą być wykorzystane jako wskaźniki tablicy .

+0

Dziękuję za odpowiedź, ale 'array_search()' używa iteracji, więc jest to rozwiązanie O (n), w którym szukałem zamiast tego rozwiązania O (1). – FtDRbwLXw6

+0

Możesz łączyć oba rozwiązania, więc nie będziesz musiał myśleć o dwóch zmiennych :-) – Voitcus

Powiązane problemy