Jak uniknąć isset () i empty()
Mam kilka starszych aplikacji, które rzucają wiele komunikatów "xyz is undefined" i "undefined offset" podczas uruchamiania na poziomie błędu E_NOTICE, ponieważ istnienie zmiennych nie jest jawnie sprawdzane za pomocą isset()
i consorts.
Rozważam pracę nad nimi, aby były kompatybilne z E_NOTICE, ponieważ powiadomienia o brakujących zmiennych lub przesunięciach mogą uratować życie, mogą być pewne drobne ulepszenia wydajności, które można uzyskać, i ogólnie jest to czystszy sposób.
Jednak nie podoba mi się to, co zadaje setki isset()
empty()
i array_key_exists()
S robi z moim kodem. Staje się nadęty, staje się mniej czytelny, nie zyskując niczego pod względem wartości czy znaczenia.
Jak mogę uporządkować kod bez nadmiaru sprawdzania zmiennych, jednocześnie będąc kompatybilnym z E_NOTICE?
11 answers
Dla zainteresowanych rozszerzyłem ten temat na mały artykuł, który zawiera poniższe informacje w nieco lepiej zorganizowanej formie: The Definitive Guide to PHP ' s isset And empty{[35]]}
IMHO powinieneś pomyśleć nie tylko o tym, aby aplikacja była "kompatybilna z E_NOTICE", ale też o restrukturyzacji całej sprawy. Posiadanie setek punktów w kodzie, które regularnie próbują używać nieistniejących zmiennych, brzmi jak dość źle zorganizowany program. Trying to dostęp nieistniejące zmienne nigdy nie powinny się zdarzyć, inne języki balk w tym czasie kompilacji. Fakt, że PHP pozwala ci to zrobić, nie oznacza, że powinieneś.
Te ostrzeżenia są po to, by Ci pomóc, a nie by cię denerwować. Jeśli otrzymasz ostrzeżenie " próbujesz pracować z czymś, co nie istnieje!", twoja reakcja powinna być " UPS, mój błąd, pozwól mi to naprawić jak najszybciej." jak inaczej odróżnisz zmienne, które działają tylko fine undefined " i szczerze zły kod, który może prowadzić do poważnych błędów ? Jest to również powód, dla którego zawsze, zawsze , rozwijasz się z raportowaniem błędów zamienionym na 11 i trwaj przy swoim kodzie, dopóki nie zostanie wydany ani jedenNOTICE
. Wyłączenie raportowania błędów dotyczy tylko środowisk produkcyjnych, aby uniknąć wycieku informacji i zapewnić lepsze wrażenia użytkownika nawet w obliczu błędnego kodu.
Do rozwinięcia:
Będziesz zawsze potrzebujesz isset
lub empty
gdzieś w kodzie, jedynym sposobem na zmniejszenie ich występowania jest prawidłowe zainicjowanie zmiennych. W zależności od sytuacji istnieją różne sposoby, aby to zrobić:
Argumenty funkcji:
function foo ($bar, $baz = null) { ... }
Nie ma potrzeby sprawdzania, czy $bar
lub $baz
są ustawione wewnątrz funkcji, ponieważ po prostu je ustawisz, jedyne, o co musisz się martwić, to czy ich wartość zostanie obliczona na true
lub false
(lub cokolwiek innego).
Zmienne regularne anywhere:
$foo = null;
$bar = $baz = 'default value';
Zainicjalizuj swoje zmienne u góry bloku kodu, w którym będziesz ich używać. Rozwiązuje to problem !isset
, zapewnia, że zmienne zawsze mają znaną wartość domyślną, daje czytelnikowi wyobrażenie, na czym będzie działał poniższy kod, a tym samym służy również jako rodzaj samodzielnej dokumentacji.
Tablice:
$defaults = array('foo' => false, 'bar' => true, 'baz' => 'default value');
$values = array_merge($defaults, $incoming_array);
To samo co powyżej, inicjalizujesz tablicę wartościami domyślnymi i zastępujesz je rzeczywistymi wartości.
W pozostałych przypadkach, powiedzmy w szablonie, w którym wypisujesz wartości, które mogą lub nie mogą być ustawione przez kontroler, musisz tylko sprawdzić:
<table>
<?php if (!empty($foo) && is_array($foo)) : ?>
<?php foreach ($foo as $bar) : ?>
<tr>...</tr>
<?php endforeach; ?>
<?php else : ?>
<tr><td>No Foo!</td></tr>
<?php endif; ?>
</table>
Jeśli regularnie używasz array_key_exists
, powinieneś ocenić, do czego go używasz. Tylko tutaj robi różnicę:
$array = array('key' => null);
isset($array['key']); // false
array_key_exists('key', $array); // true
Jak wspomniano powyżej, jeśli prawidłowo inicjujesz zmienne, nie musisz sprawdzać, czy klucz istnieje, ponieważ wiesz, że tak. Jeśli otrzymujesz tablicę z zewnętrznego źródła, wartość najprawdopodobniej nie będzie null
, ale ''
, 0
, '0'
, false
lub coś w tym stylu, tj. wartość, którą możesz ocenić za pomocą isset
lub empty
, w zależności od intencji. Jeśli regularnie ustawiasz klucz tablicy na null
i chcesz, aby oznaczał cokolwiek innego niż false
, tzn. jeśli w powyższym przykładzie różne wyniki isset
i array_key_exists
mają wpływ na logikę Twojego programu, powinieneś zadać sobie pytanie dlaczego. Samo istnienie zmiennej nie powinno być ważne, tylko jego wartość powinna mieć znaczenie. Jeśli kluczem jest true
/false
flag, następnie użyj true
lub false
, a nie null
. Jedynym wyjątkiem od tego są biblioteki stron trzecich, które chcą, aby null
coś znaczyło, ale ponieważ null
jest tak trudny do wykrycia w PHP, nie znalazłem jeszcze żadnej biblioteki, która to robi.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-27 14:13:43
Po prostu napisz do tego funkcję. Coś w stylu:
function get_string($array, $index, $default = null) {
if (isset($array[$index]) && strlen($value = trim($array[$index])) > 0) {
return get_magic_quotes_gpc() ? stripslashes($value) : $value;
} else {
return $default;
}
}
Które możesz użyć jako
$username = get_string($_POST, 'username');
Zrób to samo dla błahych rzeczy, takich jak get_number()
, get_boolean()
, get_array()
i tak dalej.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-25 13:43:18
Uważam, że jednym z najlepszych sposobów radzenia sobie z tym problemem jest dostęp do wartości tablic GET I POST (COOKIE, SESSION, itp.) za pośrednictwem klasy.
Tworzy klasę dla każdej z tych tablic i deklaruje metody __get
i __set
(overloading ). __get
przyjmuje jeden argument, który będzie nazwą wartości. Ta metoda powinna sprawdzić tę wartość w odpowiedniej globalnej tablicy używając isset()
lub empty()
i zwrócić wartość, jeśli istnieje lub null
(lub innego domyślnego wartość) inaczej.
Następnie możesz bez obaw uzyskać dostęp do wartości tablicy w następujący sposób: $POST->username
i w razie potrzeby dokonać walidacji bez użycia isset()
s lub empty()
s. Jeśli username
nie istnieje w odpowiedniej globalnej tablicy, to zostanie zwrócona null
, więc nie będą generowane żadne ostrzeżenia ani ostrzeżenia.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-27 23:46:40
Nie mam nic przeciwko używaniu array_key_exists()
, w rzeczywistości wolę używać tej konkretnej funkcji zamiast polegać na hack funkcje, które mogą zmienić swoje zachowanie w przyszłości Jak (striked through to avoid susceptibilities ).empty
i isset
Używam jednak prostej funkcji, która przydaje się w tym i w niektórych innych sytuacjach w radzeniu sobie z indeksami tablicy : {]}
function Value($array, $key, $default = false)
{
if (is_array($array) === true)
{
settype($key, 'array');
foreach ($key as $value)
{
if (array_key_exists($value, $array) === false)
{
return $default;
}
$array = $array[$value];
}
return $array;
}
return $default;
}
Powiedzmy, że masz następujące tablice:
$arr1 = array
(
'xyz' => 'value'
);
$arr2 = array
(
'x' => array
(
'y' => array
(
'z' => 'value',
),
),
);
Jak uzyskać "wartość" z tablic? Proste:
Value($arr1, 'xyz', 'returns this if the index does not exist');
Value($arr2, array('x', 'y', 'z'), 'returns this if the index does not exist');
Mamy już pokryte tablice uni i wielowymiarowe, co jeszcze możemy zrobić?
Weźmy na przykład następujący fragment kodu:
$url = 'https://stackoverflow.com/questions/1960509';
$domain = parse_url($url);
if (is_array($domain) === true)
{
if (array_key_exists('host', $domain) === true)
{
$domain = $domain['host'];
}
else
{
$domain = 'N/A';
}
}
else
{
$domain = 'N/A';
}
Nudne, prawda? Oto inne podejście wykorzystujące funkcję Value()
:
$url = 'https://stackoverflow.com/questions/1960509';
$domain = Value(parse_url($url), 'host', 'N/A');
Jako dodatkowy przykład, weź RealIP()
funkcję do testu:
$ip = Value($_SERVER, 'HTTP_CLIENT_IP', Value($_SERVER, 'HTTP_X_FORWARDED_FOR', Value($_SERVER, 'REMOTE_ADDR')));
Neat, co? ;)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:17:20
Jestem tu z Tobą. Ale projektanci PHP popełnili znacznie więcej gorszych błędów niż to. Poza zdefiniowaniem funkcji niestandardowej dla dowolnego odczytu wartości, nie ma możliwości obejścia jej.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-25 06:04:30
Używam tych funkcji
function load(&$var) { return isset($var) ? $var : null; }
function POST($var) { return isset($_POST[$var]) ? $_POST[$var] : null; }
Przykłady
$y = load($x); // null, no notice
// this attitude is both readable and comfortable
if($login=POST("login")) // really =, not ==
if($pass=POST("pass"))
if($login=="Admin" && $pass==...) {
// login and pass are not empty, login is "Admin" and pass is ...
$authorized = true;
...
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-07-17 12:59:20
Tworzy funkcję, która zwraca false
jeśli nie jest ustawiona, oraz, jeśli jest określona, false
jeśli jest pusta. Jeśli jest poprawna, zwraca zmienną. Możesz dodać więcej opcji, jak widać w poniższym kodzie:
<?php
function isset_globals($method, $name, $option = "") {
if (isset($method[$name])) { // Check if such a variable
if ($option === "empty" && empty($method[$name])) { return false; } // Check if empty
if ($option === "stringLength" && strlen($method[$name])) { return strlen($method[$name]); } // Check length of string -- used when checking length of textareas
return ($method[$name]);
} else { return false; }
}
if (!isset_globals("$_post", "input_name", "empty")) {
echo "invalid";
} else {
/* You are safe to access the variable without worrying about errors! */
echo "you uploaded: " . $_POST["input_name"];
}
?>
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-12 17:18:45
Witamy w operatorze Null:
$field = $_GET['field'] ?? null;
PHP says:
Operator zerowy (??) został dodany jako cukier składniowy w powszechnym przypadku konieczności użycia trójnika w połączeniu z isset (). Zwraca swój pierwszy operand, jeśli istnieje i nie jest NULL; w przeciwnym razie zwraca swój drugi operand.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-05 16:55:07
Nie jestem pewien, jaka jest twoja definicja czytelności, ale właściwe użycie bloków empty (), isset () I try / throw/catch jest dość ważne dla całego procesu. Jeśli twój E_NOTICE pochodzi z $_GET lub $_POST, to powinny one być sprawdzane przez empty() wraz ze wszystkimi innymi kontrolami bezpieczeństwa, które te dane powinny przejść. Jeśli pochodzi z zewnętrznych kanałów lub bibliotek, powinien być zawinięty w try/catch. Jeśli pochodzi z bazy danych, $db_num_rows() lub jest równoważne należy sprawdzić. Jeśli pochodzi od zmiennych wewnętrznych, powinny być prawidłowo zainicjowane. Często tego typu powiadomienia pochodzą z przypisania nowej zmiennej do zwracanej funkcji, która zwraca FALSE po niepowodzeniu, powinny być owinięte w test, który w przypadku niepowodzenia może albo przypisać zmiennej akceptowalną wartość domyślną, którą może obsłużyć kod, albo rzucić wyjątek, który może obsłużyć kod. Te rzeczy wydłużają kod, dodają dodatkowe bloki i dodają dodatkowe testy, ale nie zgadzam się z Tobą w tym, że myślę, że zdecydowanie dodać dodatkową wartość.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-25 06:35:35
Oprogramowanie nie działa magicznie dzięki łasce Boga, jeśli oczekujesz czegoś, czego brakuje, musisz to odpowiednio obsłużyć. jeśli go zignorujesz, prawdopodobnie tworzysz luki w zabezpieczeniach w swoich aplikacjach. w językach statycznych dostęp do nieokreślonej zmiennej nie jest po prostu możliwy, nie kompiluje ani nie zawiesza aplikacji, jeśli jest null. ponadto sprawia, że aplikacja jest niemożliwa do utrzymania, a Ty oszalejesz, gdy wydarzy się coś nieoczekiwanego. surowość językowa jest koniecznością a php z założenia jest błędne w wielu aspektach. to uczyni cię złym programistą, jeśli nie jesteś tego świadomy.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-25 11:52:00
A co z użyciem operatora@? np.:
if(@$foo) { /* do something */ }
Możesz powiedzieć, że jest źle, ponieważ nie masz kontroli nad tym, co dzieje się" wewnątrz " $foo (jeśli było to wywołanie funkcji, które zawiera na przykład błąd PHP), ale jeśli używasz tylko tej techniki dla zmiennych, jest to równoważne:
if(isset($foo) && $foo) { /* ... */ }
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-13 20:13:26