Как известно, язык PHP славится своими «подводными камнями», когда дело касается типизации переменных.
Рассмотрим задачу, когда, казалось бы, очевидное и простое решение вдруг не работает, и очень важно внимательно читать документацию.
Допустим, у нас есть текст, в котором содержится номер договора, и есть массив соответствия номеров договоров названиям компаний-контрагентов. Лобовое решение может выглядеть примерно так
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<?php $text = 'Договор № 123'; $companyByContract = [ 123 => 'Microsoft', 456 => 'Google', 789 => 'Facebook', ]; $companyName = ''; foreach($companyByContract as $id => $company) { if (strpos($text, $id) !== false) { $companyName = $company; break; } } echo $companyName; |
Запускаем, ожидаем увидеть текст Microsoft — но ничего нет! Как же так, все же просто?! Начинаем читать документацию функции strpos() и находим там следующее: «Если needle [второй параметр функции] не является строкой, он приводится к целому и трактуется как код символа». Ага, все понятно, надо задать ключи в массиве в виде строк, вот так:
1 2 3 4 5 6 7 |
... $companyByContract = [ '123' => 'Microsoft', '456' => 'Google', '789' => 'Facebook', ]; ... |
Запускаем — и снова ничего! И снова читаем документацию, теперь уже по массивам, и находим там следующее: «Строки, содержащие целое число (исключая случаи, когда число предваряется знаком +) будут преобразованы к типу integer». То есть наше преобразование ключей оказалось бесполезным, они все равно считаются средой PHP целочисленными. В итоге приходится при каждой итерации предварительно преобразовывать ключ массива к строковому типу:
1 2 3 4 5 6 7 8 9 |
... foreach($companyByContract as $id => $company) { $id = (string)$id; if (strpos($text, $id) !== false) { $companyName = $company; break; } } ... |
Можно предложить еще один вариант решения задачи — через регулярные выражения:
1 2 3 4 5 6 7 8 |
... $ids = array_keys($companyByContract); if (preg_match('/'.join('|', $ids).'/', $text, $matches)) { $id = $matches[0]; $companyName = $companyByContract[$id]; } ... |
Мораль сей басни такова: читайте внимательно документацию, там часто поясняются тонкие моменты и «подводные камни».
P.S. Я намеренно немного упростил решение задачи, потому что, например, если есть договоры с номером 12 и 123, то при простом поиске по тексту ‘Договор № 123’ номер легко может определиться как 12, но это уже не относится к теме заметки, это больше о том, что входные данные могут подкидывать любые сюрпризы, нужно всегда быть готовым к ним, всегда держать голову включенной. В данном случае мы могли бы переписать наш поиск так:
1 2 3 4 5 |
... if (preg_match('/('.join('|', $ids).')(?!\d)/', $text, $matches)) { ... } ... |
То есть мы ищем в тексте подстроку с номером договора, и требуем, чтоб после этой подстроки не шла цифра.