czwartek, 30 maja 2019

PHP dziwne przypadki: rzutowanie tablicy na obiekt

Przypisywanie pustego stringa jako klucz elementu


$myArray = ['' => 2];
$result  = $myArray[(string) null];
var_dump($result); // int(2)

Zwr贸膰 uwag臋 偶e null rzutowany na stringa daje w艂a艣nie pusty 艂a艅cuch znak贸w.

Co si臋 zatem stanie gdy taki pusty klucz mia艂by zosta膰 zamieniony na pole obiektu po rzutowaniu tablicy na obiekt?

$myObject = (object) ['' => 2];
var_dump($myObject);

Operacja ta nie wygenerowa艂a na 偶adnego b艂臋du a tre艣膰 var_dump'a jest do przewidzenia 

object(stdClass)#2 (1) { [""]=> int(2) }

Mamy pole do kt贸rego nie mo偶emy si臋 odwo艂a膰, kiepsko. 
Potrafi臋 wyobrazi膰 sobie use case'y gdzie deklaracja pustego klucza tablicy jest po偶膮dana, ale w czasie rzutowania takiego tworu na obiekt, moim zdaniem powinien zosta膰 wyrzucany jaki艣 error mode gdy偶 wtedy pozyskanie tej warto艣ci jest utrudnione.

W akcie desperacji postanowi艂em zaryzykowa膰 i odwo艂a膰 si臋 do obiektu jakbym mia艂 do czynienia z tablic膮!

$myObject[''];

Jednak szybko zosta艂em przywr贸cony do porz膮dku czytaj膮c wy艣wietlony komunikat

Fatal error: Uncaught Error: Cannot use object of type stdClass as array

M贸g艂bym posun膮膰 si臋 jeszcze dalej wprowadzaj膮c do akcji foreach'a - skuteczne ale paskudne.

foreach ($myObject as $field => $value) {
   echo $value;
}
// 2

Wiecie, to nie jest tylko problem pustego klucza ale te偶 kluczy numerycznych. Potrzebna by nam by艂a jaka艣 nowa sk艂adnia dzi臋ki kt贸rej okie艂znaliby艣my. Gdyby tylko co艣 takiego istnia艂o...

https://wiki.php.net/rfc/convert_numeric_keys_in_object_array_casts

Jak wida膰 funkcjonalno艣膰 dost臋pna od wersji 7.2 - sp贸jrzmy na to


echo $myObject->{''}; // 2

Uda艂o si臋! Dr偶yjcie tablice numeryczne i pustokluczowe rzutowane na obiekty! Teraz ju偶 偶adna warto艣膰 si臋 nie skryje przed developerem. Mamy dost臋p do wszystkiego.

Na koniec, rzutem na ta艣m臋 stworzy艂em takiego potworka

$myObject = (object) [' ' => 2, '  ' => 3, '        ' => 4];

echo $myObject->{'        '}; // 4

I wiecie co? 艣miga a偶 mi艂o.


