Адаптивная типизация
PHP*
Суть сего паттерна заключается в том, чтобы задавать типы значений через накладываемые на них ограничения. И при возможности изменять это значение так, чтобы оно вписывалось в эти ограничения.
Для чего вообще нужна типизация? Чтобы отлавливать появление ошибки как можно раньше, то есть как можно ближе к тому месту, где программист совершил оплошность, а не к тому, где она вызвала непоправимый сбой. Но вручную приводить типы — это слишком накладно, поэтому необходимо автоматическое приведение для совместимых друг с другом типов. Например, «строка не длиннее Х, содержащая только цифры» может быть однозначно преобразована «целое положительное число», и наоборот.
Многие языки не позволяют определять собственные типы. Некоторые языки это позволяют, но выразительных средств зачастую не хватает. Однако, можно опредлить набор функций, каждая из которых на вход принимает значение и на выходе гарантирует, что возвращённое ею значение удовлетворяет всем ограничениям. При этом она может попытаться преобразовать значение так, чтобы оно соответствовало ограничениям, а если ей это не удаётся — должна бросить исключение.
Определим несколько типовых тайпкастеров:
Это тайпкастеры общего назвачения. Они делают приведение типов абы как, поэтому лучше вместо них использовать более специфичные типы, соответствующие вашей бизнес-логике:
Заметьте, что тайпкастеры сначала изменяют значение параметра, а потом его возвращают. Это позволяет использовать их в двух формах:
Сейчас типовая функция, реализующая паттерн адаптивной типизации, выглядит примерно так:
Однако, возможно вскоре в пхп будет добавлена нативная поддержка и запись станет более удобной:
Фактически мы получим тогда статическую типизацию функций с автоматическим приведением и возможностью самостоятельно определять новые типы данных. А пока разве что можно воспользоваться кодогенерацией или не лениться ;-)
Для чего вообще нужна типизация? Чтобы отлавливать появление ошибки как можно раньше, то есть как можно ближе к тому месту, где программист совершил оплошность, а не к тому, где она вызвала непоправимый сбой. Но вручную приводить типы — это слишком накладно, поэтому необходимо автоматическое приведение для совместимых друг с другом типов. Например, «строка не длиннее Х, содержащая только цифры» может быть однозначно преобразована «целое положительное число», и наоборот.
Многие языки не позволяют определять собственные типы. Некоторые языки это позволяют, но выразительных средств зачастую не хватает. Однако, можно опредлить набор функций, каждая из которых на вход принимает значение и на выходе гарантирует, что возвращённое ею значение удовлетворяет всем ограничениям. При этом она может попытаться преобразовать значение так, чтобы оно соответствовало ограничениям, а если ей это не удаётся — должна бросить исключение.
Определим несколько типовых тайпкастеров:
function aNumber( $val ){
if( !is_numeric( $val ) ) throw new Exception( 'can not convert to number' );
return $val= +$val;
}
function aString( $val ){
return $val= $val . '';
}
function anArray( $val ){
if( is_object( $val ) ) $val= get_object_vars( $val );
else if( !is_array( $val ) ) throw new Exception( 'can not convert to array' );
return $val;
}Это тайпкастеры общего назвачения. Они делают приведение типов абы как, поэтому лучше вместо них использовать более специфичные типы, соответствующие вашей бизнес-логике:
function anUserId( $val ){
aNumber( &$val );
if( $val <= 0 ) throw new Exception( 'user id is not positive' );
return $val;
}Заметьте, что тайпкастеры сначала изменяют значение параметра, а потом его возвращают. Это позволяет использовать их в двух формах:
function example( $count ){
aNumber( &$count ); // передали переменную по ссылке. внутри функции она при необходимости будет изменена
return aString( $count + 2 ); // передали некоторое выражение и воспользовались возвращаемым функцией результатом.
}
$x= example( '2' ); // вернёт '4'
$y= example( '2x' ); // бросит исключениеСейчас типовая функция, реализующая паттерн адаптивной типизации, выглядит примерно так:
function xxx( $count= 0, $title= '', $list= array(), $user= 0, $db= null ){
aNumber( &$count ); aString( &$title ); anArray( &$list ); anUserId( &$user ); DB::anInstance( $db );
var_dump( $count, $title, $list, $user );
return aString( $count * 2 );
}Однако, возможно вскоре в пхп будет добавлена нативная поддержка и запись станет более удобной:
function aString xxx( aNumber $count= 0, aString $title= '', anArray $list= array(), anUserId $user= 0, DB $db= null ){
var_dump( $count, $title, $list, $user );
return $count * 2;
}Фактически мы получим тогда статическую типизацию функций с автоматическим приведением и возможностью самостоятельно определять новые типы данных. А пока разве что можно воспользоваться кодогенерацией или не лениться ;-)

комментарии (18)