Типизация зло?

demongloom

Новичок
Типизация зло?

Как лучше решить вопрос с типизацией, особенно с такими "слабо" контролируемыми типами, как string/numeric. Причем решение не должно быть жестким.

Пример отсутствия типизации.

function test($a) { echo $a; }

Пример стандартной типизации.

function test($a) { echo (string) $a; }

Пример жесткой типизации.

function test($a) {

if( !is_string($a) ) {
return trigger_error("wrong arg type"); }

echo $a;

}

Пример более мягкой типизации, с уведомлением.

function test($a) {

if( !is_scalar($a) || !settype($a,"string") ) {
return trigger_error("wrong arg type"); }

echo $a;

}

Как лучше?
 

Vladson

Сильнобухер
Пример жесткой типизации лучше.

Более того, желательно идти ещё дальше и в зависимости от данных которые мы ждём сделать её ещё более жесткой

function test($a) {
if( !is_string($a) ) {
return trigger_error("wrong arg type");
}
if ( !preg_match('/[^a-z0-9]/si', $a) ) {
return trigger_error("hacking attempt");
}
echo $a;
}
 

Андрейка

Senior pomidor developer
жесткая типизация регулярными выражениями - это жестко

PHP:
if (true==($res = mysql_query("SELECT 2,3,4"))) {

    if (!is_resource($res)) {
        die("NOT RESOURCE!!");
   }
    if (true==($data = mysql_fetch_row($res))) {
        if (is_array($data)) {
            $n = $data[1];
            if (is_string($n)) {
                  //.....
           }
       } else die("AAAAAA!!");
   }
}
во как надо, а то вдруг что..
 

demongloom

Новичок
Ну скажем так, хочется отлавливать различные ошибки, которые вероятно могут возникнуть при типизации. Скажем вместо строки передадут массив. Пхп слопает $arg = (string) $arg; и значение будет 'Array', причем при этом пхп даже не ругнется.

Хочется этакий синтаксис
void function test(integer $a, ~integer $b) {
echo $a + $b;
}

test(2,2) // 4
test(2,"2.3"); // 4
test("2.3", 2); // ошибка, т.к. 1 аргумент не integer.

~ - означает приведение к типу, а если этого символа нет, то жесткая проверка.


все таки свободная динамичная типизация, точно такая же крайность как и жесткая типизация.
нужно предоставлять оба инструмента, а не склонятся к одному единственному.
 

denver

?>Скриптер
Андрейка
die() как метод выкидывания ошибок это жестко
 

Андрейка

Senior pomidor developer
denver
не хуже(не лучше) trigger_error, зато имеет больше смысла, чем return trigger_error(...);
PHP:
function isUserAdmin($username) {
  if ( !preg_match('/[^a-z0-9]/si', $username) ) { 
     return trigger_error('hacking attempt');
  }
  //.....
}
:)))))))))))))))))))))))))

demongloom
Скажем вместо строки передадут массив.
что-ж такое ты программируешь, если тебе часто вместо строки массив передают
 

Vladson

Сильнобухер
Popoff, Андрейка
Есть поговорка "Если у вас параноя, это вовсе не значит что за вами не следят!"
Если бы к проверке переменных с такой "маниакальной" силой относились все программисты то сайты типа секъюритилаба имели ОГРОМНЫЙ дефицит статей...

(конечно перебарщивать не стоит, это только навредит, но если игнорировать подобные проверки абсолютно, то результаты могут быть даже плачевными)
 

Bermuda

Новичок
demongloom
Лучше побольше строк кода, побольше условий, циклов, регулярных выражений. Самое главное не думать зачем это нужно, а просто применять, жесткую типизацию, конечно же. А потом сидеть и удивляться "Интересно посмотреть как теперь вся эта фигня взлетит".

А вообще если язык милостиво приводит одни типы к другим и не выдает даже варнинга, то может быть в этом есть некий тайный смысл? Может так оно и задумано? Хотя если это не устраивает, то всегда можно выбрать другой интсрумент для написания программ, пожестче инструмент.
 

Vallar_ultra

Любитель выпить :)
2demongloom
Может лучше юзать связку ASP.NET / C# если требуется НАСТОЛЬКО жёсткий контроль за данными?
 

Popoff

popoff.donetsk.ua
Vladson
Ты меня с кем-то попутал. Я как раз и задал свой вопрос:
Для чего это нужно?
потому, что сомневаюсь в необходимости подобных жёстких проверок. Лично у меня возникло только одно место, в котором я провёл подобную жесточайшую проверку всеми доступными способами, да ещё и юнит тестов написал на километр - это проверка правильности ввода имени привилегии. Потому как если будет взломано распределение привилегий, все прочие защиты уже не будут иметь значения.

В остальных местах подобные крайности нахожу лишими.

Поэтому, раз уж Вы взялись за выставление диагнозов, то выставьте его, пожалуйста, и себе.

return trigger_error(...);
Это же надо было такую бредятину придумать %) Думаю, эта конструкция займёт достойное место среди моих вопросов.
 

Mich

Продвинутый новичёк
Имхо насиловать PHP жесткой типизацией не стоит. Уж лучше простой лаконичный код, возлагающий больше ответственности на программера, чем ф-ции на 90% состоящие из проверок. Причем смысл всего этого неочевиден.

И я думаю не стоит смешивать типизацию и валидацию. И соответсвенно приплетать сида securitylab.
 

Vladson