Ewolucja PHP 5 - w skr贸cie


  • 5.0 (2004)

    • nowy model OOP,
    • brak kompatybilno艣ci wstecznej z wersj膮 4,

  • 5.1 (2005)

    • PDO extension dodane jako domy艣lne,
    • dodano funkcje do operowania na tablicach: 
      • array_diff_key()
      • array_diff_ukey()
      • array_intersect_key() and 
      • array_intersect_ukey(),

  • 5.2 (2006)

    • wprowadzono klasy DateTime i DateTimeZone,
    • nowy error mode E_RECOVERABLE_ERROR,
    • JSON extension dodane jako domy艣lne, 
    • Input filtering extension dodane jako domy艣lne,

  • 5.3 (2009)

    • namespace czyli przestrzenie nazw, __autoload(),
    • Late State Binding,
    • funkcje anonimowe i obiekty Closure,
    • Short Tenary Operator ?:,
    • NOWDOC,
    • HEREDOC umo偶liwia inicjalizowanie statycznych zmiennych, p贸l klasy oraz sta艂ych klasy, 
    • sta艂e mog膮 by膰 deklarowane poza klasami za pomoc膮 s艂owa kluczowego const,
    • dynamiczny dost臋p do metod statycznych,
    • nowe metody magiczne __callStatic(), __invoke(),
    • nowy error mode E_STRICT raportuj膮cy o funkcjonalno艣ciach kt贸re w przysz艂ych wersjach mog膮 by膰 oznaczone jako deprecated,
    • SPL'owa klasa DirectoryIterator od teraz implementuje ArrayAccess,
    • dwie nowe funkcje do operowania na tablicach: array_replace() & array_replace_recursive(),

  • 5.4 (2012)

    • skr贸cona sk艂adnia tablic. Zamiast deklarowania jej w taki spos贸b array() mo偶na zamiennie stosowa膰 [],
    • Traits,
    • Function Array Dereferencing. Umo偶liwia odwo艂anie si臋 do indeks贸w tablicy bezpo艣rednio na funkcji/metodzie zwracaj膮cej array np. foo()[0],
    • echo tag <?= domy艣lnie zawsze dost臋pny, chyba 偶e zadeklarujesz inaczej w php.ini short_open_tag,
    • Natychmiastowe odwo艂ywanie si臋 do metod i p贸l instancjonowanej klasy umieszczaj膮c ten proces w nawiasach np. (new MyExampleClass())->getName(),
    • mo偶liwo艣膰 wykorzystania $this w Closure
    • stosowanie Type Hint w callable
    • sk艂adnia Class::{expr}(),
    • blok switch jako argument mo偶e przyjmowa膰 array,

  • 5.5 (2013)

    • generatory,
    • s艂owo kluczowe finally dla bloku try catch,
    • Literal Dereferencing czyli odwo艂ywanie si臋 do poszczeg贸lnych indeks贸w tablic i string贸w w nast臋puj膮cy spos贸b: ['a','b','c'][0] albo "hello"[1],
    • password_hash() i password_verify() zast膮pi艂y wcze艣niej wykorzystywan膮 do tego celu funkcje crypt(). Wykorzystuje domy艣lnie algorytm bcrypt,
    • konstrukt j臋zykowy empty() mo偶na wykorzystywa膰 teraz na funkcjach, odwo艂aniach do metod obiekt贸w czy wyra偶eniach, 
    • pozyskiwanie pe艂nej nazwy importowanej klasy (fully qualified class name) czyli takiej zawieraj膮cej przestrze艅 nazw za po艣rednictwem s艂owa kluczowego class poprzedzonego operatorem :: (Paamayim Nekudotayim) w taki spos贸b MyImportedClass::class. Mo偶na to r贸wnie偶 stosowa膰 na importowanych interfejsach,
    • korzystanie z konstruktu list() jako aktualnie iterowanego elementu tablicy (b臋d膮cego tablic膮) zamiast klasycznego $key => $item np.            foreach($array as list($item1, $item2)) {...} w przypadku korzystania z tablic wielowymiarowych,
    • deklarowany array w foreach po kt贸rym si臋 iterujemy i ustawiamy referencje na kluczu czy warto艣ci nie wyrzuca ju偶 b艂臋du "Cannot create references to elements of a temporary array expression". Np. foreach([1, 2, 3, 4] as $key => &$value) {...},

  • 5.6 (2014)

    • wprowadzono mo偶liwo艣膰 deklarowania wyra偶e艅 skalarnych w constach,
    • zmniejszenie ilo艣ci pami臋ci (2-3 krotnie) tablicy POST,
    • Variadic Functions. Uproszczono korzystanie z nieokre艣lonej ilo艣ci parametr贸w w funkcjach, poprzez wprowadzenie do sk艂adni Variadic Type Hint na przyk艂ad ...$numbers, jest to ciekawa alternatywa dla func_get_params() - Variadic na polski to 'ze zmienn膮 liczb膮 argument贸w',
    • osadzanie funkcji i sta艂ych (const) w namespace'ach i importowanie ich w innych przestrzeniach nazw za pomoc膮 s艂owa kluczowego use dok艂adnie tak jak robi si臋 to z klasami, 
    • nowe operatory arytmetyczne ** oraz =**
     殴r贸d艂a