За последние 24 часа нас посетили 17748 программистов и 1685 роботов. Сейчас ищут 1048 программистов ...

Доопределение и проверка аргументов

Тема в разделе "PHP для новичков", создана пользователем T-Mon, 21 апр 2009.

  1. T-Mon

    T-Mon Активный пользователь

    С нами с:
    2 янв 2008
    Сообщения:
    67
    Симпатии:
    0
    Адрес:
    Kyiv
    На сколько я знаю, PHP не поддерживает ни доопределения функций, ни операторов, так как нормально не можно проверять входящие аргументы на этапе поиска функции по сигнатуре (которого нет). Как эти моменты можно тонко обойти?

    P.S. Цель - добиться программирования в безопасном строго типизированном режиме.
     
  2. akrinel

    akrinel Активный пользователь

    С нами с:
    26 янв 2009
    Сообщения:
    955
    Симпатии:
    1
    Адрес:
    Spb
     
  3. T-Mon

    T-Mon Активный пользователь

    С нами с:
    2 янв 2008
    Сообщения:
    67
    Симпатии:
    0
    Адрес:
    Kyiv
    Но
    PHP:
    1. <?php
    2. function test (int $a, bool $b)
    3. {}
    4.  
    5. function test (int $a, bool $b, bool $c)
    6. {}
    7. ?>
    не пройдет по двум причинам - мы не можем отслеживать типы аргументов примитивных типов, мы не можем доопределять функции по сигнатуре.
     
  4. Apple

    Apple Активный пользователь

    С нами с:
    13 янв 2007
    Сообщения:
    4.984
    Симпатии:
    2
    PHP:
    1. <?php
    2.  
    3. class Someclass
    4. {
    5.     public function somef($intVar){
    6.         if(!is_int($intVar)){
    7.             // throw new Exception;
    8.         }
    9.     }
    10. }
    11.  
    12. $ab = new Someclass();
    13. $ab->somef('abc');
    14.  
    15. ?>
    16.  
    Проверку можно организовать грамотно, если это нужно.
    Насчет последнего я не понял.
     
  5. T-Mon

    T-Mon Активный пользователь

    С нами с:
    2 янв 2008
    Сообщения:
    67
    Симпатии:
    0
    Адрес:
    Kyiv
    Простой пример, мы хотим определить 4 конструктора для класса триугольников - 1) по всем координатам каждой точки, 2) по трем точкам-объектам, 3) по трем отрезкам-объектам, 4) и конструктор копирования другого триугольника; выглядит это приблизительно так:
    PHP:
    1. <?php
    2.  
    3. class Triangle
    4. {
    5.     //...
    6.    
    7.     public function __construct (int $x1, int $y1, int $x2, int $y2, int $x3, int $y3)
    8.     {
    9.         //...
    10.     }
    11.    
    12.     public function __construct (Point $p1, Point $p2, Point $p3)
    13.     {
    14.         //...
    15.     }
    16.    
    17.     public function __construct (Vector $p1, Vector $p2, Vector $p3)
    18.     {
    19.         //...
    20.     }
    21.    
    22.     public function __construct (Triangle $t)
    23.     {
    24.         //...
    25.     }
    26. }
    27.  
    28. ?>
    То есть, в зависимости от входящих аргументов, вызывается тот или иной конструктор.
    По поводу проверки входных аргументов, твой способ нельзя назвать слишком элегантным...
     
  6. Apple

    Apple Активный пользователь

    С нами с:
    13 янв 2007
    Сообщения:
    4.984
    Симпатии:
    2
    T-Mon, если не ошибаюсь, в РНР нельзя перегружать методы, есть только возможность переопределять их в дочерних классах.

    Я не претендую на элегантность, я говорю о том, что не так уж это и невозможно, и в качестве примера набросал код.
    Само собой РНР != С++ и одно из его преимуществ (так считается) - это компромисс по отношению контроля типов.
    Я, когда начал писать на РНР, постоянно перед переменной писал int $var
     
  7. T-Mon

    T-Mon Активный пользователь

    С нами с:
    2 янв 2008
    Сообщения:
    67
    Симпатии:
    0
    Адрес:
    Kyiv
    Это возможно, и я чудесно понимаю, что аргументы можно проверять просто внутри метода, а вместо доопределения методов можно по аргументам внутри определять, что делать. Но это все громоздко, неудобно и склонно к ошибкам.
    Кстати, на счет С++, я его тоже не очень люблю (а программировать на нем вообще не умею) из-за его ужасных явных указателей и определений классов за пределами классов. А за что я уважаю С++, это доопределение операторов, чего просто ужасно не хватает в PHP и Jav'е.

    P.S. "Перегрузка" не совсем корректное слово в плане перевода, а уж тем более в плане смыслового значения. Если переводить "overloading" с английского, то это скорее будет "догрузка", "надгрузка", а точнее "доопределение" - то есть добавление дополнительного смысла. "Перегрузка" уже больше по смыслу сходно с "Overriding" - переопределению методов класса.
     
  8. Apple

    Apple Активный пользователь

    С нами с:
    13 янв 2007
    Сообщения:
    4.984
    Симпатии:
    2
    Ну корректное оно или некорректное, исторически сложилось так, что во всех пособиях по изучению языков overloading всегда переводилось как "перегрузка" операторов.
    Если же вдаваться в семантику английского языка, то тут неправы вы.
    Overloading никак не переводится "надгрузка" или "догрузка", приведу даже пример, дабы не быть голословным: overate - переесть, look over - пересматривать, если копать дальше, в недры суфикса over-, то можно констатировать факт, что over- переводится на русский над-, пере-, сверх-.
    Простите, я английский не в школе учил, одно из требований там, где я работаю - fluent English.
    Посему, для меня незнание таких элементарных вещей было бы равносильно увольнению.
    На этом закончим разбор грамматических структур.

    Что касается перегрузки (да-да, именно так правильно), то нефиксированное количество аргументов, их логическая проверка по типам, классификация - это не имеет ИМХО смысла делать на РНР, по крайней мере сейчас.
    Кстати:
    Встроенными средствами это сделать невозможно, как бы вы что прекрасно там не понимали.

    Собственно это те причины, по которым я люблю С++ и езжу на нем уже пол своей жизни.
     
  9. T-Mon

    T-Mon Активный пользователь

    С нами с:
    2 янв 2008
    Сообщения:
    67
    Симпатии:
    0
    Адрес:
    Kyiv
    1) По поводу "overloading", один преподаватель мне подробно объяснил, что то единое слово "overload", которое буквально переводится, как "перегружать", "отягощать" (Lingvo), нужно рассматривать первоначально как два отдельных слова "over" - "над", "сверху", "дополнительно" (совсем не в негативном значении) и "load" - "нагружать" (в нашем контексте "смысловая нагрузка", "функциональная нагрузка"). Что означает, что наши функции имеют дополнительную (альтернативную) функциональную нагрузку, то есть их функциональность была доопределена. Английский язык - язык краткий, и берясь за перевод нельзя вырывать фразы из контекста и просто переводить, как есть. А контекст нам подсказывает, что мы эти функции не "чрезмерно загружаем" и не "переотягощаем", а "доопределяем". Если исторически сложилось, что каждый второй программист называет вещь словом, которое абсолютно не соответствует ее смыслу, это по крайней мере должно заставлять задуматься - стоит ли мне повторять ту же глупость за другими, или же называть вещи своими именами. Так сложилось, что я тоже неплохо учил английский, может не так хорошо, как ты, но имел опыт перевода текстов, и знаю, что зачастую значения слов подбираются не только прямым сопоставлением со словарем, но и согласованием с контекстом.

    2) По поводу доопределения методов (да-да, именно так корректно), оно позволяет строить элегантные приложения с минимальных риском допускания ошибки и максимальным удобством для программиста, дальнейших модификаций и редактирования.

    3) Как ни странно, возможно, но грубо и небезопасно:
    PHP:
    1. <?php
    2.  
    3. function test ()
    4. {
    5.     $args = func_get_args ();
    6.     $num = func_num_args ();
    7.    
    8.     switch ($num):
    9.         case (1):
    10.             if (is_int ($args [0])):
    11.                 //Code...
    12.                 echo ('Call function with 1 arg: ' . $args [0] . '<br />');
    13.             else:
    14.                 throw new Exception;
    15.             endif;
    16.         break;
    17.        
    18.         case (2):
    19.             if (is_int ($args [0]) && is_int ($args[1])):
    20.                 //Code...
    21.                 echo ('Call function with 2 int args: ' . $args [0] . ' and ' . $args [1] . '<br />');
    22.             elseif (is_int ($args [0]) && is_bool ($args[1])):
    23.                 //Code...
    24.                 echo ('Call function with 1 int arg and boolean: ' . $args [0] . '<br />');
    25.             else:
    26.                 throw new Exception;
    27.             endif;
    28.         break;
    29.        
    30.         default:
    31.             throw new Exception;
    32.         break;
    33.     endswitch;
    34. }
    35.  
    36. test (1);
    37. test (2, 3);
    38. test (3, true);
    39. try
    40. {
    41.     test ();
    42. }
    43. catch (Exception $exc)
    44. {
    45.     echo ($exc);
    46. }
    47.  
    48. ?>
    4) По поводу указателей еще готов понять - они обеспечивают контроль программиста над приложением (особенно smart pointer'ы), хотя и могут зачастую привести к неожиданным утечкам и крахам. Но вот по поводу определения классов в заголовных файлах, а их функционала за их пределами - не вижу ни каких приимуществ.
     
  10. Apple

    Apple Активный пользователь

    С нами с:
    13 янв 2007
    Сообщения:
    4.984
    Симпатии:
    2
    1. И всё-таки насчет перевода я крайне несогласен. Ваш преподаватель основывается на синтаксическом разборе слов, но проблема в том, что прибавление суффиксов или аффиксов часто ведет к образованию совершенно новых слов. Возмем старое русское слово "единый", от которого произошло современное слово "один". В настоящее время это два абсолютно разных по значению слова, ранее слово "единый" было точь в точь равно нашему слову "один".
    Я учился в основном по английской литературе, если брать С++, то тут на 100% на английском, С# читал на русском.
    И эта терминология уже считается официальной не смотря на то, как оно переводится.
    Всё адаптируется под смысл, лексику и так далее.

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

    3. Вообще, проверку типов я делаю только там, где это необходимо и действительно есть риск. Для int всегда вызываю функцию intval(), любую строку представляет как надо ('asdka' -> (int) 0), для float - floatval(). Самая распространенная ошибка или предумышленная подстановка - замена числового параметра строкой. Касательно bool значений, то можно представить truе/false как 1/0 - любая строка будет 1, отсутствие - 0, или же приводить данные к числовому типу, в случае строки - 0, иначе любое числовое значение - 1

    4. В принципе, речь шла об указателях. Насчет объявлений классов - так это сугубо дело стиля, в целях дебага больших проектов все средства хороши.
     
  11. откажитесь от пхп. Человек выбирает инструмент, а не инструмент - человека.
     
  12. T-Mon

    T-Mon Активный пользователь

    С нами с:
    2 янв 2008
    Сообщения:
    67
    Симпатии:
    0
    Адрес:
    Kyiv
    1) Я спорить больше не буду, просто буду употреблять слово "доопределение" в надежде, что меня поймут. Просто слово "перегрузка" лишено всякой связи с тем, что оно обозначает.

    2) Не могу, в виду того, что слово "перегрузка" в данном значении меня ужасно раздражает, на подсознательном уровне, а особенно в литературе.

    3) А тут я уже не особо что-то понял, пример, если можно...

    4) Явные указатели очень опасны, особенно в крупных приложениях.

    К сожалению, JAVA уже отпала, так как работать с ней в Internet не удобно. Осталось только узнать, как там с С#. Если и С# меня не удовлетворит - буду писать компилятор из PHP++ (модифицированный мною PHP) в PHP.
     
  13. Apple

    Apple Активный пользователь

    С нами с:
    13 янв 2007
    Сообщения:
    4.984
    Симпатии:
    2
    3.

    PHP:
    1. <?php
    2.  
    3. class Someclass
    4. {
    5.     public function check($intVar, $floatVar, $str, $boolVar)
    6.     {
    7.         $intVar   = intval($intVar);      // Работаем со значением как (int)
    8.         $floatVar = floatval($floatVar);  // Работаем со значением как (float)
    9.         $str      = strval($str);         // ЯВНО преобразуем значение в строку
    10.        
    11.         settype($boolVar, "boolean");     // Приведение значения к типу bool
    12.        
    13.        
    14.        
    15.         // Вывод получившихся переменных
    16.         echo '<pre>';
    17.         var_dump($intVar, $floatVar, $str, $boolVar);
    18.     }
    19. }
    20.  
    21. $cls = new Someclass;
    22.  
    23. $cls->check(10, 20.56, 'Hello, World', true);  // Передача корректных аргументов
    24.  
    25. $cls->check('abc', 'def', false, 645);         // Передача НЕКОРРЕКТНЫХ аргументов
    26. $cls->check(-5454.78, true, 0, 'Somethis');    // Передача НЕКОРРЕКТНЫХ аргументов
    27.  
    28. ?>
     
  14. lexa

    lexa Активный пользователь

    С нами с:
    22 июл 2007
    Сообщения:
    1.746
    Симпатии:
    0
    Адрес:
    Санкт-Петербург
    Слово "интернет" тоже раздражает?

    Пользуй питон. За исключением момента с duck typing, это язык строгой типизации. И достотачно удобный в Internet. Упомянутый "утиная типизация" просто определяет тип переменной во время указания:
    Код (Text):
    1. someint = 5
    2. sonestring = 'test'
    3.  
    4. try:
    5.     someint + sonestring
    6. except TypeError:
    7.     print 'Операция с несовместимыми типами.'
    Пхпшные игрища с типами так прекрасны. Не понимаю, почему люди начинавшие с других языков не любят столь мягкие и податливы типы в php. Просто чтобы не получить непредсказуемый результат следует либо приводить к желаемому типу входящие данные, либо исходящие:
    PHP:
    1. <?
    2. function test($array1, $array2){
    3.     return array_merge((array)$array1, (array)$array2);
    4. }
    5.  
    6. test('hop', array('lya'));
     
  15. +1. Это как фигурное катание