Почему в PHP так всё непоследовательно?

28.11.2010

Например я могу создать массив простым объявлением $array[] = 'blabla', но свойство объекта таким способом через волшебный метод __set() хрен сделаешь — натыкаешься на ошибку Indirect modification of overloaded property. Ёшкин кот, ну почему?

Почему работа со свойством объекта отличается от работы с обычной переменной?

В поисках решения нашёл различные велосипеды и костыли, которые, в общем-то, всё равно не решают задачу так, как хочется. Или мне вечно не того хочется? Я совсем дурак, или всё же PHP недостаточно хорош? И что ж теперь делать? Пойду повешаюсь…

Комментарии

  1. # Ewg: 

    Zend_Config?

  2. # Alek$

    К слову сказать, инициализация массива таким вот образом:
    $array[] = ‘blabla’
    — крайне небезопаская вещь, особенно при включенном register_globals.
    Помню, в какой-то из старых версий Sat-X благодаря такой дыре можно было получить доступ к файловой системе и залить шелл.

  3. # Тормоз

    Ewg, сейчас почитаю, что это и зачем.

    Alek$, можно пример? Почему именно инициализация массива небезопасна и как надо, по-твоему?

  4. # Ewg: 

    За register_globals казнить пора

  5. # Ewg: 

    Если array имя печеньки, то ‘blabla’ добавиться к ней и будет видна юзеру.

  6. # Тормоз

    Почитал про Zend Config. В принципе, интересно, но наверняка это монстрячный класс (не скачивал пока) с очень избыточной функциональностью. И он всё равно не решает проблему непоследовательности. Почему меняется синтаксис доступа к элементам массива? Не понимаю, для чего так сделали.

  7. # Ewg: 

    >«проблему непоследовательности»
    Это о чём?

  8. # Alek$

    Ewg, тем не менее во имя обратной совместимости он еще много где включен.

    Тормоз, ну например в Sat-X был код в духе:

    for($i = 0; $i < sizeof($text_parts); $i++)
    {

    // bla-bla

    $files[] = $part;
    }

    // bla-bla

    for($i = 0; $i < sizeof($files); $i++)
    {

    $fp = fopen(»$i.txt», «w»);

    fwrite($fp, $files[$i]);

    fclose($fp);
    }

    В итоге если к запросу добавить параметр
    files[shell.php%00]=тут_код_шелла
    то вы получите рабочий шелл. Чтобы такого не было, надо в начале явно инициализировать массив $files = array();

  9. # Ewg: 

    Alek$, кому нужна совместимость с версией младше 4.2?

  10. # Тормоз

    Это о чём?

    Ну, блин, синтаксис меняется же! Если $some просто переменная (массив), то доступ к элементу будет $some['bla'], а если $some — свойство объекта Zend Config, тогда то же самое будет как $obj->some->bla.

    Вообще-то это довольно удобно даже, но всё равно совсем-совсем непонятно для чего сделали это различие. При этом если мы просто в каком-то классе укажем массив $some, то к его элементам можно будет обратиться как $obj->some[‘bla’], а вот присвоить значение через такую конструкцию не получится. Это как понимать? Почему?! Какой в этом скрытый смысл, для чего так сделано в языке?

    Alek$, а если ты инициализировал массив, при включенных register_globals разве значение не перепишется? Что меняется-то?

  11. # Alek$

    Ewg, вопрос не ко мне.

    Тормоз, если не инициализировать явно, то твои элементы добавятся к переданным зловредом в запросе.
    Если написать $files = array(), то все его потуги подсунуть лишние значения будут перезаписаны.

  12. # Maxim

    Ну вообщето так создавать массивы крайне не рекомендую. Лучше делать $array = array(‘blablabla’) – это лучще читается… Насчет объектов: Подозреваю что тебе на самом деле нужен не объект а хешь – массив с нечисловыми ключами – так в PHP все массивы являются одновременно и хешами – поэтому можно инициализировать такие массив как $array = array(‘key1’=>‘value1’,‘key2’=>‘value2’) и так далее. Соответственно в дальнейшем добавлять новые значения: $array[‘key3’] = «value2».

  13. # Тормоз

    $Aleks, теперь понял. Но всё равно register_globals включены только у идиотов, мне так кажется :) 21 век уже.

    Maxim, проблема не в том, нужен мне объект или хэш. Я о том, что в PHP к совершенно аналогичным данным доступ организован различным образом. Насчёт «лучше читается» — очень спорно и необъективно.

  14. # Ewg: 

    $obj->some->bla = 1
    Почему нет?

  15. # Тормоз

    Кстати, как вы думаете, почему об этом есть записи в баг-трекере PHP? Хотя людей там пытаются убедить, что это типа и не баг вовсе. А пишут в баг-трекер потому что это, блин, вообще не логичное поведение!

  16. # Ewg: 

    О чём «об этом»? Сам с собой опять…

  17. # Тормоз

    $obj->some->bla = 1
    Почему нет?

    $obj->some[‘bla’] = 1
    Вопрос в том, почему такой вариант не работает?

  18. # Тормоз

    Ewg, неужели так сложно понять? У кого-то PHP головного мозга уже, кажется :) О чём, о чём. Об этом, например, или о всё том же.

  19. # Ewg: 

    Не ArrayObject он

  20. # Тормоз

    Уфф. Ладно, пофиг. Надоело объяснять.

  21. # Ewg: 

    ArrayObject позволяет такой гкод порождать.

    Status: Bogus и Closed. PHP мозга – избыточная самокритика.

  22. # Тормоз

    ArrayObject реализует $obj['some']['bla'], но не $obj->some['bla'], насколько я понял. Так что не то. Или я не понял?

  23. # kp: 

    Тормоз, правильно поставить в начало скрипта

    ini_set(‘display_errors’, ‘on’);
    error_reporting(E_ALL);

    А потом смотреть из-за чего происходят notice или warning и как их исправлять.

  24. # kp: 

    $obj->some = array();
    $obj->some[‘bla’] = 1;

    или в описании класса

    var some = array();

  25. # Тормоз

    Kp, обижаешь :( И не вник в суть вообще.

    Зато я нашёл интересное решение — тоже не без недостатков, но реализует задуманное. Жаль, что простейшая вроде бы очевидная вещь снова в PHP делается через жопу.

  26. # aktuba

    Тормоз, вот из-за таких как ты, потом ругают php ;).

    $arr5 = new Obj;

    $arr5[] = ‘test’;

    Такой код, по твоему, будет нормальный?

  27. # Тормоз

    Ага, зато из-за таких как ты не любят PHPшников :) Нет, не нормальный. И тему можно закрыть, я просто высказал своё «фи».

    Ты, кстати, Aktuba оправдываешь различие в синтаксисе вроде как, но никто из оправдателей не смог объяснить, почему разработчики языка приняли такое решение. Отсутствие логики всегда трудно объяснить.

  28. # aktuba

    =). А я не оправдывал php, я дал понять, что если применять твою концепцию, то необходимо отказаться от скалярных типов вообще – тогда будет именно то, что тебе необходимо. По поводу причины данного синтаксиса – все просто, вспомни как развивался php и ДЛЯ ЧЕГО он был создан.

    P.S.: «фи» необходимо сказать тебе за комменты и за парсер комментов. Выше было так: $arr[ 5 ] = new Obj;

  29. # Тормоз

    «Фи» необходимо сказать тем, кто предпросмотр не использует по назначению :)

    тогда будет именно то, что тебе необходимо

    Попробуй внимательней перечитать, что именно мне не понравилось, вникни в суть. И тогда поймёшь, что твой пример — всего лишь ещё один вариант извращения в обход нелогичного поведения.

  30. # Чакки: 

    Чтобы было чем ночью заниматься.

    Кстати, интересная идея. Интересно будет поглядеть что и как, если такое на четвёртом дот нете реализовать через динамик.

  31. # aktuba

    >«Фи» необходимо сказать тем, кто предпросмотр не использует по назначению :)

    Серьезно? И что, предпросмотр поправит парсер? =)

  32. # Тормоз

    Предпросмотр показывает тебе, что получится в итоге, но ты не посмотрел, а потом ворчать начал. Да, в Textile квадратные скобки используются для сносок, извини уж.

  33. # mrkto: 

    Всё равно не понял, что тебе кажется нелогичным. Тогда ведь магический метод __get($name) должен был бы содержать ещё один аргумент (ключ массива), т.е. переменное количество аргументов (если ещё вложенные массивы) Отстутствие простоты, интуитивности.

    Разумеется свойство должно быть объектом/ массивом объектов. В данном случае типа ArrayObject.
    Здесь:
    // как в последнем примере только вместо ArrayObject наследуем от него класс, где
    class arr extends ArrayObject { function __get($n) { return $this[$n]; }
    }

  34. # Тормоз

    MrKto, да, вот тут ты прав.

    Я уже запутался, блин :( Вообще, в принципе синтаксис $bla->bla->bla симпатичней и удобнее, чем с квадратными скобками и кавычками. Посмотрю, пожалуй, как там в этом Zend Config сделано.

  35. # mrkto: 

    То есть я хотел сказать в первом примере: habrahabr.ru/blogs/p…

    class A { private $p; function __construct() { $this->p = new arr; } function __get($p) { return $this->p; } } $o = new A; $o->prop[‘key’] = 1; echo $o->prop->key;

  36. # Тормоз

    В твоём коде тоже нелогичность какая-то, блин. Присваиваем значение одним способом, а получаем совсем другим. Ну некрасиво же!

  37. # mrkto: 

    Вообще-то это специально :) Я же не переписал __set(): тестируем установку значения ArrayObject-ом, тестируем чтение переписанным __get()-от ArrayObject-а (т.е. arr-а)

  38. # Alex

    Конструкция типа $array[] = ‘blabla’ отвечает за добавление элемента в массив. Операция «добавить» для сущности «массив» вполне нормальная штука.

    Расширять динамически набор свойств класса, используя волшебные методы – очень не нормальная штука. Класс должен нести в себе некоторую абстракцию, инкапсулировать строго определенные методы и свойства. Расширяться они должны только с помощью таких вещей как наследование, иначе ты можешь нарушить абстракцию и в будущем попасть в очень не простое положение.

    Не расширяй динамически набор свойств класса – найди другое приемлимое решение.

  39. # Тормоз

    Alex, наверно ты прав. И спасибо всем остальным участникам этого обсуждения. Пожалуй, для своих задач всё же воспользуюсь реализацией ArrayObject.

  40. # mrkto

    В ООП-стиле, использование объекта для хранения конфига вполне логично, наверно.

    Вместо Zend-а, если подойдёт, можно использовать примерно такой формат конфига:

    config.php
    <?php
    return (object)array(‘contacts’ => (object)array(‘email’ => ‘q@w.com’, ‘title’ => ‘Страница контактов’)); ?>

    можно изменять конфиг и через web-интерфейс: mrkto.com/php_config…

    использование:
    $Site = include(‘config.php’);
    echo $Site->contacts->email;

    Также идея добавить настройки для каждого модуля (хотя это под вопросом):
    class Page_Contacts {
    function __construct() {
    foreach($GLOBALS[‘Site’]->contacts as $k=>$v) $this->$k = $v;
    }
    function show() {
    include(‘template/contacts.htm.php’); // внутри: <head><title><?=$this->title;?></title></head>
    }
    }

  41. # Тормоз

    В следующей заметке выложу на суд свой класс БД на файлах :) Продолжаю велосипедостроительство. Кстати, я бы может и не делал уже это, но обнаружил, что на хостинге, оказывается, PHP собран без поддержки SQLite, которую я хотел попробовать. Эх.

  42. # Clr

    «Почему в PHP так всё непоследовательно?» — есть мнение, что это было сделано специально: чёрный пиар — лучший пиар.
    Впрочем, я считаю, что это тот случай, когда не следует видеть в обычной дурости специальный умысел.

    aktuba
    «вот из-за таких как ты, потом ругают php»
    В этом месте мне вспоминается облетевшее рунеты изречение Навального: «*Вы не воруйте и тогда мне пиариться не на чем будет.*»
    Может не надо было язык через жопу проектировать, тогда и ругать было бы нечего?

    Alex
    «Класс должен нести в себе некоторую абстракцию, инкапсулировать строго определенные методы и свойства. Расширяться они должны только с помощью таких вещей как наследование, иначе ты можешь нарушить абстракцию и в будущем попасть в очень не простое положение.»
    Кому класс должен? Кому методы должны? ООП головного мозга?
    Код должен решать поставленную задачу, при чём, делать это наболее прямым образом, как можно ближе к терминам предметной области. А если язык заставляет спотыкаться о квадратные скобочки, тут уже не до рассуждений на уровне предметной области, с таким синтаксисом. Хороший синтаксис как хороший дизайн — должен быть не заметен эндюзеру в работе.

  43. # Clr

    aktuba
    «я дал понять, что если применять твою концепцию, то необходимо отказаться от скалярных типов вообще»
    о_О А можно раскрыть тему? При чём тут скаляры?

  44. # Тормоз

    Clr, думаю, Актюба имел в виду «не нужно смешивать массивы и строки в свойствах объекта». Хотя почему — не ясно. Это удобно было бы.

  45. # Clr

    Это еще менее понятно. Ну то есть, вообще никак не понятно. :)

  46. # Бутылк.Ус

    21 век…
    Я, как очень долго и давно начинающий быдлокодер, лишний раз убеждаюсь, что ООП от лукавого…
    В задницу это ваше шаманство, функциями обойдусь… Не суперэффективно, но хотя бы алгоритм очевиден и код читабелен даже в индия-стайл… Но это я так, к слову, не обращайте на меня внимания =)

    А, да…Тормоз, а __set() ведь вроде как общий для всех метод? И как же ты его планируешь менять, если он всегда перегружен? И надо ли?

  47. # Бутылк.Ус

    Ой-ой-ой, забыл сказать!!!1111
    Если нужжен хорошая стабильная и быстрая реализация SQL-подобной базы на текстовых файлах – обрати свое внимание на Limbo. ЦМСка такая. у меня на файлах один сайт до сих пор хреначит. На высоких нагрузках (хостинг для примитивных сайтов, не самый мощный сервак), то есть порядка 5 обращений в секунду, почти не тормозит.

  48. # Тормоз

    Мне не нужна SQL-подобная база, скорее простое key-value хранилище. Насчёт «ООП от лукавого» — ты просто ещё не дорос до этого. И не читал хороших книг по теме :)

  49. # Evgeny Sergeev

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

    А что мешает сменить язык? И покажите, если не трудно, язык у которого нет недостатков в скобочках. :-)

    Тормоз, и как ты находишь такие узкие места PHP? :-)

  50. # Тормоз

    Ну уж не специально.

  51. # Clr

    @Evgeny Sergeev

    «А что мешает сменить язык?»
    Не ко мне вопрос. Я не использую PHP.

    «И покажите, если не трудно, язык у которого нет недостатков в скобочках.»
    JavaScript, Python, Ruby. Особенно Ruby. Наиболее последовательный синтаксис, нет тупых ограничений а ля «а вот тут нам стало лень дописывать парсер, поэтому берите в зубы костыль — и вперёд с песнями».

  52. # Evgeny Sergeev

    Clr, у PHP проблема не в том, что «А вто тут нам стало лень…». Основная сложность в том, что нельзя потерять обратную совместимость с более ранними версиями языка.
    Руби – классный язык, но к сожалению проигрывает PHP в плане популярности. Сейчас продать скрипт на руби сложнее чем на PHP.

  53. # Тормоз

    Поэтому стоит отходить от продажи скриптов в сторону SaaS :)

  54. # Clr

    «у PHP проблема не в том, что «А вот тут нам стало лень…». Основная сложность в том, что нельзя потерять обратную совместимость с более ранними версиями языка.»
    Интересно, что мешало сразу делать по-человечески? Я вам скажу, что: «шаблонизатор для подстановки переменных в HTML, изначально написанный на Перле» — такое по определению не может быть хорошим языком. Ну то есть, чудеса иногда случаются, но PHP — явно не тот случай.
    Основная проблема PHP в том, что когда появилась достаточно сильная потребность в языке для веба, этим языком стал PHP.

    Что касается обратной совместимости, то вы дважды не правы. Во-первых, погуглите php backward incompatible changes. Во-вторых, есть куча вещей в языке, которые можно исправить без нарушения обратной совместимости.

    Совместимость с чем мешает дописать парсер:

    function qwerty() {return array(‘a’, ‘b’, ‘c’);}
    echo qwerty()[ 0 ];
    Parse error: syntax error, unexpected ‘[’, expecting ‘,’ or ‘;’

    echo array(‘a’, ‘b’, ‘c’)[ 0 ];
    Parse error: syntax error, unexpected ‘[’, expecting ‘,’ or ‘;’

    Совместимость с чем мешает запилить в язык нормальную библиотеку классов:

    $a = array(‘a’, ‘b’, ‘c’)[ 0 ];
    $a->merge(array(‘d’, ‘e’, ‘f’));
    Fatal error: Call to a member function merge() on a non-object

  55. # aktuba

    2Clr:
    >Может не надо было язык через жопу проектировать, тогда и ругать было бы нечего?

    назови хоть один язык программирования, который не ругают ;)

    >о_О А можно раскрыть тему? При чём тут скаляры?

    имелось в виду, что если отказаться от массивов (да и вообще от других типов), оставив только классы – будет одинаковое обращение ко всем, чего и хотел добиться Тормоз:

    class Config extends Arr {}

    $config = new Config;
    $config -> db -> username = ‘root’;
    $config -> main -> 5 = 123;

  56. # Тормоз

    Всё же подозреваю, что с объектами и субобъектами возникнут проблемы производительности. В частности перебор элементов ArrayObject в десять и более раз медленней, чем перебор элементов массива.

  57. # Clr

    «назови хоть один язык программирования, который не ругают ;)»
    Ок, начинай ругать синтаксис JavaScript или Ruby. Речь, напомню, идёт конкретно о синтаксисе. Какие нелепые ограничения есть в JavaScript, которых нет в PHP?

    «имелось в виду, что если отказаться от массивов»
    о_О
    Во-первых, массивы — никаким боком не скалярные типы. Даже специально посмотрел в справочник: вдруг у авторов PHP своё понимание слова скаляр, отличающееся от нормативного. Но нет, всё правильно: Scalar variables are those containing an integer, float, string or boolean.
    Во-вторых, какие-то отдельные от классов «типы данных» существуют только в голове разработчиков PHP. Класс — не более чем абстракция из связки структуры данных и набора функций для её обработки. То, что в PHP у массива нельзя вызвать метод — огромная нелепость, в основе которой лежит то, что PHP хочет притворяться ООП языком, хотя таковым не является. Подобное оправдано в Си++, потому что его наживую прикручивали к Си и потому что там из соображений производительности специально отказались от единой иерахии классов. В скриптовых же языках это просто дурость как она есть, ограничивающая мощь и выразительность языка.
    В-третьих, твой первый пример был такой:
    $arr[ 5 ] = new Obj;

    $arr[ 5 ][] = ‘test’;
    И это, да, был бы нормальный код. Не понятно, что тебе не нравится. Вызов $arr[ 5 ][] = ‘test’ внутренне транслировался бы в что-то типа $arr[ 5 ]->__add_value(‘test’), и благодаря этому работал бы и с со стандартными массивами, и с объектом типа Obj, если в нём такой метод определён.

  58. # aktuba

    >Ок, начинай ругать синтаксис JavaScript или Ruby. Речь, напомню, идёт конкретно о синтаксисе.

    Не передергивай =). Речь идет о проектировании языка, а не о его синтаксисе. JS могу ругать сутками – намучился с ним. Но ведь это не означает, что язык говно – это означает, что я не смог им правильно воспользоваться. Ruby ругать не могу – не знаю его и знать не хочу.

    >То, что в PHP у массива нельзя вызвать метод — огромная нелепость

    Чего??? Сам-то понял что сказал? У массива (данные!) вызвать метод. Какой нафиг тогда ООП? =)

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

    Вот с этого места начинаю крыть матом JS =). Особенно про «выразительность языка».

    >И это, да, был бы нормальный код. е понятно, что тебе не нравится

    Серьезно? Мне не нравится смешивание данных и методов обработки данных. Мне не нравится, что с ДАННЫМИ работают как с объектами. Перенести данные о товарах в поезде – это одно, а перенести все товары, вместо данных – это другое.

    P.S.: спасибо, кстати. еще раз убедился, что связываться с руби – это зло.

  59. # Тормоз

    Чего??? Сам-то понял что сказал? У массива (данные!) вызвать метод. Какой нафиг тогда ООП? =)

    А что такого? Объект — это совокупность данных и способов сделать с ними что-нибудь. Это ООП, да. Не знал? :)

    спасибо, кстати. еще раз убедился, что связываться с руби – это зло.

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

  60. # aktuba

    >А что такого? Объект — это совокупность данных и способов сделать с ними что-нибудь. Это ООП, да. Не знал? :)

    Верно. А теперь прочти еще раз. Объект может работать с данными, а не данные с объектом. Верно? ООП = Объектно-ориентированное, а не данные-ориентированнно.

    >Троллишь так, или на самом деле выводы о языке делаешь по паре высказываний одного из пользователей? Впрочем, в обоих случаях глупость, а во втором ещё и не смешная.

    Ни разу. Это не первый человек, программирующий на руби, пытающийся научить всех использовать ООП. И всегда одно и тоже – возвращение к бейсику, где не было вообще никаких ограничений. За «глупость» – спасибо.

  61. # Тормоз

    Не обижайся. Ты же знаешь, что я бываю резковат, да и ты тоже :) Про работу данных с объектами нифига не понял, что ты имел в виду?

    А с рубистами не удивительно вообще-то, у Ruby вообще вся парадигма насквозь ООП-ориентированная, там всё — объект. Странно осуждать их за это.

  62. # Clr

    «Речь идет о проектировании языка, а не о его синтаксисе. JS могу ругать сутками – намучился с ним.»
    Ок, давай о проектировании языка в целом.
    Вот конкретные проблемы JS в области семантики:

    • Кривой механизм областей видимости переменных.
    • Кривая семантика объявлений по var, связанная с тем, что переменная реально объявляется в момент входа в функцию, а не по время исполнения оператора var.
    • Неразличение собственных и унаследованных от прототипа свойств при перечислении в for-in цикле.
    • Перегрузка операции ‘+’ и отсутствие отдельной операции конкатенации.

    В области синтаксиса:

    • Semicolon insertion — ад.
    • Нет способа кратко записывать лямбды и замыкания, приходится каждый раз писать длинное function() {return …

    Всё это, конечно, иногда раздражает, но не идёт ни в какое сравнение с проблемами PHP.

    «Вот с этого места начинаю крыть матом JS»
    Так что не кроешь-то?

    «Чего??? Сам-то понял что сказал? У массива (данные!) вызвать метод. Какой нафиг тогда ООП? =)»
    Это ж нифига, какая каша у человека в голове. Уважаемый, вам на чём-нибудь, кроме PHP, доводилось писать вообще? На приплюснутых Сях, например. Почитай документацию по контейнерам STL — тогда с таким представлением об ООП вообще в ужасе будешь. Офигеть: них, натурально есть методы. И даже более того, вызов квадратных скобочек для получения элемента массива по индексу — всего лишь синтаксический сахар, транслирумый компилятором в вызов соответствующего метода.

    Открою страшную тайну, есть такая абстракций: контейнер объектов, адресуемых по индексу. Эта абстракция называется массив. И разумеется, у неё есть методы: получить диапазон элементов, получить длину массива, сортировать, фильтровать, удалить, добавить. Самые обычные такие методы.
    А у класса строк есть другие методы, например, замена по регулярке:
    result = template.gsub(/<([a-zA-Z0-9]+)>/) do |s| node.property($1); end
    result = result.gsub(/<%%((.|\n|\r)*?)%%>/) do |s| eval($1); end

    А у класса целых чисел есть методы сложения, умножения, вычисления остатка и т.п.

  63. # Clr

    «И всегда одно и тоже – возвращение к бейсику, где не было вообще никаких ограничений.»
    Made my day. Сравнить Руби с басиком — это сильно. Ты бы еще Лисп с басиком сравнил.
    Интересно, ты бейсик вообще видел, или так, ради красного словца этоо покойника вспомнил?

    Да-да, ограничения имеют высший смысл. Это не какие-то там заскоки к разрабов шаблонизатора для PHP, разбиравшизся в проектировании ЯП примерно так же, как ты. Это очень концептуально важные ограничения, и тебе открыт их высший смысл.
    Удачи в программировании а ля
    array_sort(array_merge(array_ filter(…еще( 10( вложенных( функций(…))))))
    Когда дойдёт, что это на самом деле банальные методы контейнера объектов, можешь считать, что с уровня программирования на бейсике ты поднялся на следующую ступень.

  64. # aktuba

    >Так что не кроешь-то?

    А смысл?

    >Это ж нифига, какая каша у человека в голове. Уважаемый, вам на чём-нибудь, кроме PHP, доводилось писать вообще?

    asm, c, c++, delphi, php – примерно такой путь прошел. параллельно питон, js, lisp совсем немного и пр. есть с чем сравнить. поэтому и сказал – назови хоть один язык, который не ругают.

    По поводу «страшной тайны» – давай ближе к истокам. Что из себя представляет массив объектов? Правильно – список ссылок на объекты. И не более того. И это не абстракция. Абстракцией массив сделали в нескольких языках (в питоне вообще отказались от массива, используют кортежи, списки и словари). Но, раз уж говорим о php, то надо и брать именно то, как организованно в нем: массив – это не объект!

    У кого еще каша в голове ;)

    >Не обижайся. Ты же знаешь, что я бываю резковат, да и ты тоже :)

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

  65. # Clr

    Fixed: шаблонизатора для HTML

  66. # Clr

    «И это не абстракция.»
    Массив — это контейнер. Контейнер — это абстракция. Неабстракцией он станет, когда ты будешь биты по байтам вручную гонять на ассемблере.
    Немедленно читать теорию структурного программирования!

  67. # aktuba

    >Интересно, ты бейсик вообще видел, или так, ради красного словца этоо покойника вспомнил?

    Ну что-за привычка ставить себя выше других? =) Из-за руби такая манера или это никак не связанно?
    На БК не было ничего, кроме бейсика и фокала. Да и на 8086 кроме асма был только бейсик тогда. Потом уже паскаль где-то отыскал.

    >Когда дойдёт, что это на самом деле банальные методы контейнера объектов, можешь считать, что с уровня программирования на бейсике ты поднялся на следующую ступень.

    Спасибо «великий гуру».

    >Массив — это контейнер.

    Мдя… Действительно – «Немедленно читать теорию структурного программирования!» Массив, скорее коллекция, а не контейнер. Со своим руби уже не знаете, куда засунуть определения простых вещей.

  68. # Тормоз

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

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

  69. # aktuba

    Тормоз, заметь: хоть мы и спорим с Clr и подначиваем друг-друга, но это не звучит оскорбительно.

  70. # Тормоз

    Ну хорошо, молодцы :)

  71. # Clr

    «Из-за руби такая манера или это никак не связанно?»
    Это из-за того, что когда человек проводит подобные аналогии между автомобилем и старой клячей, разумно усомниться, а видел ли он старую клячу.

    «Массив, скорее коллекция, а не контейнер.»
    А коллекция — контейнер. «Со своим PHP уже не в состоянии понять отношение is_a между двумя понятиями», так что ли?

  72. # Alex

    Цитата (Clr):
    Кому класс должен? Кому методы должны? ООП головного мозга?
    Код должен решать поставленную задачу, при чём, делать это наболее прямым образом, как можно ближе к терминам предметной области

    Сравните:

    вариант 1:
    $code = $config->system->languages->code;

    и

    вариант 2:
    $code = $config->get(«system/lanuages/code»);

    Оба куска кода решают задачу в терминах предметной области, но первый из них использует «особенности» языка PHP для динамического расширения набора свойств класса, чтобы просто эмулировать синтаксис, который нравится автору. Причем читающему код может быть неочевидно, что внутри класса используются магические методы.

    Второй вариант легко читается и имеет строго очерченную абстракцию. Причем, он способен разделять операции, которые можно произвести с настройками: чтение (get), запись (set), проверка существования (check). Эти операции и составляют абстракцию класса настроек в терминах предметной области.

  73. # Clr

    Первый способ представляет конфиг таким, какой он есть: в виде иерархического дерева свойств. Второй — в виде списка не связанных друг с другом параметров.
    В первом можно взять $config->system->languages и просто передать в функцию, которая принимает, любой перечислябельный контейнер. Во втором придётся либо вручную крутить циклы для сбора нужных значений, либо дополнять интерфейс неочевидными методами выборки группы объектов.
    Первый вариант парсится самим языком, во втором необходимо писать простейший, но парсер.
    В первом случае можно легко строить пространство конфигурации из разных источников, в том числе, подключая виртуальные вычисляемые на ходу элементы. Во втором для этого придётся вручную анализировать пути и заводить еще одно неочевидное API.

  74. # Alex

    Цитата (Clr)
    В первом можно взять $config->system->languages и просто передать в функцию, которая принимает, любой перечислябельный контейнер. Во втором придётся либо вручную крутить циклы для сбора нужных значений, либо дополнять интерфейс неочевидными методами выборки группы объектов.

    Во втором варианте тоже можно передавать в любой контейнер:

    $subConfig = $config->get(»/system/languages»);

    $code = $subConfig->get(»/code»);

    и передавайте $subConfig в любой контейнер.

    Цитата (Clr)
    Первый вариант парсится самим языком, во втором необходимо писать простейший, но парсер.

    Фактически реализация магического метода в первом варианте и реализация метода get во втором варианте примерно одинаковы по объему и сложности. Но магический метод нарушает абстракцию, не очевиден и запутывает реализацию.

    Цитата (Clr)
    В первом случае можно легко строить пространство конфигурации из разных источников, в том числе, подключая виртуальные вычисляемые на ходу элементы.

    Объясните подробнее, почему Вы не сможете сделать это красиво без магических методов?

    Цитата (Clr)
    Во втором для этого придётся вручную анализировать пути и заводить еще одно неочевидное API.

    Анализ путей во втором случае не намного сложнее, чем написание магического метода. И второй вариант не вызовет проблемы типа «Indirect modification of overloaded property», которая и послужила причиной этого топика.

  75. # Clr

    Вы 2-й раз пишете про нарушение абстракции:
    «Расширяться они должны только с помощью таких вещей как наследование, иначе ты можешь нарушить абстракцию и в будущем попасть в очень не простое положение.»
    «Но магический метод нарушает абстракцию»
    Чёрт возьми, покажите конкретный пример, что вы имеете ввиду.

    «Объясните подробнее, почему Вы не сможете сделать это красиво без магических методов?»
    Ок, всё делается красиво, только зачем-то вводятся лишние промежуточные слои.
    Давайте посмотрим: концептуально нам нужен парсер, чтобы делить путь на фрагменты и резолвер для прохода по пути к конечному элементу. Итого, в конечном счёте всё сводится к вызовам приватных функций а ля getChild и setChild.
    Спрашивается: раз задача прекрасно описывается средствами самого языка, зачем вам этот промежуточный слой, который добавляет новое API, но не добавляет никакой функциональности и не упрощает абстракцию. Выкидываем ваши get и set, обеспечивающие парсинг пути, оборачиваем getChild и setChild в магические методы и получаем, собственно, первый вариант. Впрочем, ничего не мешает иметь и пару методов get/set для парсинга путей. Возможно даже в различных вариантах синтаксисов записи путей, если такая задача возникнет.
    Но, я считаю, писать $config->get(»/some/path»), когда в программе надо просто получить $config->some->path — это из разряда «а мне нравится лишние скобочки и кавычки набирать, потому что мы так в компилируемых Сях++ привыкли».

    «И второй вариант не вызовет проблемы типа «Indirect modification of overloaded property», которая и послужила причиной этого топика.»
    Вы говорили не особенностях PHP, а о, конкретно, ООП: класс должен, методы должны. Объясните, почему должны.
    То, что в PHP есть свои особенности, мы и так все знаем.

  76. # Alex

    Цитата (Clr)
    Чёрт возьми, покажите конкретный пример, что вы имеете ввиду.

    Немного повторюсь. Абстракция класса настроек может заключаться в том, что:

    • настройка может быть считана по ключу (get, один параметр – ключ),
    • может быть изменена по ключу (set, два параметра – ключ + значение) и
    • может быть проверена на наличия ключа (check, один параметр – ключ).

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

    Цитата (Clr)
    Ок, всё делается красиво, только зачем-то вводятся лишние промежуточные слои.

    Вы разбиваете и группируете код, собираете его в методы, которые удобно тестировать и сопровождать. Это сейчас называется «лишние промежуточные слои»? :)

    Цитата (Clr)
    Выкидываем ваши get и set, обеспечивающие парсинг пути, оборачиваем getChild и setChild в магические методы и получаем, собственно, первый вариант

    Да, об этом я и говорю – реализация по сути одинаковая, в одном случае две функции обернутые в магические методы, в другом – get/set.

    Цитата (Clr)
    Но, я считаю, писать $config->get(»/some/path»), когда в программе надо просто получить $config->some->path — это из разряда «а мне нравится лишние скобочки и кавычки набирать, потому что мы так в компилируемых Сях++ привыкли».

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

    Цитата (Clr)
    Вы говорили не особенностях PHP, а о, конкретно, ООП: класс должен, методы должны. Объясните, почему должны.

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

    Поймите, я не собираюсь менять Ваш взгляд. Но так же есть альтернативные способы решения задач, они могут быть надежны и применимы. Быть может Вам стоит перестать мыслить категориями «нравится лишние скобочки», а обратить внимание на более измеряемые качества, нежели любовь/ненависть к С++ и любовь/ненависть к скобкам?

    Я не отрицаю, что тот способ, который Вы предлагаете достоин пременения, я просто показываю на его недостатки. И показываю на них не потому, что «мы так в компилируемых Сях++ привыкли», а потому, что эти недостатки есть в реальности.

  77. # Clr

    «Внутрненнее устройство класса настроек скрыто (от него абстрагируемся), а оперируем только тремя публичными методами с четко определенными параметрами. Вот это и есть пример простой абстракции для класса настроек.»

    Наплодить по отдельному интерфейсу на каждый чих, которые отличаются только своим назначеним в голове программиста? В чём профит: в запоминании еще пачки методов, делающих то же самое, но под другим именем?
    В принципе, тут уже не далеко до озвученной выше точки зрения, что контейнеру не нужны методы — он же не абстракция предметной области, он, тупо, контейнер. Вот если его завернуть в класс и присобавить кустомные геттеры и сеттеры — это дааа, будет абстракция.
    Кстати рассматриваемый пример тоже по своей сути «тупо контейнер», реализация доступа к нему через интерфейс ассоциативного массива имеет все права на существование.

    «Я надеюсь, вполне понятно, что Вы свободный человек относительно свободной страны и конкретно Ваши классы и Ваш код не обязан быть написан в соответствии с тем, что я написал выше. Я не навязываю Вам свою точку зрения – пожалуйста, не ограничивайте себя и используйте особенности PHP на полную катушку.»

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

    «Быть может Вам стоит перестать мыслить категориями «нравится лишние скобочки», а обратить внимание на более измеряемые качества, нежели любовь/ненависть к С++ и любовь/ненависть к скобкам?»

    Вы не показали ни одного измеряемого качества, обращать внимания не на что. В условиях, когда оба способа абсолютно развнозначны алгоритмически, я выбираю тот, который проще интерфейсно и удобнее в использовании. А вы?
    О любви/ненависти, кстати, речи не шло, речь шла по привычке из компилируемых языков использовать «вшитые» константы. Ведь семантика Си++ не позволяет динамически обработать имя метода.

    «Я не отрицаю, что тот способ, который Вы предлагаете достоин пременения, я просто показываю на его недостатки.»
    Ни единого недостатка вы не озвучили. Если бы вы хотели назвать реальные, а не мнимые недостатки решения через магические методы и декораторы, вы бы упомянули, например, неочевидность/невозможность сделать проверку существования пути без явных проверок существования родительских каталогов и без шанса нарваться на исключение. Ну и т.п. Вы же носитесь с «нарушением абстракции» как с писаной торбой.

  78. # Evgeny Sergeev

    clr, чего-то никак в толк взять не могу, Вы согласны с тем, что магические методы нарушают абстракцию или нет?

  79. # Clr

    Не согласен. Я бы, возможно, смог с вами согласиться, если бы хоть как-то аргументировали свою точку зрения.

  80. # Evgeny Sergeev

    Clr, тогда еще один маленький вопрос – а что такое нарушение абстракции в Вашем понимании?

  81. # Alex

    Цитата (Clr)
    Вы не показали ни одного измеряемого качества, обращать внимания не на что

    Ок. Давайте смотреть на измеряемые качества. Чтобы не быть голословным, не брать параметры с потолка, воспользуемся каким-нибудь объективным источником, например, обратимся к книге С. Макконела «Совершенный код» (2007 год). Если у Вас есть другой объективный источник, можно взять его.

    Страница 154. Контрольный список: качество классов.
    Из списка я пока убрал пункты, отвечающие за взаимодействие с другими классами и один пункт по именованию самого класса.

    Критерий Вариант с магическими методами Вариант без магических методов
    Является АТД – (*1) +
    Абстракция
    Имеет главную цель + +
    Согласованный уровень абстракции +/- +
    Интерфейс ясно описывает использование класса – (*2) +
    Достаточно ли абстрактен, чтобы не думать о реализации – (*3) +
    Достаточно ли полон набор сервисов класса, чтобы не обращаться к внутренним данным +/- (*4) +
    Исключена ли нерелевантная информация + +
    Сохраняется ли целостность интерфейса при изменении класса ? (*2) +
    Инкапсуляция
    Сделаны ли члены класса минимально доступными +/- (*4) +
    Избегает ли класс доступа к своим данным-членам +/- (*4) +
    Скрывает ли класс детали реализации +/- (*3) +
    Избегает ли класс предположений о своих клиентах +/- (*3) +
    Независим ли класс от других классов? Слабо ли он связан? + +

    (*1) Не определены даже операции
    (*2) Интерфейса в виде набора методов у класса нет, необходимо писать документацию, чтобы было понятно, что доступ к элементам настроек идет через произвольный доступ к свойствам, которые в свою очередь дергают магические методы, которые уже обрабатывают запросы.
    (*3) При работе с этим классом приходится думать о том, что запись идет не напрямую в свойства класса, а обрабатывается через магические методы.
    (*4) Если косвенное обращение к магическим методом через свойства считать за вызов операции, то можно зачесть +.

    О других преимуществах второго метода писал выше, если необходимо повторюсь.

    Цитата (Clr)
    О любви/ненависти, кстати, речи не шло, речь шла по привычке из компилируемых языков использовать «вшитые» константы

    Вы писали:
    Но, я считаю, писать $config->get(»/some/path»), когда в программе надо просто получить $config->some->path — это из разряда «а мне нравится лишние скобочки и кавычки набирать, потому что мы так в компилируемых Сях++ привыкли».

    Это про вшитые константы?

    Цитата (Clr)
    неочевидность/невозможность сделать проверку существования пути без явных проверок существования родительских каталогов и без шанса нарваться на исключение. Ну и т.п. Вы же носитесь с «нарушением абстракции» как с писаной торбой.
    Ну вот видите, Вы сами указываете на недостатки. Я писал выше про операцию check и про ее фактическое отсутсвие в варианте с магическими методами.

  82. # Idler

    Просто привет Тормозу хотел передать… а тут такое…. короче приподсел втыкать на несколько дней.

  83. # Тормоз

    ))

  84. # Evgeny Sergeev

    Alex, хе… мне явно надо перечитать Макконела!

  85. # Тормоз

    Перечитал ещё раз всю перепалку. Ухх, ну вы, блин, даёте! Спасибо, настроили мозги на нужную волну. А то давно нормально не программировал, и вот как раз снова вернулся к этой своей до сих пор не решённой красиво задаче файловой БД…

Комментирование этой статьи закрыто.

Интересное Покупки ТехникаРазное Отдых Статьи Строительство Услуги Общество Хобби Культура Советы Уют