Różnica między "negowaniem" zmiennej a skorzystaniem z isset()

0

Przykładowy kod:

  public static function getInstance() {
    if (!self::$instance) { 
    [...]

To jest znaleziony gdzieś w necie przykładowy fragment implementacji singletona w PHP.
Pytanie jest takie - czemu ktoś dał !self zamiast !isset()?
Zamiana na isset() nic nie zmienia, całość działa tak samo jak z negującym wykrzyknikiem.
Czym się te dwa zapisy różnią? Który jest lepszy? Której wersji lepiej się trzymać?

Wszelkie uwagi i komentarze mile widziane ;)

1

Podobne się rozważa w JS (podwójne negacje)

jeśli rozumiem chodzi o to, ze jest burdel z kompatybilnością wszelkich możliwych typów z FALSE a zwłaszcza TRUE.
Twórcy języka / programiści już sami nie są pewni, co jest co, i używają j/w, po takich negacjach mają zagwarantowany typ boolean (coś co javowcy/sihaszwcy mają zapewnione z mocy ustawy)

1

Znalazłem w necie jeszcze takie coś, co może rzucić nowe światło na sprawę:

if we use directly !$variableName and the $variableName is not defined before that check, then a Undefined variable warning will be generated by php. If we use isset, then if the variable is defined before, then it is set the isset will return true, if not defined then isset will return false, and hence no Undefined Variable or index warning will be generated.

https://stackoverflow.com/questions/18763705/why-would-a-person-want-to-use-isset-over-just-variablename

1

Jeśli rzeczywiście nie ma jakiejś różnicy to użyłbym isset(); W tym przypadku to może być jednak pole tej klasy o dowolnym przeznaczeniu ... i co wtedy? Nie rozumiem tego. Może brkuje szerszego kontekstu?
Ogólnie nie lubię takich składniowych wygibasów. Na pierwszy rzut oka nie mam pojęcia o co chodzi i zmusza mnie to do nadmiernego wytężania umysłu podczas czytania kodu - w tym przypadku nawet to nic nie daje bo nadal nie mam pojęcia o co chodzi.
Zresztą w PHP8 ten kod i tak jest do du... więc nie ma co dalej drążyć :-)

Jeśli już faktycznie muszę użyć jakiejś sztuczki tego typu to odpowiednio komentuję ten fragment albo ubieram go w funkcję z nazwą, która nie wzbudza wątpliwości i wrzucam do biblioteki p.t. "Tools" i po kłopocie.

<?php

class Dupa{
  
  public static $instance = true ;
  public static function getInstance() {
    if (!self::$instance) {
      echo "getDupa?" ;
    } else {
      echo "Nie getDupa?" ;
    }
  }
  
}

Dupa::getInstance();
$aDupa = new Dupa();
$aDupa->getInstance();
0

Zresztą w PHP8 ten kod i tak jest do du...

@katakrowa: możesz rozwinąć ta myśl? Co wersja 8 ma do tego?

1
cerrato napisał(a):

Zresztą w PHP8 ten kod i tak jest do du...

@katakrowa: możesz rozwinąć ta myśl? Co wersja 8 ma do tego?

screenshot-20220816095115.png

0

OK, teraz rozumiem co miałeś na myśli.
Tak - odwołanie się do nieistniejącego pola static rzuci errora.
Ale w takim razie ponawiam pytanie - czy (i dlaczego) lepiej jest dawać !$dupa albo isset($dupa)?

3
cerrato napisał(a):

OK, teraz rozumiem co miałeś na myśli.
Tak - odwołanie się do nieistniejącego pola static rzuci errora.
Ale w takim razie ponawiam pytanie - czy (i dlaczego) lepiej jest dawać !$dupa albo isset($dupa)?

Ja osobiście nie używałbym żadnego z nich, z kilku powodów.

  • isset() po prostu robi za dużo, zbyt dużo jest rzeczy które mogą wpłynąć na jej wynik, przez w gruncie rzeczy to czy isset() zwróci false czy true mówi nam niewiele, nie specjalnie jest to użyteczne, isset() bierze pod uwagę pola obiektów, atrybuty klas, klucze w array, same zmienne, atrybutu atrybutów też, oraz bierze pod uwagę samą wartość, np null. Dodatkowo isset() wycisza wszystkie "nieistniejące" rzeczy, przez co jak napiszesz tam literówkę, to nie dostaniesz żadnego errora.
  • Co do if (!self::$instance), tego również nie używam, dlatego że taki zapis najpierw castuje zmienną na bool (co już w PHP jest powalone, za głowę się można złapać jakie są zasady castowania wartości na bool - np string "0" jest castowany na false. WTF!), a potem go odwraca. Także dla mnie to niej jest w ogóle opcja.