Сильнобухер
Автор оригинала: Popoff
Vladson
сомневаюсь в необходимости подобных жёстких проверок.
Как я и сказал, перебарщивать не стоит, но совсем нгнорировать проверку тоже нельзя...

Для примера большенство дыр которые мне пришлось заделать в рнрВВ когда я стал админом на одном сайте, были именно по вине недостаточных проверок, одно из таких исправлений вошло в рнрВВ2.0.16, (именно в связи с отсутсвием строгой типизации) в результате проверялся размер загруженных аватаров.
 

whirlwind

TDD infected, paranoid
Не надо путать типизацию и валидацию. Типизация для защиты кода от ошибок программиста. А валидация - это ограничения алгоритма.
 

Vladson

Сильнобухер
whirlwind
В случае типизации в описанном мной случае можно было вовсе избежать валидацию, и это только один пример, а существует их много...
 

whirlwind

TDD infected, paranoid
Vladson

>Не надо путать типизацию и валидацию
Типизация - это встроенный в язык механизм контроля ошибок.

PHP:
function approve(Order $order){
    if ( !$order->isSelected() )
         throw new Exception("Unselected");
    ...
}


function someFunc(){
     ...
     $document = new Decline();
     $this->approve($document); // нельзя - типизация
     ...
     $document = new Order();
     $this->approve($document); // можно, но будет исключение
}
 

demongloom

Новичок
А вообще если язык милостиво приводит одни типы к другим и не выдает даже варнинга, то может быть в этом есть некий тайный смысл? Может так оно и задумано? Хотя если это не устраивает, то всегда можно выбрать другой интсрумент для написания программ, пожестче инструмент.
2demongloom
Может лучше юзать связку ASP.NET / C# если требуется НАСТОЛЬКО жёсткий контроль за данными?
Так в том то и дело, что текущее положение типизации в пхп не совсем нормальное, но не бросать же всю предыдущуюю работу из за того что в этом языке такой то инструмент сделан через ж, а в этом такой то. С таким подходом я уже сталкивался и пришел к выводу что надо писать свой язык, который устроит на 100%, но сами понимаете что это еще большая паранойя чем "ручная" проверка типов.

Начнем с простого, например приведение нескалярных типов, к строковому. Ладно бы, если была бы ошибка типа warning: array to string casting, но ее нет. Отлаживать ошибки гораздо сложней, когда скажем вместо осмысленной строки, получаешь "Array" или "Object id #xxx", поскольку случайно переменную перепутал. Само наличие таких проверок могло бы серьезно облегчить отладку. Это не значит что большая часть ошибок у меня возникает из за типизации, но это помогло бы в случае возникновения таких проблем.

Теперь другой пример, когда слишком жесткая типизация. Пример был дан выше: approve(Order $order), но он не совсем точен. Допустим сделают в пхп проверку типизации и скажем напишем функцию approve(String $order). При той реализации какая есть сейчас, в случае передачи аргумента не соответствующего типа, будет неперехватываемая фатальная ошибка. Естественно это тоже перегиб.
 

Андрейка

Senior pomidor developer
фикня какая-то пошла....

Как лучше решить вопрос с типизацией
никак
Ладно бы, если была бы ошибка типа warning: array to string casting, но ее нет.
При той реализации какая есть сейчас, в случае передачи аргумента не соответствующего типа, будет неперехватываемая фатальная ошибка
обратись к разработчикам.. вдруг они с тобой согласятся
но это помогло бы в случае возникновения таких проблем
может и помогло БЫ, но не поможет ЖЕ
скажем напишем функцию approve(String $order).
если ты пишешь класс(функцию) не "для других", то уж позаботиться о том, что передается в функцию проще простого... а от echo $array; тебя ничего не спасет
 

demongloom

Новичок
Как лучше решить вопрос с типизацией
никак


Я это понял, поэтому продолжу использовать конструкции
if( !is_scalar($a) || !settype($a,"string") ) {
throw new e_function_argument_type_is_incorrect("#1","~string"); }

Всегда их можно будет закоментировать, если это сильно ударит по производительности.


Ладно бы, если была бы ошибка типа warning: array to string casting, но ее нет.
При той реализации какая есть сейчас, в случае передачи аргумента не соответствующего типа, будет неперехватываемая фатальная ошибка
обратись к разработчикам.. вдруг они с тобой согласятся


Обращаться есть смысл если за тобой стоят люди поддерживающие идею. Хотел бы я кстати увидеть тех кто хочет уникод в пхп6, в качестве имен функций или переменных. Этож дикий гимор разбирать будет код. Я вот недавно vhcs смотрел. Там все комментарии и часть документации на немецском. Что будет если и код будет на нем же?
Есть действительно гораздо более насущные проблемы.


но это помогло бы в случае возникновения таких проблем
может и помогло БЫ, но не поможет ЖЕ


Непоможет т.к. остстувуют стандартные механизмы, приходится писать свое, что гораздо серьезней бьет по производительности, чем встроенные на уровне интерперетатора проверки. И прекрасно поможет и покажет что где не так написано, особенно начинающим новичкам в пхп/программировании.


скажем напишем функцию approve(String $order).
если ты пишешь класс(функцию) не "для других", то уж позаботиться о том, что передается в функцию проще простого... а от echo $array; тебя ничего не спасет


Я лишь привел пример что жесткая типизация, которая приводит к фатальной ошибке тоже перегиб.

strlen(count(array(н число элементов))) приведет к фатальной ошибке, т.к. count возвращает интегер, а не строку.
 
Сверху