Ответ 1
К лучшему или худшему, свободный ввод текста "Путь PHP" . Многие из встроенных модулей и большинство языковых конструкций будут работать на любых типах, которые вы им даете - молча (и часто опасно) бросать их за кулисы, чтобы вещи (вроде) сочетались друг с другом.
Исходя из опыта Java/C/С++, модель PHP для свободной печати всегда была источником разочарования для меня. Но на протяжении многих лет я обнаружил, что, если мне нужно писать PHP, я могу сделать лучше (я делаю это более чистым, безопасным, более тестируемым), обнимая "слабость" PHP, а не борясь с ним; и из-за этого я становлюсь более счастливой обезьяной.
Кастинг действительно является основополагающим для моей техники - и (IMHO) - это единственный способ последовательно создавать чистый, читаемый PHP-код, который обрабатывает аргументы смешанного типа в хорошо понятном, проверяемом, детерминированном виде.
Основной момент (который вы также четко понимаете) заключается в том, что в PHP вы не можете просто предположить, что аргумент является тем типом, который вы ожидаете от него. Это может привести к серьезным последствиям, которые вы вряд ли поймаете, пока ваше приложение не приступит к производству.
Чтобы проиллюстрировать этот момент:
<?php
function displayRoomCount( $numBoys, $numGirls ) {
// we'll assume both args are int
// check boundary conditions
if( ($numBoys < 0) || ($numGirls < 0) ) throw new Exception('argument out of range');
// perform the specified logic
$total = $numBoys + $numGirls;
print( "{$total} people: {$numBoys} boys, and {$numGirls} girls \n" );
}
displayRoomCount(0, 0); // (ok) prints: "0 people: 0 boys, and 0 girls"
displayRoomCount(-10, 20); // (ok) throws an exception
displayRoomCount("asdf", 10); // (wrong!) prints: "10 people: asdf boys, and 10 girls"
Один из подходов к решению этого - ограничить типы, которые может принимать функция, бросая исключение, когда обнаружен недопустимый тип. Другие уже упоминали этот подход. Это хорошо отражается на моей Java/C/С++ -эстетике, и я следовал этому подходу в PHP годами и годами. Короче говоря, в этом нет ничего плохого, но это противоречит "Пути PHP", и через некоторое время это начинает ощущаться как плавание вверх.
В качестве альтернативы, литье обеспечивает простой и чистый способ гарантировать, что функция ведет себя детерминистически для всех возможных входов, без необходимости писать конкретную логику для обработки каждого другого типа.
Используя литье, наш пример теперь выглядит следующим образом:
<?php
function displayRoomCount( $numBoys, $numGirls ) {
// we cast to ensure that we have the types we expect
$numBoys = (int)$numBoys;
$numGirls = (int)$numGirls;
// check boundary conditions
if( ($numBoys < 0) || ($numGirls < 0) ) throw new Exception('argument out of range');
// perform the specified logic
$total = $numBoys + $numGirls;
print( "{$total} people: {$numBoys} boys, and {$numGirls} girls \n" );
}
displayRoomCount("asdf", 10); // (ok now!) prints: "10 people: 0 boys, and 10 girls"
Теперь функция ведет себя так, как ожидалось. Фактически, легко показать, что поведение функции теперь хорошо определено для всех возможных входов. Это связано с тем, что операция литья хорошо определена для всех возможных входов; броски гарантируют, что мы всегда работаем с целыми числами; а остальная часть функции записывается так, чтобы быть четко определенной для всех возможных целых чисел.
Правила для литья типов в PHP описаны здесь, (см. ссылки на конкретные страницы в середине страницы - например: "Преобразование в целое число" ).
Этот подход имеет дополнительное преимущество в том, что функция теперь будет вести себя так, как это согласуется с другими встроенными PHP и языковыми конструкциями. Например:
// assume $db_row read from a database of some sort
displayRoomCount( $db_row['boys'], $db_row['girls'] );
будет работать нормально, несмотря на то, что $db_row['boys']
и $db_row['girls']
являются фактически строками, которые содержат числовые значения. Это согласуется с тем, что средний PHP-разработчик (который не знает C, С++ или Java) ожидает, что он будет работать.
Что касается значений возвращаемых значений: это очень мало, если вы не знаете, что у вас есть переменная смешанного типа, и вы всегда должны гарантировать, что возвращаемое значение является определенным типом. Это чаще встречается в промежуточных точках кода, а не в точке, откуда вы возвращаетесь от функции.
Практический пример:
<?php
function getParam( $name, $idx=0 ) {
$name = (string)$name;
$idx = (int)$idx;
if($name==='') return null;
if($idx<0) $idx=0;
// $_REQUEST[$name] could be null, or string, or array
// this depends on the web request that came in. Our use of
// the array cast here, lets us write generic logic to deal with them all
//
$param = (array)$_REQUEST[$name];
if( count($param) <= $idx) return null;
return $param[$idx];
}
// here, the cast is used to ensure that we always get a string
// even if "fullName" was missing from the request, the cast will convert
// the returned NULL value into an empty string.
$full_name = (string)getParam("fullName");
Вы получаете идею.
Есть пара полезных сведений о
-
Механизм кастования PHP недостаточно умен, чтобы оптимизировать "no-op". Поэтому кастинг всегда вызывает копирование переменной. В большинстве случаев это не проблема, но если вы регулярно используете этот подход, вы должны держать его в глубине своего сознания. Из-за этого кастинг может вызвать неожиданные проблемы со ссылками и большими массивами. Подробнее см. Отчет об ошибке PHP # 50894.
-
В php целое число, которое слишком велико (или слишком мало) для представления в виде целочисленного типа, будет автоматически представлено как float (или double, если необходимо). Это означает, что результат
($big_int + $big_int)
может фактически быть поплавком, и если вы передадите его в int, то результирующее число будет тарабарщиной. Итак, если вы строите функции, которые должны работать на больших целых числах, вы должны помнить об этом и, возможно, рассмотреть какой-то другой подход.
Извините за длинный пост, но это тема, которую я подробно рассмотрел, и с годами я накопил немало знаний (и мнения) об этом. Поставив его здесь, я надеюсь, что кто-то найдет его полезным.