Ja sugeruję w ogóle w PHP nie robić takich rzeczy jak "sprawdzanie, czy coś istnieje w PHP", chyba że nie masz innego wyjścia.

A jeśli już musisz, to użyłbym jednego z tych zapisów:

  • self::$instance === null - koniecznie ===, nie ==
  • self::$instance === false
  • array_key_exists($array, 'key')
  • property_exists($object, 'property') - to jest dobre, bo nawet jeśli property ma null, to dostaniemy true (nie tak jak isset()).

Jeśli chcesz napisać singletona, to ja raczej użyłbym self::$instance === null. Ale singletona też bym raczej nie używał :D

PS: @cerrato Co do błędów w PHP, to jest trochę bardziej posrane, niż w innych językach. Mamy:

  • Parse error - aplikacja includowany/requireowany/uruchamiany plik nawet się nie włączy
  • Fatal error, kiedy się stanie proces PHP się po prostu ubija bez wysłania response'a. Nie da się tego niczym złapać, ani zareagować na to. Fatal to już koniec.
  • Exception - to jest jedyna normalna rzecz
  • Error, warning, notice - nie różnią się niczym od siebie - to jest taki dziwny mechanizm informowania o błędach, ale nie jest rzetelny, tzn ustawiana jest flaga, którą różne servery ogarniają inaczej (np rethrowują exception, printują błąd w HTML'u lub plaintexcie), i innych rzeczach
  • Niektóre błędy są po prostu wyciszane
  • Niektóre funkcje zwracają 0, false, -1 lub null jako "sygnał" o błędzie
  • Niektóre funkcje się "udają", ale błąd trzeba odczytać inną funkcją, np preg_last_error(), json_last_error(), mysql_error(), curl_error().

Także, z tymi błędami to nie jest takie czarno białe, a dodatkowo - PHP w różny sposób, różną "siłą" reaguje na różne błędy, np:

PHP hehe:

  • Użycie nieistniejącego property, np $user->idd - warning
  • Użycie nieistniejącego consta, np USER_IDD - notice
  • Użycie propery na czymś, co nie jest obiektem, np ([1,2,3])->property - notice
  • Użycie nieistniejącej zmiennej - notice
  • Iterowanie po czymś co nie jest arrayem, np po integer - warning

PHP not hehe:

  • Użycie niestniejącego statica - Fatal error?
  • Użycie stringa jako call funkcji - parse error
  • Użycie niestniejącej funkcji - fatal error
  • Użycie isset() (lub echo, list(), die()i innych "konstruktów") jako funkcji - parse error

Wyjątków nie rzuca praktycznie nic w PHP, może oprócz najnowszych feature'ów w PHP.

0

@Riddle: dzięki za fajną i wyczerpującą odpowiedź.

Skoro zamiast isset() proponujesz (co zresztą ma sens) zapis ===null to co masz do powiedzenia na w kwestii zwalniania zmiennych - czy lepiej dać unset() czy $dupa = null? Z tego co widzę, w necie zdania są podzielone, ja bym się skłaniał raczej w kierunku unset(), ale może Ty proponujesz inną opcję?

https://www.geeksforgeeks.org/which-one-is-better-unset-or-var-null-to-free-memory-in-php/
https://stackoverflow.com/questions/13667137/the-difference-between-unset-and-null

0
cerrato napisał(a):

@Riddle: dzięki za fajną i wyczerpującą odpowiedź.

Skoro zamiast isset() proponujesz (co zresztą ma sens) zapis ===null to co masz do powiedzenia na w kwestii zwalniania zmiennych - czy lepiej dać unset() czy $dupa = null? Z tego co widzę, w necie zdania są podzielone, ja bym się skłaniał raczej w kierunku unset(), ale może Ty proponujesz inną opcję?

https://www.geeksforgeeks.org/which-one-is-better-unset-or-var-null-to-free-memory-in-php/
https://stackoverflow.com/questions/13667137/the-difference-between-unset-and-null

Ja w swoich programach nigdy nie zwalniam zmiennych, więc unset(), nigdy nie używam. Nie mam w swoich programach kodu który sprawdza istnienie jakiejś zmiennej bądź property, jeśli w jakimś kodzie używam zmiennej, to dbam o to, by w tym momencie była zdefiniowana (czyli muszę swoją dyscypliną pilnować to co robi za mnie kompilator jak np w Javie lub c#).

Jeśli zaś chodzi o ustalenie $var = null;, to nie widzę w tym specjalnego sensu, jako jakąś idea "usuwania zmiennych". Jeśli już coś, to może jako forma czyszczenia stanu w kolekcji lub cache'u, ale raczej nie.

Nie martwię się o performance wynikający z ze zmiennych, mam małe funkcje więc u mnie zmienne żyją raczej krótko więc i tak będą wyczyszczone po wyjściu z funkcji.

1
Riddle napisał(a):
  • isset() po prostu robi za dużo, zbyt dużo jest rzeczy które mogą wpłynąć na jej wynik, bym raczej nie używał :D

moiżesz rozwinąć? w manualu https://www.php.net/manual/en/function.isset.php jest

Determine if a variable is considered set, this means if a variable is declared and is different than null.

3
Miang napisał(a):
Riddle napisał(a):
  • isset() po prostu robi za dużo, zbyt dużo jest rzeczy które mogą wpłynąć na jej wynik, bym raczej nie używał :D

moiżesz rozwinąć? w manualu https://www.php.net/manual/en/function.isset.php jest

Determine if a variable is considered set, this means if a variable is declared and is different than null.

No tak, tylko tutaj jest napisane if a variable is declared, co nie jest do końca prawdą, bo isset() sprawdza istnienie: zmiennych, kluczy w array, pół w obiektach i atrybutów w klasach.

Poza tym isset() się zachowuje inaczej, jak sprawdzamy nieistniejące dziecko w istniejącym rodzicu, vs. dziecko w nieistniejącym rodzicu. Dla mnie isset() jest całkowicie nierzetelnym rozwiązaniem.

Swoją drogą dokumentacja PHP jest najgroszą dokumentacją języka programowania jaką widziałem.

Nie wspominając o tym, że taki kod:

class TheClass {
    public static $value = 2;
}

isset(${TheClass::$value['value']->well}['next']->$mising[CONSTANT])

po prostu sobie zwraca false, i nie rzuca żadnym błędem.

1

Nie mam w swoich programach kodu który sprawdza istnienie jakiejś zmiennej bądź property, jeśli w jakimś kodzie używam zmiennej, to dbam o to, by w tym momencie była zdefiniowana (czyli muszę swoją dyscypliną pilnować to co robi za mnie kompilator jak np w Javie lub c#).

OK. Taki przykład na szybko (może nie idealny, ale pokazuje sytuację, w której isset() może się przydać):

  • tworzymy tablicę asocjacyjną $pracownicy
  • dodajemy do niej pozycje - w stylu $pracownicy['michal'] = 'kierownik'
  • potem przychodzi zlecenie - zwolnić typa o imieniu Michał
  • dajesz if (isset($pracownicy['michal'])) {zwolnic($pracownicy['michal']);}

Jak napisałem - to taki przykład na szybko, można to zrobić inaczej/ładniej. Ale chodzi o to, że może się pojawić sytuacja, w której jednak pojawi się potrzeba sprawdzenia statusu jakiejś zmiennej. OK, jeśli to zmienne, które wprowadzasz ręcznie w kodzie to można się pilnować. Ale Michała mógł dodać user jakimś formularzem (albo został zassany z bazy pracowników) i przez to nie masz możliwości wpłynięcia na to, co się pojawi w danym miejscu jako zmienna. OK, można to obejść chociażby korzystając z https://www.php.net/manual/en/function.array-key-exists.php - albo w 100 innych sposobów, mi chodziło jedynie o pokazanie, że czasem takie sprawdzenie zmiennej może mieć sens/może być potrzebne.

1
cerrato napisał(a):

Nie mam w swoich programach kodu który sprawdza istnienie jakiejś zmiennej bądź property, jeśli w jakimś kodzie używam zmiennej, to dbam o to, by w tym momencie była zdefiniowana (czyli muszę swoją dyscypliną pilnować to co robi za mnie kompilator jak np w Javie lub c#).

OK. Taki przykład na szybko (może nie idealny, ale pokazuje sytuację, w której isset() może się przydać):

  • tworzymy tablicę asocjacyjną $pracownicy
  • dodajemy do niej pozycje - w stylu $pracownicy['michal'] = 'kierownik'
  • potem przychodzi zlecenie - zwolnić typa o imieniu Michał
  • dajesz if (isset($pracownicy['michal'])) {zwolnic($pracownicy['michal']);}

Ja bym to napisał tak

<?php
if (array_key_exists($pracownicy, 'michal')) {
  zwolnij($pracownicy['michal']);
} else {
  // obsłuż brak takiego pracownika, np wyjątek lub inna odpowiedź.
}
cerrato napisał(a):

Jak napisałem - to taki przykład na szybko, można to zrobić inaczej/ładniej. Ale chodzi o to, że może się pojawić sytuacja, w której jednak pojawi się potrzeba sprawdzenia statusu jakiejś zmiennej. OK, jeśli to zmienne, które wprowadzasz ręcznie w kodzie to można się pilnować. Ale Michała mógł dodać user jakimś formularzem (albo został zassany z bazy pracowników) i przez to nie masz możliwości wpłynięcia na to, co się pojawi w danym miejscu jako zmienna. OK, można to obejść chociażby korzystając z https://www.php.net/manual/en/function.array-key-exists.php - albo w 100 innych sposobów, mi chodziło jedynie o pokazanie, że czasem takie sprawdzenie zmiennej może mieć sens/może być potrzebne.

W mojej opinii raczej nie ma, podchodzi mi to pod jakiś taki metaprograming. Owszem, zachodzi potrzeba: sprawdzić czy plik istnieje, czy jest klucz w JSON'ie, sprawdzić czy jakiś user istnieje w bazie, czy jakiaś wartośc przyszła w requeście, ale to zawsze da się sprawdzić standardowymi rozwiązaniami, właśnie np jak array_key_exists(), in_array() lub innymi podobnymi. To czy zmienna istnieje, czy nie, moim zdaniem to antywzorzec. Prowadzi tylko do bólu i cierpienia.

0

Nie ma roznicy jako takiej, najlepiej stosowac isset()

1

Najlepiej to sobie zatypować

protected static ?self $instance = null;

i wtedy wszystkie wątpliwości znikają ;)

// bez większej różnicy; isset w którejś wersji był nieznacznie szybszy (mikrooptymalizacja)
// chyba że nie zdefiniujesz domyślnego nulla dla pola, wtedy tylko isset
isset(self::$instance); 
self::$instance !== null;
1
Riddle napisał(a):

Poza tym isset() się zachowuje inaczej, jak sprawdzamy nieistniejące dziecko w istniejącym rodzicu, vs. dziecko w nieistniejącym rodzicu. Dla mnie isset() jest całkowicie nierzetelnym rozwiązaniem.

Możesz podać jakiś przykład kodu, w którym isset() nie działa w sposób jaki się oczekuje lub jak to piszesz działa "nierzetelnie" lub ewentualnie wskazać na czym ta nierzetelność polega?

2

@Riddle: to raczej negowanie zmiennej w PHP czasami daje rezultaty z kosmosu (tak, wiem, że tak się php zachowuje ale pamiętam ile czasu szukałem błędu przez właśnie takie negowanie).

@chomikowski - są pewne różnice - zerknij na to:

<?php
$varA = 0;

echo ($varA) ? 'true<br />' : 'false<br />';
echo (isset($varA)) ? 'true<br />' : 'false<br />';

Wyświetli nam false a w drugim warunku true

0

@leonpro778: No i prawidlowo ci wyswietla. W pierwszym przypadku pytasz czy wartosc jest True a nie jesy bo jest 0 wiec powinno byc false. W drugim przypadku pytasz czy jakaolwiek wartosc jest ustawiona do zmiennej varA? wiec masz odpowiedz ze tak. Co cie tu dziwi?

W pierwszym przypadku jesli nie bedziesz mial zadeklarowanej zmiennej $varA to php ci taka zmienna utworzy wlasnie w tym momencie i przypisze do nie false, w drugim przypadku nie zostanie zmienna utworzona tylko dostaniesz rezultat false poniewaz zmienna nie moze byc znaleziona czyli jest wartosc null. ale tej zmiennej nie utworzy. Dlatego piszelm ze isset jest lepsze

0

@chomikowski: Mi bardziej chodziło o wskazanie różnic ponieważ napisałeś, że nie ma różnicy jako takiej a jednak są różnice. Chodzi tutaj o to, że cyfra 0/1 jest konwertowana automatycznie na true/false (kretynizm moim zdaniem) i te dwie metody sprawdzania dają różne rezultaty. Co do Twojej dalszej wypowiedzi to się mylisz:

<?php
// $varA = 0;

echo ($varA) ? 'true<br />' : 'false<br />';
echo (isset($varA)) ? 'true<br />' : 'false<br />';

Odpowiedź:
Notice: Undefined variable: varA in C:\www\temp\index.php on line 4
false
false

PHP w pierwszym przypadku nic mi nie utworzy

1 użytkowników online, w tym zalogowanych: 0, gości: 1