Вы видите копию треда, сохраненную 21 декабря 2017 года.
Скачать тред: только с превью, с превью и прикрепленными файлами.
Второй вариант может долго скачиваться. Файлы будут только в живых или недавно утонувших тредах. Подробнее
Если вам полезен архив М.Двача, пожертвуйте на оплату сервера.
Пожалуйста, пишите один большой пост вместо нескольких маленьких и не флудите не по теме.
Это тред для начинающих. Не написал за свою жизнь ни одной программы и имеешь тройку по математике? Ты наш человек.
Предыдущий тред был тут: >>1082507 (OP). Еще предыдущие треды ищутся в гугле по словам "клуб изучающих php" или в архиваче.
Мейлач лежит? Есть запасной тред на доброчане: /s/res/23225.xhtml#i46467
Что самое главное для программиста? Умение аккуратно оформлять код (как, написано во втором посте).
Правила: ведем себя воспитанно, помогаем новичкам, читаем учебники, решаем задачки, постим ссылки на решения, ОП их проверяет и дает советы и замечания. ОП заходит редко, где-то раз в 2-3 дня, у него мало времени, не жди его, решай задачки дальше. ОП отвечает на все вопросы по его задачкам и учебнику, а вот насчет каких-то других вещей - только если останется время. Но в треде немало анонимных экспертов разного уровня, так что вряд ли вопрос останется без ответа.
С чего начать
У нас есть свои уроки по основам PHP, они собраны и выложены по адресу http://archive-ipq-co.narod.ru/ Это учебник для изучающих с нуля, то есть если ты вообще ничего не знаешь, то можно начать с него. Он простой и понятный. Там есть задачи, их нужно решать (чтобы стать программистом, надо писать код — иначе никак). Пости ссылки на решения в тред, мы их проверим, напишем замечания и дадим советы по улучшению. С другой стороны, если этот учебник тебе не нравится, можно читать любой другой. Или официальный мануал. Или все сразу.
Устанавливать пока что ничего не требуется, разве что редактор кода вроде Sublime Text 3, Notepad++, Visual Studio Code, Netbeans PHP или PhpStorm (с ним будет удобнее).
Если не знаешь как решать, запости код, напиши в каком месте остановился и попроси подсказку.
Ты прошел весь учебник? Молодец, но это были лишь основы языка PHP, этого недостаточно. Вот что в идеале надо изучить еще: ООП, как работает веб-сервер, HTML/CSS, SQL, PDO, работа с таблицами в БД, работа с формами, MVC, git, composer, JS, фреймворки, автоматизированное тестирование.
Надо переходить к более серьезным задачкам, которые научат тебя всему этому.
- для начала прочти урок https://github.com/codedokode/pasta/blob/master/soft/web-server.md
- установи Апач + PHP (советы выше и ниже) и читай туториал http://php.net/manual/ru/tutorial.php
- Учи HTML/CSS и SQL, PDO, хотя бы основы
- Далее простая, но полезная задача сделать список студентов, в ней много полезных советов: https://github.com/codedokode/pasta/blob/master/student-list.md
- Более сложная задача сделать файлообменник на микрофреймворке Slim: https://gist.github.com/codedokode/9424217
- Еще более сложная и долгая задача на Yii/Symfony: https://gist.github.com/codedokode/8733007
- После нее можно изучать автоматизированное тестирование https://gist.github.com/codedokode/a455bde7d0748c0a351a
- Если ты все решил, переходи к Symfony 3/Doctrine 2
- Почитать про паттерны http://designpatternsphp.readthedocs.org/ru/latest/README.html (если ты не изучил ни одного фреймворка, то это будет рановато), тут с примерами кода http://designpatternsphp.readthedocs.org/ru/latest/README.html . Имей в виду что без примеров использования их учить бесполезно - не поймешь, хочешь увидеть примеры использования паттернов - ковыряй исходники Симфони, например Symfony Forms. Не заучивай паттерны - смотри код и думай, зачем тут они использованы.
Чтобы делать эти задания, тебе надо установить Апач + PHP (можно заодно сразу и MySQL) на компьютер. Вот полезные инструкции:
https://github.com/codedokode/pasta/blob/master/soft/php-install.md
https://github.com/codedokode/pasta/blob/master/soft/apache-install.md
Может тебе понадобится пользоваться командной строкой, вот гайд https://github.com/codedokode/pasta/blob/master/soft/cli.md
Решения задач лучше показать мне, особенно на ООП,так как сам ты вряд ли увидишь все ошибки. Пости свой код на гитхаб и вкидывай ссылку в тред по мере решения. Я прокомментирую и укажу на ошибки.
Также, у нас есть задачи которые позволят тебе изучить или подтянуть до нормального уровня знания JS/HTML/CSS/SQL. Решай их параллельно с задачами выше.
- HTML/CSS: https://github.com/codedokode/pasta/blob/master/html/html.md
- JS: https://gist.github.com/codedokode/ce30e7a036f18f416ae0
- SPA (сложно): https://github.com/codedokode/pasta/blob/master/js/spa.md
- Проверялка решений на JS: http://dkab.github.io/jasmine-tests/
- MySQL: https://github.com/codedokode/pasta/blob/master/db/databases.md
Что почитать
- Мануал по PHP — http://www.php.net/manual/ru/langref.php
- Сайт phptherightway (перевод на русский: http://getjump.me/ru-php-the-right-way/ )
- По PHP: Профессиональное программирование на PHP Джордж Шлосснейгл
- По PHP: Мэтт Зандстра — PHP: Объекты, шаблоны, методики программирования
- JS: learn.javascript.ru
- Про Git: https://git-scm.com/book/ru/v1
Оформляй код аккуратно!!! — например пропусти через phpformatter.com . Также, если ты пользуешься IDE вроде PhpStorm, Netbeans, Eclipse, то в них эта опция встроена, подробнее: https://gist.github.com/codedokode/8759492
У ОПа нет аккаунтов и групп вконтакте, в фейсбуке, в твиттере, все "пхп-треды" там поддельные.
Платиновые вопросы
- Почему PHP? Потому что вакансий море, и учить легко.
- Сайт опять упал!!!!! — Не паникуй, а открой http://rghost.ru/6bfCY9lfl и получи личную немного устаревшую оффлайновую копию сайта (можно читать хоть на андроиде без интернета)
- Что надо знать чтобы найти работу - разработчику: PHP, SQL, HTML/CSS, JS, ООП, Git, композер, MVC, фреймворк. Верстальщику - HTML/CSS, JS, jQuery. У нас в треде были люди, которые практически с нуля учились и смогли найти работу.
- Что будут спрашивать на собеседовании если 0 опыта - гонять по теории, по официальному мануалу PHP, давать дурацкие задачки на переворачивание строк, гонять по SQL (транзакции, внешние ключи, напиши запрос), по JS (как сделать анимацию при нажатии кнопки), ну погугли, не ленись
- Можно подробнее про поиск работы, собеседования - нет, ОП писать не будет, но может кто из анонов захочет рассказать. Поищите тред перезвонивших, а также раздел /wrk/
- Сколько времени надо изучать все это? - все зависит от тебя, но не меньше 6-8 месяцев
- Нужен ли ООП, фреймворки, MVC, git, composer? — Да, однозначно. Посмотри любую вакансию.
Если тебе лень выравнивать код руками, закачай его на http://beta.phpformatter.com/ и нажми «format». Робот исправит выравнивание и отступы в мгновение ока (да, прогресс не стоит на месте). Если ты используешь мощную IDE вроде PhpStorm, там тоже есть функция форматирования кода.
Горячие клавиши для форматирования кода в разных IDE: https://gist.github.com/codedokode/8759492
Вообще, в PHP долгое время не было единого стандарта оформления кода, все писали как попало и было много бардака, но сейчас дело лучше — есть стандарты PSR-1 и 2. Вот как надо оформлять код:
- переменные и функции пишутся с маленькой буквы, подчеркивание не используется, используется camelCase, пример: $x, $numberOfPeople, printResults()
- Название функции начинается с глагола, в стиле «сделайЧтоТо»
- не знаешь английский? Не беда, в 21 веке есть решение этой проблемы. Не пиши транслитом, открой лучше Гугл Транслейт или slovari.yandex.ru и найди название для переменной там
- в именах классов используется CamelCase, первая буква большая, «_» может использоваться
- мы предпочитаем подстановку переменных вместо конкатенации строк: "I am $age years old" — хорошо, 'I am ' . $age . ' years old' — плохо из-за обилия точек и кавычек
- мы используем для отступов 4 пробела (можно настроить редактор, чтобы при нажатии Tab он вставлял 4 пробела)
Вот ссылка на стандарты, где все это описано подробнее и даны примеры оформления:
PSR-1: https://github.com/samdark/fig-standards-ru/blob/master/accepted/ru/PSR-1-basic-coding-standard.md
PSR-2: https://github.com/samdark/fig-standards-ru/blob/master/accepted/ru/PSR-2-coding-style-guide.md
Это направляющие (guides). Погугли по словам "photoshop guides", есть кнопки и пункт меню для их отключения.
Есть у меня на обслуживании проект, полностью написанный в стиле php4. Даже html кое-где вперемешку с кодом.
Позавчера вздумалось мне переставить на сервере с этим проектом php, с 5.6 прыгнуть на 7.1. Прочитал все статьи про миграцию с 5.6 на 7.0 и с 7.0 на 7.1 на php.net, убедился, что ничего не сломается, обновил php.
Проверил логи - ничего не сыпется. Потыкал сайт, все работает, красота. Хотя ой. Почему-то пара запросов оборвались - сервер рвет соединение, будто php падает. В логах пусто. Рестарт апача еще раз, потыкал-потыкал, вроде норм. Забегая вперед: не норм, просто код не уходил на ветку, где все падало.
Вчерашний вечер, собираюсь идти домой. Проверяю рабочую почту. А там куча репортов от юзеров, что одна из функций сайта не работает. Ну ебать. И меня ждал удивительный вечер в обнимку с var_dump().
Смотрю, код при заходе на определенную ветку действительно всегда безмолвно падает. В логах пусто совсем. Даже в php.ini прописал директиву error_log со ссылкой на лог апача, но ничего. Ветка длинная, пытаюсь отловить сломанное место с помощью die(), лучшего отладчика легаси кода.
Тут мне на глаза попадается еще один баг, одна из функций стала работать просто некорректно - уходит на ветку else, вместо того, чтобы зайти в один из elseif. Тут хотя бы ничего не падает. Лезу туда. И постепенно глаза лезут на лоб.
В начале скрипта $code это string(3) "304". А около ветки с if - уже string(2) "10". Я в шоке, эту переменную трогать не должен никто. Расставляю var_dump() повсюду. В итоге нахожу зловредное место.
var_dump($code); // string(3) "304"
$someData = file_get_contents('some_config.conf');
var_dump($code); // string(2) "10"
Чего блядь?! Лезу в мануал, fgc завезли сайд-эффект? Да нет, у разработчиков пхп мозги еще на месте.
Копирую $code в $code2, $another_random_var - после вызова file_get_contents все они превращаются в string(2) "10"!!!
Комментирую вызов fgc. Скрипт падает.
У меня опускаются руки, я заказываю платную поддержку у хостера и описываю ситуацию. Утром мне отписываются "закомментировали zend_extension=opcache.so, все заработало".
И правда, всё заработало как раньше, ничего нигде не падает.
Всё это выглядит как переполнение буфера у OpCache, либо какая-то борода с указателями, в общем проблемы с памятью, что серьезный баг.
Слава богу, что это не интернет-магазин, было бы охуенно выставить счет на 304 тысячи, а продать за 10 тысяч, например.
Я не знаю, как зарепортить подобное разработчикам, да и как это воспроизвести - понятия не имею. Могу только включить opcache обратно и дать доступ к серверу.
Такие дела.
Есть у меня на обслуживании проект, полностью написанный в стиле php4. Даже html кое-где вперемешку с кодом.
Позавчера вздумалось мне переставить на сервере с этим проектом php, с 5.6 прыгнуть на 7.1. Прочитал все статьи про миграцию с 5.6 на 7.0 и с 7.0 на 7.1 на php.net, убедился, что ничего не сломается, обновил php.
Проверил логи - ничего не сыпется. Потыкал сайт, все работает, красота. Хотя ой. Почему-то пара запросов оборвались - сервер рвет соединение, будто php падает. В логах пусто. Рестарт апача еще раз, потыкал-потыкал, вроде норм. Забегая вперед: не норм, просто код не уходил на ветку, где все падало.
Вчерашний вечер, собираюсь идти домой. Проверяю рабочую почту. А там куча репортов от юзеров, что одна из функций сайта не работает. Ну ебать. И меня ждал удивительный вечер в обнимку с var_dump().
Смотрю, код при заходе на определенную ветку действительно всегда безмолвно падает. В логах пусто совсем. Даже в php.ini прописал директиву error_log со ссылкой на лог апача, но ничего. Ветка длинная, пытаюсь отловить сломанное место с помощью die(), лучшего отладчика легаси кода.
Тут мне на глаза попадается еще один баг, одна из функций стала работать просто некорректно - уходит на ветку else, вместо того, чтобы зайти в один из elseif. Тут хотя бы ничего не падает. Лезу туда. И постепенно глаза лезут на лоб.
В начале скрипта $code это string(3) "304". А около ветки с if - уже string(2) "10". Я в шоке, эту переменную трогать не должен никто. Расставляю var_dump() повсюду. В итоге нахожу зловредное место.
var_dump($code); // string(3) "304"
$someData = file_get_contents('some_config.conf');
var_dump($code); // string(2) "10"
Чего блядь?! Лезу в мануал, fgc завезли сайд-эффект? Да нет, у разработчиков пхп мозги еще на месте.
Копирую $code в $code2, $another_random_var - после вызова file_get_contents все они превращаются в string(2) "10"!!!
Комментирую вызов fgc. Скрипт падает.
У меня опускаются руки, я заказываю платную поддержку у хостера и описываю ситуацию. Утром мне отписываются "закомментировали zend_extension=opcache.so, все заработало".
И правда, всё заработало как раньше, ничего нигде не падает.
Всё это выглядит как переполнение буфера у OpCache, либо какая-то борода с указателями, в общем проблемы с памятью, что серьезный баг.
Слава богу, что это не интернет-магазин, было бы охуенно выставить счет на 304 тысячи, а продать за 10 тысяч, например.
Я не знаю, как зарепортить подобное разработчикам, да и как это воспроизвести - понятия не имею. Могу только включить opcache обратно и дать доступ к серверу.
Такие дела.
Вдогонку: Zend OpCache стоял и до этого, расширением к php5.6. Что-то поломано именно сейчас.
Это теперь всегда так будет, Анон.
У меня при обработке текстовых файлов время от времени выскакивает «Unable to allocate 74255 petabytes of memory» и уже довольно давно. Все настройки в пыхопэини крутил, гуглил, да всё без толку. Когда работает, а когда нет.
У тебя тоже opcache? А если его выключить и перезапустить апач?
Да и к тому же, у меня вообще ничего не выскакивало. display_errors=Off, конечно, но до записи в лог эти краши точно не доходят.
Проблемы с оп-кешем на старых проектах (на Zend) я видел еще лет 5 назад во времена PHP5. Все аналогично. Просто какой-то баг.
> В логах пусто совсем.
Ну так если PHP падает, он уже в лог ничего записать не может. Надо смотреть лог Апача, где будет что-то вроде Child xxx unexpectedly terminated.
По-хорошему, если хочется разобраться в проблеме, надо сделать коредамп упавшего процесса и отладчиком (gdb) смотреть, в каком месте он падает. В идеале выделить еще проблемный кусок PHP кода.
>>1097571
> У меня при обработке текстовых файлов время от времени выскакивает «Unable to allocate 74255 petabytes of memory» и уже довольно давно.
Тут тоже хорошо бы сделать минимальный скрипт, который вызывает эту ошибку и зарепортить.
>Надо смотреть лог Апача
Ой, я не знал, что у апача еще свой лог имеется. Да, там килотонны
[Sat Nov 25 10:27:42.445985 2017] [mpm_itk:error] [pid 63118] child died with signal 11
[Sat Nov 25 10:27:44.163616 2017] [mpm_itk:error] [pid 63126] child died with signal 11
[Sat Nov 25 10:27:46.207923 2017] [mpm_itk:error] [pid 63128] child died with signal 11
>надо сделать коредамп упавшего процесса и отладчиком (gdb) смотреть
Не умею ничего из перечисленного, я простая веб-макака.
По такому описанию разработчики PHP баг найти просто не смогут. Если бы у меня было время, я бы попробовал поставить такие же версии софта, как у тебя, нагенерировал бы огромных PHP файлов и пробовал бы их запускать, чтобы поймать ошибку - а потом можно отладчиком найти место падения и от него искать истоки ошибки. Но времени у меня, увы, на это нет.
>было бы охуенно выставить счет на 304 тысячи, а продать за 10 тысяч, например.
У вас что, транзакций в MySQL нет?..
Ничего там не сломается, не переживай.
У ВК некоторое время назад сменилось шифрование прямой ссылки на аудиозапись. Нашел на этом форуме новый дешифратор прямой ссылки. Но если брать ссылку из ВК, то он возвращает ее же без дешифровкистарый дешифратор теперь возвращает полную хуйню. набор символов, а не ссылку
вот его код: https://pastebin.com/vvmpKjdw
С ссылками, которые приводились в пример к другим дешифраторам и которые я нашел в интернете он справляется хорошо. Возвращает ссылку типа https://...mp3, но если я сам возьму из HTML кода (или даже через пост запрос к al_audio.php) зашифрованную ссылку типа audio_api_unavailable, то он возвращает ее же.
скриншот консоли пикрелейтед
первый вариант - с той ссылкой, которую я сам взял из HTML разметки ВК
https://vk.com/mp3/audio_api_unavailable.mp3?extra=Adu4mwuXyuPJwfLOqL0WrtfLEdKYBK8XsOfjs10WCgeZy10Ol2eOChz4AOiYvxnIwsOTBI8OnKnbp2qZounYDs44 qNDplxfTDM5Rq2O5lJvLrJGOl3KXDeXOq3bUEM5iuJPyB2q5s1a4BvDYow9jAee1zeG1vJfhA3bJlvvnyLCYAuzZsMjeog1KnKqXthzXwveTyNbwDgD5ovDN x3GOudnJr29on3LSlufSrvzpBxnum2mOnejpq2uOwNPjwdyTl249BMuUEtC#AqS1nZC
второй вариант - с той ссылкой, которую приводили как пример для других дешифраторов
https:\/\/vk.com\/mp3\/audio_api_unavailable.mp3?extra=jtK5pt53yMiUpN5GFJT5yZSMyc4Pi2mJkdLIpxX8yN51Ex98FhH5Dh1OFhL8yYa9FNi0ntK\/lhaInY0CFdL5hcGVpdK3obWxFY9\/lJX1oZOjkX85bYrGgHG+FN54jquPlGn1hbuElcCddJ0gptCbDbqDFrizkH0mixuioYT6jW4FiZT4pauiybKViJW7E3W\/hxGSEYb\/isyEiNGKEZP+nZqzgYW5FIiogGumldCunXS7kX0hhZWvd2aPlaiFaqjG#DGL4cOOjDG
https://ideone.com/Y2yRSp
Спасибо большое.
Нет, это отдельный символ. Две одинарных кавычки - пустая строка.
У меня двойные кавычки (") в русской раскладке пишутся как Shift + 2, а в латинской - есть отдельная кнопка с одиночными (') и двойными (") кавычками около Enter. Проверь свою клавиатуру.
Учти, что еще есть апостроф ` - у меня он на клавише с буквой Ё и тильдой ~.
Есть еще разные Юникодные кавычки и символы дюймов, но их нет на клавиатуре.
Короче, есть один хеадер, в нем список расположенный горизонтально, 3 элемента в нем - ссылки, 1, последний - поле для ввода. Сделалхотел сделать, чтобы поле для ввода раскрывалось вправо при выделении, но оно раскрывается в обе стороны и сдвигает другие элементы. Как сделать, чтобы оно раскрывалось только вправо? Паддинг не предлагать, потому что тогда текст идет не до конца.
index.html
https://pastebin.com/5njNSUFM
style.css
https://pastebin.com/CC7jaDk
есть книги по LAMP с новым PHP и Apache. Пытался найти, но всюду пых оброс бородой
Охуенная картинка с Юкиной <:3
К фотошопу идет официальный мануал, переведенный в том числе на русский, толстенная книга (в PDF) под 1000 страниц. Если ты по каким-то причинам его потерял, его можно найти в сети в формате PDF. Обрати внимание, что надо искать руководство для нужной версии программы.
Более того, я сейчас погуглил и выяснил, что похоже наступил коммунизм, и Адоб выложила руководство по фотошопу на русском (!) под свободной лицензией:
Версия CC2017: https://helpx.adobe.com/ru/photoshop/user-guide.html
Старые версии: https://helpx.adobe.com/ru/photoshop/archive.html
Раздел про текст: https://helpx.adobe.com/ru/photoshop/user-guide.html
Не ленись, читай. Там есть раздел про редактирование текста, соответственно в этом режиме ты можешь его выделить и скопировать. Учти, что в макете текст может быть вставлен картинкой и тогда это не получится.
>>1097912
Можно без ЧПУ, можно с ЧПУ.
>>1097858
Наверно только официальный мануал на англ https://httpd.apache.org/docs/2.4/ (если есть время, можешь перевести статью-другую, и материал выучишь, и другим людям поможешь).
Со стороны PHP подключение PHP как mod_php (модуль Апача) описано тут http://php.net/manual/ru/install.unix.apache2.php (часть про компиляцию Апача смело пропускаем, важна только часть, где надо добавить директивы в конфиг Апача).
CSS-файл удален. А так, это делается обычно за счет float, меню флоатится влево, поиск флоатится вправо, и на всю шапку ставится clearfix. Таким образом, правый край поля поиска прикреплен к правому краю шапки.
Если ты используешь флоат и поле поиска расширяется так, что перекрывает меню, то по умолчанию оно провалится вниз, так как флоаты не перекрывают друг друга. В этом случае можно использовать либо абсолютное позиционирование для поля, либо задать ему отрицательный нижний маргин так, чтобы занимаемая им "высота" была нулевая.
Также есть другие варианты:
- использовать display: table для создания таблицы с 2 ячейками с выравниванием влево и вправо (не получится реализовать перекрытие меню)
- использовать flexbox (то же самое)
Все основные способы позиционирования перечислены (но не описаны) в уроке тут: https://github.com/codedokode/pasta/blob/master/html/positioning.md
Судя по описанию здесь, надо заморочиться: https://bugs.php.net/bugs-generating-backtrace.php
- нужно скомпилировать отладочную версию PHP (без нее дамп сделать возможно, но в нем не будет имен функций, а только адреса). При большом желании ее можно скомпилировать не имея прав рута, но это конечно займет время. Также, придется компилировать opcache.
- могут понадобиться права рута, чтобы включить в системе core dump (если их нет, можно запустить веб-сервер из-под gdb как описано там, gdb должен быть установлен, при большом желании это можно сделать без прав рута)
- нужно запустить веб-сервер из командной строки (чтобы он запустился с настроенными через ulimit параметрами)
То есть нужно либо включить коредампы (может они даже уже включены, можно проверить через cat /proc/sys/kernel/core_pattern и ulimit -a ) либо запускать сервер из-под gdb (в однопоточном режиме). Второе наверно даже удобнее, но может быть баг в однопоточном режиме не проявится.
core dump - это дамп памяти упавшего процесса, из которого можно получить место, где произошла ошибка. Более того, если у тебя отладочная версия PHP, то ты можешь просматривать значения сишных переменных в дампе и выяснить в каком состоянии был интепретатор, какую PHP команду он выполнял и тд.
При этом надо помнить, что в core dump могут сохраниться куски PHP кода и данных (значения переменных), которые он обрабатывал.
Также, хорошо, если бы ты мог выделить проблемное место и получить маленький скрипт, вызывающий ту же ошибку (замену значения переменной или падение).
Также, я еще кое-что придумал. Ты можешь попробовать запускать код без участия Апача (но с теми же настройками php.ini), используя встроенный в PHP веб-сервер ( http://php.net/manual/ru/features.commandline.webserver.php ). Его можно запустить даже без прав рута, если, есть доступ к командной строке. С помощью него ты можешь проверить: связано ли появление бага с Апачом или нет.
Разумеется, ты можешь также скопилировать отладочную версию PHP у себя на компьютере (если у тебя линукс или виртуальная машина с ним), главное взять ту же самую версию PHP и расширений (версию и параметры, с которыми был собран PHP, можно увидеть в phpinfo()). Это удобнее в том плане, что ты имеешь там все нужные права. Если ты раньше ничего не собирал, то это минимум несколько часов (а может и дней), так как будут возникать ошибки от того, что не хватает какой-то библиотеки или неверно прописан какой-то путь и ты будешь искать их причину.
Судя по описанию здесь, надо заморочиться: https://bugs.php.net/bugs-generating-backtrace.php
- нужно скомпилировать отладочную версию PHP (без нее дамп сделать возможно, но в нем не будет имен функций, а только адреса). При большом желании ее можно скомпилировать не имея прав рута, но это конечно займет время. Также, придется компилировать opcache.
- могут понадобиться права рута, чтобы включить в системе core dump (если их нет, можно запустить веб-сервер из-под gdb как описано там, gdb должен быть установлен, при большом желании это можно сделать без прав рута)
- нужно запустить веб-сервер из командной строки (чтобы он запустился с настроенными через ulimit параметрами)
То есть нужно либо включить коредампы (может они даже уже включены, можно проверить через cat /proc/sys/kernel/core_pattern и ulimit -a ) либо запускать сервер из-под gdb (в однопоточном режиме). Второе наверно даже удобнее, но может быть баг в однопоточном режиме не проявится.
core dump - это дамп памяти упавшего процесса, из которого можно получить место, где произошла ошибка. Более того, если у тебя отладочная версия PHP, то ты можешь просматривать значения сишных переменных в дампе и выяснить в каком состоянии был интепретатор, какую PHP команду он выполнял и тд.
При этом надо помнить, что в core dump могут сохраниться куски PHP кода и данных (значения переменных), которые он обрабатывал.
Также, хорошо, если бы ты мог выделить проблемное место и получить маленький скрипт, вызывающий ту же ошибку (замену значения переменной или падение).
Также, я еще кое-что придумал. Ты можешь попробовать запускать код без участия Апача (но с теми же настройками php.ini), используя встроенный в PHP веб-сервер ( http://php.net/manual/ru/features.commandline.webserver.php ). Его можно запустить даже без прав рута, если, есть доступ к командной строке. С помощью него ты можешь проверить: связано ли появление бага с Апачом или нет.
Разумеется, ты можешь также скопилировать отладочную версию PHP у себя на компьютере (если у тебя линукс или виртуальная машина с ним), главное взять ту же самую версию PHP и расширений (версию и параметры, с которыми был собран PHP, можно увидеть в phpinfo()). Это удобнее в том плане, что ты имеешь там все нужные права. Если ты раньше ничего не собирал, то это минимум несколько часов (а может и дней), так как будут возникать ошибки от того, что не хватает какой-то библиотеки или неверно прописан какой-то путь и ты будешь искать их причину.
Также, что касается поиска багов обращения к памяти, то для этого можно запустить программу под valgrind: http://valgrind.org/ - это не требует сборки какой-то специальной версии PHP (но в неотладочной версии конечно полезной информации будет меньше).
То есть можно запустить встроенный в PHP веб-сервер под valgrind, запустить в нем проблемный скрипт, и если там есть ошибки работы с памятью, valgrind может их обнаружить.
Вот кстати, если бы у тебя были автоматизированные приемочные тесты, которые тестируют разные страницы, ты бы обнаружил этот баг еще в dev-окружении. Пишите тесты, аноны, в Оп-посте есть обзорный урок про тестирование.
Ну и если бы ты мог сделать хотя бы минимальную версию PHP скрипта, которая дает ошибку, под встроенным веб-сервером, этого в принципе могло бы быть достаточно для поиска проблемы без возни с gdb (но возня с gdb сэкономит время разработчикам PHP, а так может ты сразу и причину найдешь и исправление предложишь).
А так да, лет 5 назад я видел такую же проблему на хостинге, тоже с древним приложением, только с другим кешем, вроде бы apc cache или еще какой-то. Замена кеша на другой решила проблему.
Также, что касается поиска багов обращения к памяти, то для этого можно запустить программу на другом языке программирования: это не требует сборки какой-то специальной версии PHP (но в неотладочной версии конечно полезной информации будет меньше).
То есть можно взять текстовый редактор, написать в нём заново «проблемный скрипт», и если там есть ошибки работы с памятью, в другом языке программирования их не будет.
Ведь делать разные анимации и всё такое можно только на JS, потому что это единственный язык, которой понимает браузер
Это значит, что бэкенд сделан на Php. То есть ты хочешь посмотреть на сайте сообщения за прошлый год, жмешь кнопку, сайт посылает с фронта http-запрос с нужными параметрами, далее php обрабатывает запрос, лезет в базу и выдает нужные данные, а потом на сайте это реализуется с помощью js или html или неважно как. Также на этот самый бэкенд приходят запросы с мобильной версии сайта, с мобильного приложения, с десктопного (если оно у них есть).
>>1098043
вполне реально, правда я в дс не видел особо много контор, где можно работать неполный день. плюс верстальщик - такая специализация, которая ни туда, ни сюда. знать надо дохуя, а перспектив нет. у нас в конторе вообще нет понятия "верстальщик", есть джуниор-фронт.
Ну почему же... перспектив нет. Женитьса на склочной стервозной бабище из хуяр-отдела, очень даже.
>>1097470
Комменатрий лучше добавить не к таблице, а прямо к колонке (например через ALTER TABLE MODIFY password_hash ... COMMENT ....).
https://github.com/kichiweb123/students/blob/master/model/ConnectDb.php
Здесь не очень понятно, зачем этот класс. Если он для того, чтобы хранить объект mysqli, то что мешает его хранить просто в переменной без всяких ConnectDb? Также, непонятно, зачем в нем поля вроде db_address? Где и как они будут использоваться?
То есть в TDG можно написать так:
> function __construct(mysqli $mysqli) ...
Или у тебя в него будет добавляться еще какой-то полезный функционал? То есть, должна быть причина, чтобы создавать новый класс. И причина, чтобы сделать в нем то или иное поле.
>>Лучше использовать DI и убрать с класса TableStudentGateway обязанность соединяться с БД.
> Сделал, но надо проверять
Вроде с DI ты разобрался.
> $err = $this->connect->connect_error;
> $err = mb_convert_encoding($err, 'UTF-8', 'cp1251');
А это зачем? Ошибка соединения с БД возвращается в cp1251? Это конечно плохо, так как под линуксом они будут в utf-8... По-хорошему, это mysqli сама должна преобразовывать информацию об ошибке в заданную в настройках PHP (default_encoding) кодировку, если это не так, то можно собрать подробности, проверить что все верно и зарепортить баг разработчикам PHP (а еще лучше - вместе с исправлением).
> TableStudentsGateway.php
> Класс нужен для соединия с БД,
Для соединения он не нужен, это лучше убрать.
Код оформлен не по PSR. Пропусти код класса через phpformatter.com, и увидишь, как правильно надо его оформлять. Также, смотри второй пост в треде про оформление кода.
> class TableStudentsGateway{
> public $db = null;
Почему поле db сделано public? Как ты выбираешь, что поставить, public или private?
В функции getStudent в SQL запрос вставляется переменная $sort, но нет проверки, что она содержит разрешенное значение, а значит тут может быть SQL инъекция.
> while($row = $result->fetch_array(MYSQLI_ASSOC)){
> $arr[] = $row;
Это можно сделать одной командой вместо цикла.
> for($i = 0; $i<=8; $i++){
Почему не foreach тут? А то придется цифру менять при изменении числа полей.
И еще кое-что. Ты передаешь в функцию refreshStudent массив данных. Но нигде не описано, какие поля могут быть в этом массиве. Не лучше ли передавать сюда объект, который имеет описание (класс), и у которого всегда можно посмотреть набор полей?
Передача массивов вместо объектов имеет тот плюс, что требует чуть меньше кода. Но ее недостаток - это то, что код труднее понять и проще ошибиться. В случае класса известно, каике у него поля, у них могут стоять комментарии. Ну например, у тебя функции в TableDataGateway принимают и возвращают массивы, но нигде формат этих массивов не описан. Экономить строчки тут необходимости нет, не лучше ли передавать объект, представляющий студента?
Вот я например заметил одну вещь: в базе поле называется second_name, а в коде sname - легко перепутать. И неудобно работать: если ты берешь массив из одной функции и передаешь в другую, получается, надо заменять в нем название поля? Было бы проще если бы для представления одного студента использовался объект.
> if(!$data['name'] and !$data['sname'] and $data['class']){
> $class = "class = ?";
> }elseif(($data['name'] or $data['sname']) and $data['class']){
> $class = ", class = ?";
> }
> if(!$data['name'] and !$data['sname'] and !$data['class'] and $data['email']){
> $email = "email = ?";
> }elseif(($data['name'] or $data['sname'] or $data['class']) and $data['email']){
> $email = ", email = ?";
> }
Это тяжело читаемая копипаста. Не нужно писать 5 однотипных блоков кода, нужно использовать цикл.
Запрос проще собирать так. Сделать массив кусочков вида ['name = ?', 'email = ?'] и склеить через implode.
> WHERE login = ?
> AND password_hash = ?
Вообще, по моему проще указывать не логин/пароль, а просто id пользователя, которого надо обновить. id это ведь первичный ключ и он однозначно указывает на пользователя.
Методы findPage и getStudent не дублируют друг друга?
Название таблицы data неудачное. Все, что хранится в базе - это данные, и название по сути ничего не говорит. Нужно называть таблицы словами вроде students.
> function getEmail(){
В этой функции есть нарушение разделения ответственности (принципа, что каждый класс занимается своим делом). Мы вроде бы подразуемваем, что за получение данных из БД отвечает только класс TabsleStudentsGateway, никто другой этим не занимается. Но! Эта функция возвращает объект класса mysqli_result. Не список email, а объект для работы с базой данных. И код, который функцию вызовет, должен получается сам работать с базой данных, а не получить готовый результат.
Приведу простой пример: допустим, мы заменим mysqli на PDO. Если все сделано верно, то нам придется править только класс TableStudentGateway. Но у тебя придется править еще и код, который использует getEmail. То есть то, что должно быть инкапсулировано (спрятано) внутри TableStudentsGateway, "протекает" в этой функции из класса наружу.
Вот еще пример нарушения инкапсуляции:
> Authorisation.php
> function isLogin($login, $pass = false){
> $result = $this->tableStudentGateway->getLoginPass();
> if($login and $pass){
> while($row = $result->fetch_array(MYSQLI_ASSOC)){
Во-первых, здесь есть проблема, что мы вытягиваем из БД все данные, вместо того, чтобы взять данные только по одному студенту. И во-вторых, здесь класс Authorisation почему-то работает с mysqli, хотя это не его зона ответственности.
Должно быть так:
- запрашиваем у TSG данные по студенту с логином login
- если не нашлись, значит логи неправильный
- если такие данные нашлись, сверяем хеш
Также, раз уж мы заговорили про разделение ответственности, хеширование паролей тоже надо поручить какому-то одному классу, чтобы оно было только в нем. Чтобы только он "знал", как их хеширвоать. И если мы захотим поменять алгоритм хеширования, чтобы надо было править только этот один класс. В данном случае, думаю, можно назначить ответственным за это класс Authorisation.
Далее, я вижу в Authorisatin метод isEmailUsed. Какое отношение он имеет к авторизации? Никакого. Этот метод лучше сделать в классе TSG. И сделать его эффективно, чтобы не вытягивались все email из базы, а делался поиск с помощью SQL запроса. Иначе на таблице в миллион пользователей это будет работать очень медленно, а может даже памяти не хватит. То, что база умеет делать сама (поиск одной записи), выгоднее делать в ней.
>>1097470
Комменатрий лучше добавить не к таблице, а прямо к колонке (например через ALTER TABLE MODIFY password_hash ... COMMENT ....).
https://github.com/kichiweb123/students/blob/master/model/ConnectDb.php
Здесь не очень понятно, зачем этот класс. Если он для того, чтобы хранить объект mysqli, то что мешает его хранить просто в переменной без всяких ConnectDb? Также, непонятно, зачем в нем поля вроде db_address? Где и как они будут использоваться?
То есть в TDG можно написать так:
> function __construct(mysqli $mysqli) ...
Или у тебя в него будет добавляться еще какой-то полезный функционал? То есть, должна быть причина, чтобы создавать новый класс. И причина, чтобы сделать в нем то или иное поле.
>>Лучше использовать DI и убрать с класса TableStudentGateway обязанность соединяться с БД.
> Сделал, но надо проверять
Вроде с DI ты разобрался.
> $err = $this->connect->connect_error;
> $err = mb_convert_encoding($err, 'UTF-8', 'cp1251');
А это зачем? Ошибка соединения с БД возвращается в cp1251? Это конечно плохо, так как под линуксом они будут в utf-8... По-хорошему, это mysqli сама должна преобразовывать информацию об ошибке в заданную в настройках PHP (default_encoding) кодировку, если это не так, то можно собрать подробности, проверить что все верно и зарепортить баг разработчикам PHP (а еще лучше - вместе с исправлением).
> TableStudentsGateway.php
> Класс нужен для соединия с БД,
Для соединения он не нужен, это лучше убрать.
Код оформлен не по PSR. Пропусти код класса через phpformatter.com, и увидишь, как правильно надо его оформлять. Также, смотри второй пост в треде про оформление кода.
> class TableStudentsGateway{
> public $db = null;
Почему поле db сделано public? Как ты выбираешь, что поставить, public или private?
В функции getStudent в SQL запрос вставляется переменная $sort, но нет проверки, что она содержит разрешенное значение, а значит тут может быть SQL инъекция.
> while($row = $result->fetch_array(MYSQLI_ASSOC)){
> $arr[] = $row;
Это можно сделать одной командой вместо цикла.
> for($i = 0; $i<=8; $i++){
Почему не foreach тут? А то придется цифру менять при изменении числа полей.
И еще кое-что. Ты передаешь в функцию refreshStudent массив данных. Но нигде не описано, какие поля могут быть в этом массиве. Не лучше ли передавать сюда объект, который имеет описание (класс), и у которого всегда можно посмотреть набор полей?
Передача массивов вместо объектов имеет тот плюс, что требует чуть меньше кода. Но ее недостаток - это то, что код труднее понять и проще ошибиться. В случае класса известно, каике у него поля, у них могут стоять комментарии. Ну например, у тебя функции в TableDataGateway принимают и возвращают массивы, но нигде формат этих массивов не описан. Экономить строчки тут необходимости нет, не лучше ли передавать объект, представляющий студента?
Вот я например заметил одну вещь: в базе поле называется second_name, а в коде sname - легко перепутать. И неудобно работать: если ты берешь массив из одной функции и передаешь в другую, получается, надо заменять в нем название поля? Было бы проще если бы для представления одного студента использовался объект.
> if(!$data['name'] and !$data['sname'] and $data['class']){
> $class = "class = ?";
> }elseif(($data['name'] or $data['sname']) and $data['class']){
> $class = ", class = ?";
> }
> if(!$data['name'] and !$data['sname'] and !$data['class'] and $data['email']){
> $email = "email = ?";
> }elseif(($data['name'] or $data['sname'] or $data['class']) and $data['email']){
> $email = ", email = ?";
> }
Это тяжело читаемая копипаста. Не нужно писать 5 однотипных блоков кода, нужно использовать цикл.
Запрос проще собирать так. Сделать массив кусочков вида ['name = ?', 'email = ?'] и склеить через implode.
> WHERE login = ?
> AND password_hash = ?
Вообще, по моему проще указывать не логин/пароль, а просто id пользователя, которого надо обновить. id это ведь первичный ключ и он однозначно указывает на пользователя.
Методы findPage и getStudent не дублируют друг друга?
Название таблицы data неудачное. Все, что хранится в базе - это данные, и название по сути ничего не говорит. Нужно называть таблицы словами вроде students.
> function getEmail(){
В этой функции есть нарушение разделения ответственности (принципа, что каждый класс занимается своим делом). Мы вроде бы подразуемваем, что за получение данных из БД отвечает только класс TabsleStudentsGateway, никто другой этим не занимается. Но! Эта функция возвращает объект класса mysqli_result. Не список email, а объект для работы с базой данных. И код, который функцию вызовет, должен получается сам работать с базой данных, а не получить готовый результат.
Приведу простой пример: допустим, мы заменим mysqli на PDO. Если все сделано верно, то нам придется править только класс TableStudentGateway. Но у тебя придется править еще и код, который использует getEmail. То есть то, что должно быть инкапсулировано (спрятано) внутри TableStudentsGateway, "протекает" в этой функции из класса наружу.
Вот еще пример нарушения инкапсуляции:
> Authorisation.php
> function isLogin($login, $pass = false){
> $result = $this->tableStudentGateway->getLoginPass();
> if($login and $pass){
> while($row = $result->fetch_array(MYSQLI_ASSOC)){
Во-первых, здесь есть проблема, что мы вытягиваем из БД все данные, вместо того, чтобы взять данные только по одному студенту. И во-вторых, здесь класс Authorisation почему-то работает с mysqli, хотя это не его зона ответственности.
Должно быть так:
- запрашиваем у TSG данные по студенту с логином login
- если не нашлись, значит логи неправильный
- если такие данные нашлись, сверяем хеш
Также, раз уж мы заговорили про разделение ответственности, хеширование паролей тоже надо поручить какому-то одному классу, чтобы оно было только в нем. Чтобы только он "знал", как их хеширвоать. И если мы захотим поменять алгоритм хеширования, чтобы надо было править только этот один класс. В данном случае, думаю, можно назначить ответственным за это класс Authorisation.
Далее, я вижу в Authorisatin метод isEmailUsed. Какое отношение он имеет к авторизации? Никакого. Этот метод лучше сделать в классе TSG. И сделать его эффективно, чтобы не вытягивались все email из базы, а делался поиск с помощью SQL запроса. Иначе на таблице в миллион пользователей это будет работать очень медленно, а может даже памяти не хватит. То, что база умеет делать сама (поиск одной записи), выгоднее делать в ней.
>>1097470
> setcookie("login", "$login", 0x7FFFFFFF,
Время бы лучше указать как-то понятнее, вроде текущее + 10 лет, а то не очень понятно, почему именно 7ffff... и сколько это в привычных нам единицах измерения.
Для удаления кук надо указывать время в прошлом, посмотри мануал.
В валидаторе, при проверке поля score, надо проверять, что оно содержит цифры. А то можно ввести "30 cats". Для года надо проверять что там указан реалистичный год.
> if($this->authorisation->isLogin
Лучше isLoginUsed
Также, нужно подумать, как избавиться от повторяющегося кода в методах validateStudent и validateProfile.
> https://github.com/kichiweb123/students/blob/master/public/cfg.ini
зачем ты конфиг с паролями положил в публично доступную папку? Хочешь со всеми поделиться своими секретами?
> function my_autoloader($class){
Тут ошибка. В моем уроке про автозагрузку ( https://github.com/codedokode/pasta/blob/master/php/autoload.md ) было сказано:
> автозагрузчик не должен выдавать ошибку, если он не может найти файл с классом - может быть, этот класс подгрузит другой автозагрузчик
У тебя нет проверки, что файл ../controller/'.$class.'.php'; существует - следовательно, если написать например код
if (class_exists('TestClass')) {}
То произойдет ошибка при попытке подключить несуществующий файл. Также, из-за этого твой автозагрузчик не сможет работать вместе с другими.
> header('Location: error.php');
Это неправильно. Допустим у тебя в коде произошла ошибка. Сервер должен отдать ответ с кодом 5xx. А ты отдаешь ответ с кодом 302 (редирект), который значит - страница, которую вы ищете, переехала по другому адресу. Не надо никогда редиректить на страницу ошибки, надо ее показывать.
https://github.com/kichiweb123/students/blob/master/public/index.php
Из этого файла надо убрать полностью HTML код и лишние маркеры <?php
Ты попытался сделать обработчик исключений. Но почему-то ты ловишь только исключения при создании нескольких объектов, а остальной код не проверяешь. Логичнее тогда весь код в файле обернуть в один большой try/catch. Или прочитать про обработчик исключений в моем уроке по исключениям.
> $error = $e->getMessage();
Ты берешь только сообщение, но теряешь другую информацию, например, стектрейс. Лучше писать $e->__toString(), которая вернет всю информацию об ошибке. Также, проверь, пишется ли в лог время, когда произошла ошибка, и URL, который пытался открыть пользователь. без этих данных тебе трудно будет понять - где именно ошибка.
Контроллеры Search и Table очень похожи. Их функции можно объединить в один контроллер, ведь поиск - это тоже просмотр списка студентов, только с фильтром по имени.
> Profile.php
> if($_SERVER["REQUEST_METHOD"] == "POST"){
> require_once "../refreshStudent.php";
Зачем из контроллера вынсоить кусок в отдельный файл? Не лучше ли сюда этот код и вписать?
> <form class="form-inline" style="float:right;
Для этого в бутстрапе есть класс pull-right. Также, почитай про сетку в бутстрапе, которая здорово помогает выровнять блоки до заданной ширины. Просто возьми руководство по бутстрапу и пролистай, и обрати внимание, какие в нем возможности есть - это тебе не раз пригодится, я думаю.
https://github.com/kichiweb123/students/blob/master/view/login.phtml
В view не должно быть работы с POST/GET. Оно просто отображает то, что дал контроллер.
> elseif(!$container['Authorisation']->isLogin($login, $pass)){
То же самое, это должно быть в контроллере, это не задача view, проверять логин.
> view/pages.phtml
> echo "<a href='?id=search&search=".$search."&p=".($offset-1).
тебе не кажется, что тут длинная и тяжело читаемая смесь из знаков препинания? Лучше сделать функцию или метод где-нибудь в Util, который будет формировать URL из переданных ему параметров. И не забывай про htmlspecialchars.
> view/search.phtml
> Найдены запросы по слову \"$search\":
Прочитай мой урок по XSS на гитхабе.
Также, в шаблонах не должно быть echo, это неудобно, писать HTML в кавычках. Используй <?= ?>.
Если тебе что-то непонятно, спрашивай. Важно не слепо следовать советам, а понимать, зачем это нужно.
>>1097468
>> Нет, в данном случае, тебя должно залогинить без регистрациии и без наличия кук. Под каким-то существующим аккаунтом.
> Это как?
Взять какой-нибудь аккаунт, например с id=1. Нужно, чтобы ты после захода на специальную страницу был залогинен под этим аккаунтом. То есть залогиниться под чьим-то аккаунтом не вводя логин или пароль (представь, что это нужно администратору например, или тестировщику).
Если у тебя код правильно разделен на части, то это сделать нетрудно.
>>1097470
> setcookie("login", "$login", 0x7FFFFFFF,
Время бы лучше указать как-то понятнее, вроде текущее + 10 лет, а то не очень понятно, почему именно 7ffff... и сколько это в привычных нам единицах измерения.
Для удаления кук надо указывать время в прошлом, посмотри мануал.
В валидаторе, при проверке поля score, надо проверять, что оно содержит цифры. А то можно ввести "30 cats". Для года надо проверять что там указан реалистичный год.
> if($this->authorisation->isLogin
Лучше isLoginUsed
Также, нужно подумать, как избавиться от повторяющегося кода в методах validateStudent и validateProfile.
> https://github.com/kichiweb123/students/blob/master/public/cfg.ini
зачем ты конфиг с паролями положил в публично доступную папку? Хочешь со всеми поделиться своими секретами?
> function my_autoloader($class){
Тут ошибка. В моем уроке про автозагрузку ( https://github.com/codedokode/pasta/blob/master/php/autoload.md ) было сказано:
> автозагрузчик не должен выдавать ошибку, если он не может найти файл с классом - может быть, этот класс подгрузит другой автозагрузчик
У тебя нет проверки, что файл ../controller/'.$class.'.php'; существует - следовательно, если написать например код
if (class_exists('TestClass')) {}
То произойдет ошибка при попытке подключить несуществующий файл. Также, из-за этого твой автозагрузчик не сможет работать вместе с другими.
> header('Location: error.php');
Это неправильно. Допустим у тебя в коде произошла ошибка. Сервер должен отдать ответ с кодом 5xx. А ты отдаешь ответ с кодом 302 (редирект), который значит - страница, которую вы ищете, переехала по другому адресу. Не надо никогда редиректить на страницу ошибки, надо ее показывать.
https://github.com/kichiweb123/students/blob/master/public/index.php
Из этого файла надо убрать полностью HTML код и лишние маркеры <?php
Ты попытался сделать обработчик исключений. Но почему-то ты ловишь только исключения при создании нескольких объектов, а остальной код не проверяешь. Логичнее тогда весь код в файле обернуть в один большой try/catch. Или прочитать про обработчик исключений в моем уроке по исключениям.
> $error = $e->getMessage();
Ты берешь только сообщение, но теряешь другую информацию, например, стектрейс. Лучше писать $e->__toString(), которая вернет всю информацию об ошибке. Также, проверь, пишется ли в лог время, когда произошла ошибка, и URL, который пытался открыть пользователь. без этих данных тебе трудно будет понять - где именно ошибка.
Контроллеры Search и Table очень похожи. Их функции можно объединить в один контроллер, ведь поиск - это тоже просмотр списка студентов, только с фильтром по имени.
> Profile.php
> if($_SERVER["REQUEST_METHOD"] == "POST"){
> require_once "../refreshStudent.php";
Зачем из контроллера вынсоить кусок в отдельный файл? Не лучше ли сюда этот код и вписать?
> <form class="form-inline" style="float:right;
Для этого в бутстрапе есть класс pull-right. Также, почитай про сетку в бутстрапе, которая здорово помогает выровнять блоки до заданной ширины. Просто возьми руководство по бутстрапу и пролистай, и обрати внимание, какие в нем возможности есть - это тебе не раз пригодится, я думаю.
https://github.com/kichiweb123/students/blob/master/view/login.phtml
В view не должно быть работы с POST/GET. Оно просто отображает то, что дал контроллер.
> elseif(!$container['Authorisation']->isLogin($login, $pass)){
То же самое, это должно быть в контроллере, это не задача view, проверять логин.
> view/pages.phtml
> echo "<a href='?id=search&search=".$search."&p=".($offset-1).
тебе не кажется, что тут длинная и тяжело читаемая смесь из знаков препинания? Лучше сделать функцию или метод где-нибудь в Util, который будет формировать URL из переданных ему параметров. И не забывай про htmlspecialchars.
> view/search.phtml
> Найдены запросы по слову \"$search\":
Прочитай мой урок по XSS на гитхабе.
Также, в шаблонах не должно быть echo, это неудобно, писать HTML в кавычках. Используй <?= ?>.
Если тебе что-то непонятно, спрашивай. Важно не слепо следовать советам, а понимать, зачем это нужно.
>>1097468
>> Нет, в данном случае, тебя должно залогинить без регистрациии и без наличия кук. Под каким-то существующим аккаунтом.
> Это как?
Взять какой-нибудь аккаунт, например с id=1. Нужно, чтобы ты после захода на специальную страницу был залогинен под этим аккаунтом. То есть залогиниться под чьим-то аккаунтом не вводя логин или пароль (представь, что это нужно администратору например, или тестировщику).
Если у тебя код правильно разделен на части, то это сделать нетрудно.
>ucwords — Преобразует в верхний регистр первый символ каждого слова в строке
Там, где delimiters нужно регулярное выражение? Почему он в верхний регистр отказался преобразовать строку?
Спасибо большое по поводу фотошопа
Ой, пост пропустил. Потому я обычно и прошу напомнить о себе, потому что в треде на 900 постов можно что-то и упустить.
>>>+offset + +1
>>Немного странное место. Не многовато ли знаков "плюс"?
> Что поделать если js при сложении не преобразует данные в число? Приходиться делать это самому.
Ну это уже вопрос к твоему коду в backend, почему он числа в виде строк возвращает. А так, надо хотя бы скобки ставить для понятности: (+offset) + 1
>>Также, мне кажется, что у тебя в контроллере находится код, относящийся ко view: вызовы jQuery вроде if ($(that.view.moremessages).length) стоило бы перенести во view и писать вместо этого if (that.view.hasMoreMessagesButton()), а еще лучше - if (this.canShowMoreMessages()), так как это довольно коряво, проверять наличие новых сообщений по наличию кнопки на экране. Должно ведь быть наоборот - модель/viewModel сама знает, есть ли новые сообщения.
> Всегда нужно пользоваться только высстананвленными наружу методами, даже если код займет одну строку?
Тут скорее идея в том, что мы изолируем всю работу с DOM в один класс. Это ведь один из принципов ООП - single responsibility. И потому мы должны писать
view.showMessageCount(1);
а не
view.messageCountDiv.text(1);
Видишь разницу между 2 вариантами? Она в наличии/отсутствии инкапсуляции работы с DOM внутри view. Ну и если ты, например, захочешь сделать анимацию при изменении числа, в первом варианте это будет проще. Также, в первом случае код чуть понятнее, на мой взгляд.
Можно конечно не делать инкапсуляцию, но тогда возникает вопрос, а зачем вообще нужен view? Не проще его объединить с контроллером? Такой вариант тоже возможен.
Да, может показаться, что это раздувает код, но это потому, что ты пишешь все руками, не используешь библиотеки для data-binding (knockout, angular, react, vue и тд), которые решают проблему избавления от ручного обновления DOM.
>>Должно ведь быть наоборот - модель/viewModel сама знает, есть ли новые сообщения.
> Должно быть свойство модели/viewModel, например this.canShowMoreMessages = true/false?
Не знаю, зависит от реализации. Но вообще обычно данные хранятся/берутся из модели и передаются во вью для отображения. Ну например, можно возвращать это свойство вместе с результатами запроса к АПИ:
backend.getMessages(offset) -> [messages, hasMoreMessages]
И просто хранить в переменной. Можно хранить в свойстве контроллера. В переменной удобнее тем, что у нее ограничена область видимости.
Также, может быть, у тебя есть модель, представляющая хранилище сообщений. И тогда она может ответить на вопрос, есть ли еще:
var hasMore = messageList.hasMoreMessages(offset);
Но проверять наличие сообщений по наличию кнопки в DOM - это не соответствует MVC. И это имеет недостатки, при изменении этой кнопки придется менять код прокрутки, который, казалось бы, с ней никак не связан. Легко забыть поменять и создать баг. Поверь, тот, кто обнаружит этот баг, будет тебя не лучшими словами вспоминать.
Я там еще увидел, что ты решил пойти дальше и переменные начать хранить в DOM:
> var datawith = $('a', that.view.moreMessages).attr('data-with');
А что мешает хранить это в переменной?
Тот подход, который ты использовал - хранить данные в атрибутах, он вообще допустим. Ну например, мы могли бы сделать такой HTML-код для карточки отеля:
<div class="hotel-card" data-stars="3" data-city="London" data-price="100"></div>
Более того, давно уже ведутся разговоры по возможности добавления кастомных тегов, чтобы писать <hotel-card stars="3" city="London"></hotel-card>. Например, такое есть в Polymer.js, для этого добавили Shadow DOM. Такой синтаксис используют в Реакте. Почему нет? Вполне соответствует идее семантической (смысловой) разметки.
Но в таком случае обычно "карточка отеля" - это отдельный компонент. Где-то есть скрипт, который читает эти атрибуты и обрабатывает их, есть шаблон и тд. А у тебя не так, у тебя ведь кнопка не оформлена как отдельный компонент. Ты просто используешь DOM атрибуты как поля объекта или переменные, и возникает вопрос - а что мешает данные сразу и хранить в полях или переменных?
Из-за этого код сложнее становится - надо разбираться, кто пишет значение в этот атрибут, кто читает, данные передаются каким-то усложненным способом.
>>Из-за того, что ты в контроллере смешиваешь код view, код установки обработчиков, асинхронные вызовы, все это выглядит сложно и запутанно.
> Разве контроллер не должен "дирижировать" всем этим?
Я не помню, что я имел в виду, но думаю, я хотел сказать о 1) разделении ответственности (например, только вью работает с DOM напрямую) и 2) о преобразовании больших функций с кучей колллбеков (callback hell). Может их надо на части разбить, может их надо писать не вложенно, а последовательно.
Про callback hell, это когда пишут так:
$(...).click(function (e) {
$.ajax({
url: ...,
onsuccess: function (result) {
setTimeout(function () {
$(...).click(function () {
...
});
});
}
})
});
То есть создают код с большой глубиной отступов. Я видел, как некоторые даже отступ ставят на 2 пробела, чтобы код не уезжал вправо, но они борются с последствием, а не с причиной. Не надо писать такой сильно вложенный код.
Я вот сейчас открыл твой код - и обнаружил там те самые 2 пробела. Как в воду глядел.
Вот это вот код не для человека:
https://github.com/someApprentice/chat/blob/master/public/js/conversation.js#L71
> that.backend.handleError(jqXHR, textStatus);
> }
> );
> }
> }
> }
> }.bind(this));
> };
Я не робот и я не могу в уме посчитать, к чему тут относится bind(this). 8 уровней вложенности! 3-4 хватило бы с лихвой.
Промисы позволяют победить это:
var result = doSmth();
result.catch(...);
result.then(function () {
...
}).then(function () {
...
});
Также, можно выносить код в функции:
$(btn).click(handleClick);
$(btn2).click(this.handleClick.bind(this));
Алсо, кто-то даже сделал сайт по теме http://callbackhell.com/
Или тут: https://github.com/someApprentice/chat/blob/master/public/js/conversation.js#L80 - функция на целых 60 строк. Пока я дойду до конца, я забуду, что было в начале.
И еще, ты-то может это знаешь, но я например не понимаю, за что отвечает каждый класс. Вот conversation.js - это контроллер области сообщений? Контроллер, отвечающий за переписку вообще? Стоит взять за правило писать перед классом, за что он отвечает и зачем нужен. Кроме самых очевидных случаев.
Огромные if можно превратить в маленькие, если поменять условие на противоположное.
if (!...) {
return;
}
Вот попробуем упростить это:
https://github.com/someApprentice/chat/blob/master/public/js/conversation.js#L31
> that.backend.getLastMessages(datawith, offset).then(function(data) {
> проверка, что URL не изменился
> отправка сообщений на расшифровку
> обновление DOM
Я бы сделал так. Все, связанное с расшифровкой, просто вынес бы в функцию. Использовал бы промисы для выполнения асинхронных операций последовательно:
var encryptedPromise = that.backend.getLastMessages(datawith, offset);
var decryptedPromise = encryptedPromise.then(this.decryptMessages.bind(this));
decryptedPromise.then(function (decrypted)) {
если (URL изменился) { выйти; }
this.appendMessages(decrypted);
this.showSomeButton(...);
...
};
То есть надо ограничивать глубину вложенности и длину функций. Это ведь тоже показывает твои навыки - можешь ли ты разложить код на составные части или напишешь длинный кусок лапши.
Иногда ситуация бывает сложнее, чем я написал. Ну например, бекенд возвращает 2 значения, { encryptedMessages, haveMore }, и надо как-то передать haveMore в функцию вывода данных, пропустив этап расшифровки. Я не знаю правильного ответа, попробуем например что-нибудь написать:
var resultPr = that.backend.getLastMessages(datawith, offset);
var viewData = resultPr.then(function (lastMessages) {
var decryptedPr = that.decrypt(lastMessages.encryptedMessages);
// Добавляем haveMore в результат расшифровки
var decryptedAndHaveMorePr = decryptedPr.then(function (decrypted) {
return {
haveMore: lastMessages.haveMore,
decrypted: decrypted
};
});
return decryptedAndHaveMorePr;
});
viewData.then(function (decryptedAndHaveMore) {
// вывод сообщений
}, function () {
// вывод ошибок
});
Не знаю, читабельно ли вышло? Может, ты сможешь красивее записать? Асинхронный код, он такой, на await/async ( https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Operators/await ) это бы наверно компактнее получилось:
var result = await that.backend.getLastMessages(datawith, offset);
var decrypted = await decryptMessages(result.encrypted);
view.showMessages(decrypted);
view.showMoreButton(result.haveMore);
>>Также, твой Crypter является по сути оберткой над openpgp, ничего от себя не добавляя. Непонятно, в чем смысл его существовани
> Вы выше делали замечание что нужно делать обёртку. Я запутан.
Не помню, к сожалению, что я имел в виду. Я просто хотел сказать, что если ты пишешь класс-обертку, он должен добавлять какой-то функционал, иначе можно использовать внутренний класс напрямую. Ну не знаю, давай считать тогда, что добавленный функционал - это запуск воркера (initWorker).
Ой, пост пропустил. Потому я обычно и прошу напомнить о себе, потому что в треде на 900 постов можно что-то и упустить.
>>>+offset + +1
>>Немного странное место. Не многовато ли знаков "плюс"?
> Что поделать если js при сложении не преобразует данные в число? Приходиться делать это самому.
Ну это уже вопрос к твоему коду в backend, почему он числа в виде строк возвращает. А так, надо хотя бы скобки ставить для понятности: (+offset) + 1
>>Также, мне кажется, что у тебя в контроллере находится код, относящийся ко view: вызовы jQuery вроде if ($(that.view.moremessages).length) стоило бы перенести во view и писать вместо этого if (that.view.hasMoreMessagesButton()), а еще лучше - if (this.canShowMoreMessages()), так как это довольно коряво, проверять наличие новых сообщений по наличию кнопки на экране. Должно ведь быть наоборот - модель/viewModel сама знает, есть ли новые сообщения.
> Всегда нужно пользоваться только высстананвленными наружу методами, даже если код займет одну строку?
Тут скорее идея в том, что мы изолируем всю работу с DOM в один класс. Это ведь один из принципов ООП - single responsibility. И потому мы должны писать
view.showMessageCount(1);
а не
view.messageCountDiv.text(1);
Видишь разницу между 2 вариантами? Она в наличии/отсутствии инкапсуляции работы с DOM внутри view. Ну и если ты, например, захочешь сделать анимацию при изменении числа, в первом варианте это будет проще. Также, в первом случае код чуть понятнее, на мой взгляд.
Можно конечно не делать инкапсуляцию, но тогда возникает вопрос, а зачем вообще нужен view? Не проще его объединить с контроллером? Такой вариант тоже возможен.
Да, может показаться, что это раздувает код, но это потому, что ты пишешь все руками, не используешь библиотеки для data-binding (knockout, angular, react, vue и тд), которые решают проблему избавления от ручного обновления DOM.
>>Должно ведь быть наоборот - модель/viewModel сама знает, есть ли новые сообщения.
> Должно быть свойство модели/viewModel, например this.canShowMoreMessages = true/false?
Не знаю, зависит от реализации. Но вообще обычно данные хранятся/берутся из модели и передаются во вью для отображения. Ну например, можно возвращать это свойство вместе с результатами запроса к АПИ:
backend.getMessages(offset) -> [messages, hasMoreMessages]
И просто хранить в переменной. Можно хранить в свойстве контроллера. В переменной удобнее тем, что у нее ограничена область видимости.
Также, может быть, у тебя есть модель, представляющая хранилище сообщений. И тогда она может ответить на вопрос, есть ли еще:
var hasMore = messageList.hasMoreMessages(offset);
Но проверять наличие сообщений по наличию кнопки в DOM - это не соответствует MVC. И это имеет недостатки, при изменении этой кнопки придется менять код прокрутки, который, казалось бы, с ней никак не связан. Легко забыть поменять и создать баг. Поверь, тот, кто обнаружит этот баг, будет тебя не лучшими словами вспоминать.
Я там еще увидел, что ты решил пойти дальше и переменные начать хранить в DOM:
> var datawith = $('a', that.view.moreMessages).attr('data-with');
А что мешает хранить это в переменной?
Тот подход, который ты использовал - хранить данные в атрибутах, он вообще допустим. Ну например, мы могли бы сделать такой HTML-код для карточки отеля:
<div class="hotel-card" data-stars="3" data-city="London" data-price="100"></div>
Более того, давно уже ведутся разговоры по возможности добавления кастомных тегов, чтобы писать <hotel-card stars="3" city="London"></hotel-card>. Например, такое есть в Polymer.js, для этого добавили Shadow DOM. Такой синтаксис используют в Реакте. Почему нет? Вполне соответствует идее семантической (смысловой) разметки.
Но в таком случае обычно "карточка отеля" - это отдельный компонент. Где-то есть скрипт, который читает эти атрибуты и обрабатывает их, есть шаблон и тд. А у тебя не так, у тебя ведь кнопка не оформлена как отдельный компонент. Ты просто используешь DOM атрибуты как поля объекта или переменные, и возникает вопрос - а что мешает данные сразу и хранить в полях или переменных?
Из-за этого код сложнее становится - надо разбираться, кто пишет значение в этот атрибут, кто читает, данные передаются каким-то усложненным способом.
>>Из-за того, что ты в контроллере смешиваешь код view, код установки обработчиков, асинхронные вызовы, все это выглядит сложно и запутанно.
> Разве контроллер не должен "дирижировать" всем этим?
Я не помню, что я имел в виду, но думаю, я хотел сказать о 1) разделении ответственности (например, только вью работает с DOM напрямую) и 2) о преобразовании больших функций с кучей колллбеков (callback hell). Может их надо на части разбить, может их надо писать не вложенно, а последовательно.
Про callback hell, это когда пишут так:
$(...).click(function (e) {
$.ajax({
url: ...,
onsuccess: function (result) {
setTimeout(function () {
$(...).click(function () {
...
});
});
}
})
});
То есть создают код с большой глубиной отступов. Я видел, как некоторые даже отступ ставят на 2 пробела, чтобы код не уезжал вправо, но они борются с последствием, а не с причиной. Не надо писать такой сильно вложенный код.
Я вот сейчас открыл твой код - и обнаружил там те самые 2 пробела. Как в воду глядел.
Вот это вот код не для человека:
https://github.com/someApprentice/chat/blob/master/public/js/conversation.js#L71
> that.backend.handleError(jqXHR, textStatus);
> }
> );
> }
> }
> }
> }.bind(this));
> };
Я не робот и я не могу в уме посчитать, к чему тут относится bind(this). 8 уровней вложенности! 3-4 хватило бы с лихвой.
Промисы позволяют победить это:
var result = doSmth();
result.catch(...);
result.then(function () {
...
}).then(function () {
...
});
Также, можно выносить код в функции:
$(btn).click(handleClick);
$(btn2).click(this.handleClick.bind(this));
Алсо, кто-то даже сделал сайт по теме http://callbackhell.com/
Или тут: https://github.com/someApprentice/chat/blob/master/public/js/conversation.js#L80 - функция на целых 60 строк. Пока я дойду до конца, я забуду, что было в начале.
И еще, ты-то может это знаешь, но я например не понимаю, за что отвечает каждый класс. Вот conversation.js - это контроллер области сообщений? Контроллер, отвечающий за переписку вообще? Стоит взять за правило писать перед классом, за что он отвечает и зачем нужен. Кроме самых очевидных случаев.
Огромные if можно превратить в маленькие, если поменять условие на противоположное.
if (!...) {
return;
}
Вот попробуем упростить это:
https://github.com/someApprentice/chat/blob/master/public/js/conversation.js#L31
> that.backend.getLastMessages(datawith, offset).then(function(data) {
> проверка, что URL не изменился
> отправка сообщений на расшифровку
> обновление DOM
Я бы сделал так. Все, связанное с расшифровкой, просто вынес бы в функцию. Использовал бы промисы для выполнения асинхронных операций последовательно:
var encryptedPromise = that.backend.getLastMessages(datawith, offset);
var decryptedPromise = encryptedPromise.then(this.decryptMessages.bind(this));
decryptedPromise.then(function (decrypted)) {
если (URL изменился) { выйти; }
this.appendMessages(decrypted);
this.showSomeButton(...);
...
};
То есть надо ограничивать глубину вложенности и длину функций. Это ведь тоже показывает твои навыки - можешь ли ты разложить код на составные части или напишешь длинный кусок лапши.
Иногда ситуация бывает сложнее, чем я написал. Ну например, бекенд возвращает 2 значения, { encryptedMessages, haveMore }, и надо как-то передать haveMore в функцию вывода данных, пропустив этап расшифровки. Я не знаю правильного ответа, попробуем например что-нибудь написать:
var resultPr = that.backend.getLastMessages(datawith, offset);
var viewData = resultPr.then(function (lastMessages) {
var decryptedPr = that.decrypt(lastMessages.encryptedMessages);
// Добавляем haveMore в результат расшифровки
var decryptedAndHaveMorePr = decryptedPr.then(function (decrypted) {
return {
haveMore: lastMessages.haveMore,
decrypted: decrypted
};
});
return decryptedAndHaveMorePr;
});
viewData.then(function (decryptedAndHaveMore) {
// вывод сообщений
}, function () {
// вывод ошибок
});
Не знаю, читабельно ли вышло? Может, ты сможешь красивее записать? Асинхронный код, он такой, на await/async ( https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Operators/await ) это бы наверно компактнее получилось:
var result = await that.backend.getLastMessages(datawith, offset);
var decrypted = await decryptMessages(result.encrypted);
view.showMessages(decrypted);
view.showMoreButton(result.haveMore);
>>Также, твой Crypter является по сути оберткой над openpgp, ничего от себя не добавляя. Непонятно, в чем смысл его существовани
> Вы выше делали замечание что нужно делать обёртку. Я запутан.
Не помню, к сожалению, что я имел в виду. Я просто хотел сказать, что если ты пишешь класс-обертку, он должен добавлять какой-то функционал, иначе можно использовать внутренний класс напрямую. Ну не знаю, давай считать тогда, что добавленный функционал - это запуск воркера (initWorker).
> Нет, локальное хранилище должно быть в любом случае. Я уже подготовился к его написанию.
Тут главное правильно его спроектировать (интерфейс к нему), с учетом асинхронности почти всех операций.
> В омем предстовлении backend занимается только получением данных с API, т.е. с бэкенда сервера. Не будет ли вывод данных нарушением инкапсуляции в таком случае?
Конечно, будет. Если это делает бекенд. А если бекенд генерирует события пропадения/появления связи или события ошибок, а контроллер/вью на них подписывается и отображает на экране, то разделению соблюдается. То есть паттерн "Observer" решает эту проблему.
Вот так:
// в контроллере
this.backend.onError(function (e) {
that.displayError(e);
});
Просто тут ведь есть такие варианты:
1) обрабатывать ошибки после вызова каждой функции отдельно
2) централизованно фиксировать наличие ошибок и где-то в одном месте их ловить и выводить
И какой лучше - зависит от ситуации. Может ты в углу хочешь выводить ошибки, может менять цвет иконки, а может рядом с сообщением или кнопкой отправки.
Движок от Википедии: https://github.com/wikimedia/mediawiki
Магенто 2, движок для интернет-магазинов: https://github.com/magento/magento2
Вот примерно с таким вы можете столкнуться, если устроитесь на работу.
И еще. Ты использешь в дампе utf8: https://github.com/someApprentice/chat/blob/master/chat.sql
Это не utf-8, настоящая utf-8 в MySQL называется utf8mb4: https://medium.com/@adamhooper/in-mysql-never-use-utf8-use-utf8mb4-11761243e434
А то в твоем чатике нельзя будет эмодзи пересылать.
https://ideone.com/EQhCuF
Репост из предыдущего треда
Какой популярный фреймворк "более ооп-шный".
Даже не знаю, может мое недовольство не обоснованно, но вот например пробовал laravel, так там по мануалу полно обращений к статическим методам или сам генератор перечисляет поля из бд в массиве. (например protected $fillable = [ 'name', 'email', 'password', ]; )
И еще. В дампе ошибка DATETIME(6), в форме регистрации не пропускает логин ivan, из-за кривой регулярки.
В имени нельзя использовать цифры.
При регистрации появляется ошибка, что за 60 секунд ключ не сгенерировало, хотя процесс gpg висит с 0 потреблением CPU все это время. Может конечно, это нехватка энтропии в виртуальной машине виновата.
На c9.io просто появляется надпись generating keys... и ничего не происходит.
вводил здесь
https://xdebug.org/wizard.php
аутпут от php -i
Download php_xdebug-2.5.4-7.1-vc14-nts-x86_64.dll
Move the downloaded file to ext
Edit C:\tools\php71\php.ini and add the line
zend_extension = ext\php_xdebug-2.5.4-7.1-vc14-nts-x86_64.dll
Прописал эту строчку сразу после
;;;;;;;;;;;;;;;;;;;
; About php.ini ;
;;;;;;;;;;;;;;;;;;;
таким образом
;zend_extension = ext\php_xdebug-2.5.4-7.1-vc14-nts-x86_64.dll
после этого снова ввел
pact install xdebug
в Бабуне, но ничего всё равно получил
Package xdebug not found or ambiguous name, exiting
Скачать Атом ? Или есть достойные альтернативы?
Инструкции на сайте xdebug - они для ручной установки. То есть она пишет, какую dll тебе надо скачать, куда положить и что дописать в php.ini. Ты их выполнял?
Что касается pact, он ведь никак с разработчиками xdebug не связан. Это сборка с cygwin. И pact устанавливает не любые программы, а те, что есть в репозитории cygwin.
Что такое cygwin? Это набор библиотек, имитирующих линуксовое АПИ на Windows. За счет этого можно скомпилировать линуксовые программы под cygwin и запускать их под windows.
Если ты ставил php для windows (не для cygwin), то ты должен для него скачать xdebug с сайта, как он тебе советует.
Если вместо этого ты бы предпочел пользоваться cygwin и pact, то тебе надо установить php через pact, и через него же xdebug. И убедиться, что виндовый PHP находится не в PATH, чтобы не запустить его случайно.
> Package xdebug not found or ambiguous name, exiting
Ты ввел неправильнео имя пакета. Делать надо не так:
- найти пакеты по слову xdebug (pact find xdebug)
- просмотреть список и выбрать нужный тебе
- установить его, указав его правильное имя. Скорее всего он называется как-то вроде php7-xdebug. Поиск подскажет.
pact describe xdebug покажет подробную информацию о пакетах, в названии которых есть это слово.
Я кстати сам cygwin использую, ты можешь с его помощью потихоньку привыкать к линуксовой командной строке.
Короче чот ты много нагородил, мож заработался, у меня такое бывает. Ну в общем:
>text-align: center;
Вот эта штука вроде как выравнивает все посередине, но и заставляет одновременно синхронить свое положение при изменений окна, неважно какого, даже внутри дисплея. Так как теги имеют гены, то естественно детки эту штуку переняли, в общем тегам потомкам передалось это свойство.
> <div id="page-wrapper">
>Внутри него находится твой хаотический список
>Соответственно этот div и является окном
>>1097944
Чот ты нагородил тоже, не проще ли установить его статично и все? Просто в таких случаях лезть во флекс, совет интересный, но не в этом случае смею предположить. Ну ка расскажи где эт флексы так используют, аж интересно стало? Почему так все усложнено?
Смотри што сделал:
https://theknacker.github.io/Test/index.html
>А так, это делается обычно за счет float, меню флоатится влево, поиск флоатится вправо, и на всю шапку ставится clearfix. Таким образом, правый край поля поиска прикреплен к правому краю шапки.
https://theknacker.github.io/Test/index2.html - Поиск здорового человека.
>Если ты используешь флоат и поле поиска расширяется так, что перекрывает меню, то по умолчанию оно провалится вниз, так как флоаты не перекрывают друг друга.
https://theknacker.github.io/Test/index3.html - Поиск курильщика.
Все вспомнил, извини ОП за тупость. Но вот табличный способ если чесна первый раз слышу, интересно как он работает?
Я не автор страницы, я просто взял ее на разбор ради интереса.
Как я понял, у человека была задача сделать меню прижатым слева, а поиск - прижатым вправо. При клике в поле поиска оно расширяется (левый край поля движется влево, правый остается на месте), возможно, наезжая поверх меню (на многих сайтах сейчас так делают). Я и предложил решения. Может я конечно задачу не так понял.
Тут https://theknacker.github.io/Test/index.html сделано что-то другое, поле поиска не прижато вправо.
тут https://theknacker.github.io/Test/index2.html поле не наезжает на меню при расширении, а проваливается вниз. Попробуй сделать, чтобы поле расширялось до 200px, а не 120, и увидишь.
https://theknacker.github.io/Test/index3.html та же проблема.
Я думаю, что нужно, чтобы поле поиска при расширении наезжало поверх меню, а не проваливалось вниз.
При этом в идеале это надо еще сделать адаптивно, чтобы на маленькой ширине экрана это тоже нормально работало.
> Но вот табличный способ если чесна первый раз слышу, интересно как он работает?
display: table/table-row/rable-body/table-cell. Лучше всего про них почитать в спецификации если не боишься, или в какой-нибудь статье. Заставляют элементы позиционироваться как таблицу. Соответственно, можно сделать таблицу из 2 ячеек.
> Чот ты нагородил тоже, не проще ли установить его статично и все?
Что значит статично? position: static? Не вижу логики.
> где эт флексы так используют
Там, где другие способы не годятся. Ты почитай спеку по флексам или хотя бы обзор на MDN. Ну например, если тебе надо сделать интерфейс, который разбивает экран на части и выравнивает их содержимое. Плюс, там можно задавать пропорции между этими частями.
Можно например распределять блоки равномерно вдоль горизонтальной или вертикальной оси, даже если они разных размеров.
HTML все же, если честно, заточен на оформление именно текста. Когда делаешь сложный интерфейс, флекс может быть полезен. Но у них конечно куча подвохов (например, при неудачном использовании он может картинки делать нулевого размера), поддерживается не везде, было 2 спецификации флекса, то есть нужная, но немного проблемная и сырая технология.
Как я понял, у человека была задача сделать меню прижатым слева, а поиск - прижатым вправо. При клике в поле поиска оно расширяется (левый край поля движется влево, правый остается на месте), возможно, наезжая поверх меню (на многих сайтах сейчас так делают). Я и предложил решения. Может я конечно задачу не так понял.
Тут https://theknacker.github.io/Test/index.html сделано что-то другое, поле поиска не прижато вправо.
тут https://theknacker.github.io/Test/index2.html поле не наезжает на меню при расширении, а проваливается вниз. Попробуй сделать, чтобы поле расширялось до 200px, а не 120, и увидишь.
https://theknacker.github.io/Test/index3.html та же проблема.
Я думаю, что нужно, чтобы поле поиска при расширении наезжало поверх меню, а не проваливалось вниз.
При этом в идеале это надо еще сделать адаптивно, чтобы на маленькой ширине экрана это тоже нормально работало.
> Но вот табличный способ если чесна первый раз слышу, интересно как он работает?
display: table/table-row/rable-body/table-cell. Лучше всего про них почитать в спецификации если не боишься, или в какой-нибудь статье. Заставляют элементы позиционироваться как таблицу. Соответственно, можно сделать таблицу из 2 ячеек.
> Чот ты нагородил тоже, не проще ли установить его статично и все?
Что значит статично? position: static? Не вижу логики.
> где эт флексы так используют
Там, где другие способы не годятся. Ты почитай спеку по флексам или хотя бы обзор на MDN. Ну например, если тебе надо сделать интерфейс, который разбивает экран на части и выравнивает их содержимое. Плюс, там можно задавать пропорции между этими частями.
Можно например распределять блоки равномерно вдоль горизонтальной или вертикальной оси, даже если они разных размеров.
HTML все же, если честно, заточен на оформление именно текста. Когда делаешь сложный интерфейс, флекс может быть полезен. Но у них конечно куча подвохов (например, при неудачном использовании он может картинки делать нулевого размера), поддерживается не везде, было 2 спецификации флекса, то есть нужная, но немного проблемная и сырая технология.
Причем, когда поле наезжает на меню, нужно, чтобы пункт меню, уходящий под поле поиска, плавно исчезал на протяжении 10-20 пикс. Не резко врезался в поле поиска, а плавно терял яркость. Надеюсь, ты понял идею.
Первая ссылка это я автору дал намек на его вопрос, остальные это имплементация слов вот тут написано >>1098576 (Гринтекст - ссылка как работает).
>Я думаю, что нужно, чтобы поле поиска при расширении наезжало поверх меню, а не проваливалось вниз.
При этом в идеале это надо еще сделать адаптивно, чтобы на маленькой ширине экрана это тоже нормально работало.
Ну как вопрос задал, так и ответили, зачем придумывать что-то еще? У него там зачем то JS стоит, айдишники повсюду и ни одного класса, я бы посоветовал спеку пойти читать.
>display: table/table-row/rable-body/table-cell. Лучше всего про них почитать в спецификации если не боишься, или в какой-нибудь статье. Заставляют элементы позиционироваться как таблицу. Соответственно, можно сделать таблицу из 2 ячеек.
Господи да спеку по CSS3 я уже изнасиловал. Я спросил кто этим пользуется и как оно выглядит. А не про поведение display параметра.
>Что значит статично? position: static? Не вижу логики.
Зафиксировать ширину элемента (Шапки например) чтобы поиск отталкивался просто от нее, не трогая другие элементы, я кстати так и сделал тут: https://theknacker.github.io/Test/index2.html
>HTML все же, если честно, заточен на оформление именно текста.
Изначально да, а потом напичкали всякими API и скриптами.
>>1098595
Вот это я пытался сделать, потом займусь. Типо так?
https://tympanus.net/codrops/
ну шторм.
А зачем в этом примере про регулярные выражения (с этой страницы взято: http://archive-ipq-co.narod.ru/l1/regexp.html ) вначале пишется ([0-9]{3}), а потом ([0-9]{7}) ? Это потому-что система не поймет, если сразу написать ([0-9]{10}) ?
Я сделал регулярное выражение для проверки автомобильного номера.
$regexp = '/([а-яё]{1})([0-9]{3})([а-яё]{2})/'
Все верно сделано?
https://regex101.com/ пишет, что да. Я протестил несколько вариантов, но вдруг что-то упусти.
register_shutdown_function тоже ничего не выводит.
Естественно выставлено:
error_reporting(E_ALL);
ini_set("display_errors", 1);
ini_set('display_startup_errors', 1);
Алсо, варнинги и нотайсы выводятся нормально. Что мне с этим делать?
Попробую.
>>1098675
Дело в том, что в учебнике автор выделяет часть. Если нам просто нужно было найти номер, то подошло бы и то, что ты написал. Но в данном случае мы проверяем на шаблон и выводим часть. Я возможно пишу плохо, потому что у меня нету навыков преподавания, поэтому попробую сразу примеры дать.
Формат номера такой 8(xxx)(xxxxxxx)
Где первая скобка - это код оператора, вторая - оставшийся номер. Благодаря этим скобкам, в учебнике ОП выводит код оператора. Без разделения на ([0-9]{3}) и ([0-9]{7}) этого бы не получилось.
Пример.
https://ideone.com/BV0u8L
Если ты про российский госномер, то "яё" в нём нет.
>ГОСТ для использования на знаках разрешены 12 букв кириллицы, имеющие графические аналоги в латинском алфавите — А, В, Е, К, М, Н, О, Р, С, Т, У и Х.
https://ru.wikipedia.org/wiki/Регистрационные_знаки_транспортных_средств_в_России
много чем. в первую очередь тем, что если ты используешь if exit, тебя нормальный работодатель пошлет нахуй.
а технологически отличие в том, что исключения можно ловить (т.е. обрабатывать) в одном удобном месте (или в разных для разных компонентов системы), логировать, классифицировать по степени критичности. какие-то, например, можно красиво упаковать и показать пользователю, а какие-то слать на имейл админу и пользователю показывать только заглушку "что-то временно не работает".
А ты случайно content-type: application/json в неправильном ответе не получаешь? Это не может быть баг в инструментах разработчика?
Если ты отправляешь AJAX через GET, попробуй открыть этот URL просто в браузере. Если через POST - поменяй временно PHP код, чтобы он принимал GET. И посмотри, что будет - тоже белая страница или нет?
Ну и ты показал вкладку Response, но я не вижу там ни кода ответа HTTP, ни заголовков. Даже если ты в скрипте сделаешь die(), то все равно будет HTTP ответ, с заголовками. Это может быть просто баг в инструментах разработчика.
Если у тебя есть под рукой другой браузер, например, Хром, посмотри еще в нем.
Также, ты можешь отправить HTTP запрос из командной строки программой curl (нужно ее установить сначала). Примерно так:
curl -v 'http://xxx/page.php?a=1'
В Хроме в отладчике есть удобная опция - там можно любой запрос скопировать как команду curl и вставить в командную строку, и увидеть, что реально приходит в ответ.
Ну и всегда есть радикальный вариант. Ты можешь посмотреть, какой запрос с какими заголовками отправляет аякс на вкладке Headers, и отправить такой же запрос руками через nc или telnet (описано тут в задачах https://github.com/codedokode/pasta/blob/master/soft/web-server.md )
Если бы у меня была задача просто проверить, что номер состоит из 10 цифр, то скобки конечно было бы не нужны. Но у меня другая задача - проверить номер И извлечь из него код города и телефон. Для этого я группирую первые 3 и последние 7 цифр в круглые скобки. После вызова preg_match она положит код города и номер в отдельные элементы массива $m:
if (preg_match($regexp, $string, $m)) {
}
В $m[0] будет номер целиком, то есть все, что совпадает с регуляркой
В $m[1] будет часть исходного текста, которая соответствует первым круглым скобкам, то есть код города
В $m[2] будет то, что соответствует вторым круглым скобкам.
exit завершает скрипт. То есть, когда ты пишешь в функции exit то она завершает скрипт. У того, кто вызвал функцию, нет возможности на это повлиять и предложить другой способ обработки ошибки.
Если ты выбрасываешь исключение, то по умолчанию оно тоже завершает скрипт. Но тот, кто вызвал функцию, может поймать выброшенное ей исключение и сделать что-то другое - например, записать информацию об ошибке в лог (информация содержится в объекте исключения) и попробовать вызвать какую-то другую функцию.
Подробно про исключения, с самого начала, с нуля: https://github.com/codedokode/pasta/blob/master/php/exceptions.md (нужно знать что такое объекты).
Нет, в моей регулярке из учебника нет "уступки" для других символов. Она написана для номеров только из цифр.
Два вопроса:
1.Можно ли вместо -?-? ? сделать запись , типа -,(, ,? ?
2.Как вообще запихивать скобки в регулярные выражения?
>Инструкции на сайте xdebug - они для ручной установки. То есть она пишет, какую dll тебе надо скачать, куда положить и что дописать в php.ini. Ты их выполнял?
Да
>cygwin
У меня установлен Babun, который является удобной упакованной версией cygwin
>найти пакеты по слову xdebug (pact find xdebug)
Не знаю, он ничего не находит, совсем
>Я кстати сам cygwin использую, ты можешь с его помощью потихоньку привыкать к линуксовой командной строке.
У меня Минт второй системой установлен
Я поискал тут https://cygwin.com/cgi-bin2/package-grep.cgi?grep=php&arch=x86_64 - действительно, xdebug нет. Нет, ну и ладно. В линуксоподобных системах должен работать pecl, который умеет скачивать любое стандартное расширение к PHP, собирать его и устанавливать. То есть pecl - это внутрненний менеджер пакетов для расширений PHP.
В cygwin он идет в пакете php-PEAR-1.10.1-1
Тебе нужно поставить этот пакет и выполнить команду, я думаю, pecl search xdebug, а затем pecl install имя-пакета.
Возможно, что пеклу понадобится компилятор и еще что-нибудь для сборки, установишь тогда его через pact.
-----
Или же ты можешь пользоваться виндовым PHP, но надо раскомментировать строку в php.ini, у тебя zend_extension закомментирован.
спасибо за помощь
Бамп вопросу.
20лвл-хуй.
Завтра иду в веб студию, вакансия битрикс junior.
Сам битрикс нихуя не знаю, но вообще шарю в пыхапе( знаю такие слова как ООП MVC и даже чутка понимаю что это)
Пилил самопис на php+mysql(pdo) чуть сложнее гостевухи. понимаю jquery. Писал парсеры/грабберы на пхп(подключая либы+импорт в wordpress на кроне) вооот все, нихуя больше... вроде умею гуглить и ваще в пхп вкатился по урокам Попова в 13 лет. + могу настроить LAMP+postfix на вдске.
Требования в вакансии: Требования: Обязательные знания: php5, sql, html, css, js, опыт работы с 1C-Bitrix.
Желательно понимание работы систем контроля версий (если что, научим), опыт работы с Linux-подобными ОС.
Что будут спрашивать на собеседовании? Меня возьмут? Что говорить?
Алсо зп 20к руб хД
Ебать, как же торможу, если 27-ой лвл и я только полгода поработал в саппорте CMS-ки.
Дрочил хуи Пояснял клиентам за функционал, тестил обнаруженные ими баги, правил их (иногда наши) шаблоны + ИНОГДА (!) помогал им разобраться, что за хуйня у них с серваками.
Типа, у одного было столько бэкапов, что они съели все свободное место на VDS, но вначале юзер пенял на нас.
https://gist.github.com/codedokode/8733007
>php5
>1C-Bitrix
>jquery
Тебе 20 лет, тебе развиваться надо, а не копаться в CMS параше, тем более в такой отборной как битрикс. Ищи работу за еду, где тебя научат нормально кодить на нормальных фреймворках. С CMS ты никуда не вырастешь, а лишь научишься профессионально месить говно, которое на более сложных проектах вообще не нужно.
1) Перехватывать исключения в теории можно двумя способами: неструктурно и структурно. Неструктурно — это когда мы задаем обработчик исключений в начале программы:
set_exception_handler(function ([Exception $exception) {
// Функция будет вызвана при возникновении исключения
});
То что я выделил жирным - это два тайп хинта?
2)// В try пишется код, в котором мы хотим перехватывать исключения
$users = loadUsersFromFile(...);
Это значит, что в переменную $users будут класться исключения?
3) $e->getMessage() это метод встроенного класса Exception ? И что она выводит?
это я. я тут придумал табличку tests, с графой questions, где json имени вопросов, типа и вариантов ответа. но тогда табличка разрастется до вселенских масштабов, нужно как-то это разрешить.
На сайте у этой же компании есть вакансия
Помощник веб-программиста Python
Требования:
Python, SQL, HTML, CSS, JS
Крайне желательно знакомство с framework Django или неутомимое желание его освоить.
Желательно знание Linux. Приветствуется владение системами контроля версий.
Если я завтра приду и скажу, битрикс НИУМЕЮ НИХАЧУ, можно мне ДЖАНГУ? норм тема?
алсо на питоне только говнопарсеры писал
ваще как вести себя на собеседовании? мне деньги нужны за квартиру платить бляяяяяя
>Если я завтра приду и скажу, битрикс НИУМЕЮ НИХАЧУ, можно мне ДЖАНГУ? норм тема? алсо на питоне только говнопарсеры писал
Ну да.
Зачем говорить, что ты не хочешь заниматься чем-то из вакансии А, если ты подал резюме на вакансию Б?
Если хочешь осваивать питон - осваивай, если хочешь пыху - ищи еще вакансии.
>>1099151
А если деньги нужны вот прям щас, то иди на эту работку, если она тебе эти деньги в ближайшее время гарантирует, а самообразованием тогда отдельно занимайся, только сделать это будет напорядок сложнее, т.к. практику выдумать себе придется самому.
Че ты как малой, тебе еще советов накидать как штаны надевать?
Епта, че у меня завтра спросят? Чем мне выебнуться, чтобы меня взяли джуном? Я просто никогда на собесы не ходил
Челябинск
двач дай советов мудрых
>тут придумал табличку tests, с графой questions, где json имени вопросов, типа и вариантов ответа.
Зачем хранить JSON в базе? Сделай нормальную реляционную схему. Надо изучать проектирование БД, а не лепить кривые костыли вместо изучения.
Есть тесты, есть вопросы, есть варианты ответов, они все связаны внешними ключами. Как положено.
Полистай этот урок https://github.com/codedokode/pasta/blob/master/db/databases.md#Теория-по-проектированию-БД там среди прочего упомянуты нормализация, разные полезные паттерны и наследование таблиц.
Почитай эти уроки http://jtest.ru/bazyi-dannyix/sql-dlya-nachinayushhix-chast-3.html
Подумай, какие тут есть сущности, какие у них свойства, как они связаны.
Также, могу предложить попробовать спроектировать базу данных для гостиницы из этой задачки >>1097078 - она проще, чем TestHub и на ней можно потренироваться. Потом базу для продюсерского агенства отсюда >>1094213
Ну то есть я предлагаю тебе позаниматься немного проектированием баз данных, так как у тебя тут явно не хватает опыта, и начать с простых тренировочных задачек.
>Чем мне выебнуться, чтобы меня взяли джуном?
Не советую делать этого в качестве джуна. Просто расскажи прямо и честно, что умеешь и чего хочешь уметь. Ты же на джуна метишь.
Спросят тебя об элементарных вещах. Почитай про протоколы, алгоритмы, подтяни SQL и самое главное закрой двач.
шаблонизаторы - в первый раз слышу =(
Серваки ну там бля, sudo apt-get instal lamp
POST/GET tcp/ip хуй знает
алсо я накатил тут
Так и быть, ОП даст тебе пасту про шаблонизаторы, выучив которую, ты, я думаю, сможешь поразить собеседующих: https://github.com/codedokode/pasta/blob/master/php/templates.md
Также, посмотри другие уроки в моем гитхабе, там полно ценной инфы, которую иначе надо по крупицам извлекать из разных источников.
>>1099199
Первый вопрос не понял, что ты имеешь в виду. Отвечу на второй.
Скобки можно запихивать в регулярные с помощью квадратных скобок "[]"
https://regex101.com/r/TQIKNp/1/
Тогда я не понимаю, почему не работает выражение:
[7-8] ?-?-?[(]?([0-9]{1}) ?-?-?[)]?([0-9]{1}) ?-?-?([0-9]{1}) ?-?-?([0-9]{1}) ?-?-?([0-9]{1}) ?-?-?([0-9]{1}) ?-?-?([0-9]{1}) ?-?-?([0-9]{1}) ?-?-?([0-9]{1}) ?-?-?([0-9]{1})
Для набора:
'84951234567', '+74951234567', '8-495-1-234-567',
' 8 (8122) 56-56-56', '8-911-1234567', '8 (911) 12 345 67',
'8-911 12 345 67', '8 (911) - 123 - 45 - 67', '+ 7 999 123 4567',
'8 ( 999 ) 1234567', '8 999 123 4567'
У тебя слишком много повторений. Может быть лучше попробовать использовать символ * который может и отсутствовать и повторятся любое количество раз?
Может быть лучше попробовать использовать символ * который позволяет предыдущему символу отсутствовать и повторятся любое количество раз. Я исправил.
Я хотел максимально расширить регулярное выражение, чтобы в него входили ВСЕ случаи.
Логика была такая:
1)Либо "8", либо "7".
2)Может быть пробел, дефис, минус, скобка, а может и нет.
3)Цифра
4)См. п 2.
5)Повторять до упада.
>1)Либо "8", либо "7".
[78]
>2)Может быть пробел, дефис, минус, скобка, а может и нет.
>3)Цифра
>4)См. п 2.
>5)Повторять до упада.
Можно упростить эту задачу. Смотри. После 8 или 7 идет цифра. Перед ней может быть пробел, дефис, минус, скобка, а может и нет. После нее тоже. И так пока цифры номера не закончатся. То есть получается однообразное действие. Может его повторить через {10}? ( десять - это количество цифр после 7 или 8)
Ты сделал просто поиск номера, а я написал вот что " После 8 или 7 идет цифра. Перед ней может быть пробел, дефис, минус, скобка, а может и нет. После нее тоже. И так пока цифры номера не закончатся. То есть получается однообразное действие. Может его повторить через {10}?"
то есть надо изменить это "([0-9]{10})" чтобы возможно был пробел, дефис, минус, скобка перед цифрой и после нее а возможно и нет.
Я понял.
https://regex101.com/r/1s0Jab/2
Проблема в том, что я не могу добавить что-то между ] и {10}
Есть страница с тегами типа <bodyexport>, как её прочесть?
Ошибки типа:
DOMDocument::loadHTML(): Tag noindex invalid in Entity
можно я по композеру бампану вопрос, раз тут все собрались
Я не могу понять зачем тебе это
?-?-?
Ведь есть символ * . Может попробовать лучше его использовать?
Анон, как фиксить?
Ну это статья про создание такого гемороя на JS, а я хочу распарсить его через DOM.
Или я чего-то не увидел?
Это плохая затея. Почитай про semantic versioning: https://semver.org/lang/ru/
Если библиотека обновит мажорную версию то с близкой к 100% вероятностью код сломается.
Конечно, если ты используешь composer.lock, то там само ничего не обновится, так как версии фиксируются в нем.
Что касается версий, я их наизусть не помню, и могу лишь предложить мануал https://getcomposer.org/doc/articles/versions.md
Или ты его уже прочел?
>>1099236
Ну он пишет, но тег-то создает? Ошибки подавляются с помощью libxml функций http://php.net/manual/ru/ref.libxml.php
>>1099245
255 ошибка значит по моему что программа не найдена.
А так, начинай отлаживать. Например, помести в bootstrap-файл строчку die("here\n"); и проверь, выводится она или нет. Если да - помести ее же в первый тест. ЧТобы понять, где падает.
Проверь, что phpunit вообще работает, выполнив команду вроде phpunit --help, phpunit --list-suites
У меня ощущение, что у тебя там die, либо вылетает фатальная ошибка/исключение, но отображение ошибок отключено.
Это плохая затея. Почитай про semantic versioning: https://semver.org/lang/ru/
Если библиотека обновит мажорную версию то с близкой к 100% вероятностью код сломается.
Конечно, если ты используешь composer.lock, то там само ничего не обновится, так как версии фиксируются в нем.
Что касается версий, я их наизусть не помню, и могу лишь предложить мануал https://getcomposer.org/doc/articles/versions.md
Или ты его уже прочел?
>>1099236
Ну он пишет, но тег-то создает? Ошибки подавляются с помощью libxml функций http://php.net/manual/ru/ref.libxml.php
>>1099245
255 ошибка значит по моему что программа не найдена.
А так, начинай отлаживать. Например, помести в bootstrap-файл строчку die("here\n"); и проверь, выводится она или нет. Если да - помести ее же в первый тест. ЧТобы понять, где падает.
Проверь, что phpunit вообще работает, выполнив команду вроде phpunit --help, phpunit --list-suites
У меня ощущение, что у тебя там die, либо вылетает фатальная ошибка/исключение, но отображение ошибок отключено.
>Движок от Википедии: https://github.com/wikimedia/mediawiki
>// Set a dummy $wgTitle, because $wgTitle == null breaks various things
>// In a perfect world this wouldn't be necessary
>$wgTitle = Title::makeTitle( NS_SPECIAL, 'Badtitle/dummy title for API calls set in api.php' );
Лол.
> У меня ощущение, что у тебя там die, либо вылетает фатальная ошибка/исключение, но отображение ошибок отключено.
Отображение ошибок включено В конфиге бутстрапа есть переменная неопределенная, так вот если раскомментить эту строчку - тест выдает нотис и после нее 255.
Если тест запускать без бутстрапа и автолоадинга классов, тогда тест успешно проходит, в консоли вижу текст типа " 1 тест запущен, 1 пройден (ок)"
В бутстрапе происходит создание приложения yii 1, где-то там косяк, но не пойму где.
Две черточки зачем нужны? У тебя символ читает только самую правую квадратную скобку, если хочешь, чтобы читало все - нужно добавить их в круглые скобки (тут должно быть что-то)
Я не совсем понимаю, как это сделать.
И да, в описании статьи говорится только про "предыдущий символ". Т.е. нужно как-то по-особому скормить набор символов злобной звездочке.
Тебе нужна рега на телефонные номера? Я тут недавно изъебался, но написал регу для адресов с вариативностью расположения улиц/домов/хуйни, мб могу помочь?
>
>Это плохая затея. Почитай про semantic versioning: https://semver.org/lang/ru/
о, спасибо огромное. это я хочу выкатить библиотеку и делаю мануал к ней. хотел, чтобы люди всегда ставили самую новую версию, но вместо этого лучше почитаю про то, как правильно придумывать им номера.
да, мануал композера смотрел, там как раз не нашел ответ на вопрос. а в интернетах увидел только варик @stable, что не похоже на best practice.
>Понятно. А как это скомбинировать с дефисами, минусами и пробелами?
Попробуй добавить их в квадратные скобки. Пробел если что значит \s
https://regex101.com/r/uhZ7xS/1
У phpunit есть опции -vv и --debug ( https://phpunit.de/manual/4.8/en/textui.html#textui.clioptions ) попробуй их добавить.
> создание приложения yii 1, где-то там косяк, но не пойму где.
Идешь в скрипт Юи, ставишь через строчку echo 1, echo 2 и так далее и постепенно ищешь этот exit. Может у тебя, кстати, в конфиге Юи отображение ошибок выключено?
У тебя там написано
--[(]
Это значит пробел, за ним идет 2 минуса подряд, за ним открывающая скобка. И далее ][)]* что значит 0 или больше закрывающих скобок.
Квантификаторы вроде зведочки применяются к последнему элементу, в данном случае к закрывающей скобке.
Чтобы применить звездочку к нескольким символам, их берут в круглые скобки:
(abc)*
Это соответствует пустой строке, строке abc, abcabc, abcabcabc и так далее.
Что касается ситуации с 10 цифрами, там надо написать так:
- сначала напиши "ровно 1 скобка, минус или пробел"
- затем напиши "любое число минусов, скобок или пробелов"
- затем напиши "любое число минусов, скобок или пробелов, за ними ровно 1 цифра"
- затем возьми это в скобки и припишеи повторение 10 раз: (....){10}
>>1099270
Если уточнить, то \s - это не только пробел, но и любой другой пробельный символ (символ, который не печатается или выгодит как пустое место), например: перевод строки \n, узкий пробел, неразрывный пробел, и тд. В Юникоде штук 10 разных пробелов есть на все случаи жизни: http://jkorpela.fi/chars/spaces.html и символ \s всем им соответствует.
У тебя там написано
--[(]
Это значит пробел, за ним идет 2 минуса подряд, за ним открывающая скобка. И далее ][)]* что значит 0 или больше закрывающих скобок.
Квантификаторы вроде зведочки применяются к последнему элементу, в данном случае к закрывающей скобке.
Чтобы применить звездочку к нескольким символам, их берут в круглые скобки:
(abc)*
Это соответствует пустой строке, строке abc, abcabc, abcabcabc и так далее.
Что касается ситуации с 10 цифрами, там надо написать так:
- сначала напиши "ровно 1 скобка, минус или пробел"
- затем напиши "любое число минусов, скобок или пробелов"
- затем напиши "любое число минусов, скобок или пробелов, за ними ровно 1 цифра"
- затем возьми это в скобки и припишеи повторение 10 раз: (....){10}
>>1099270
Если уточнить, то \s - это не только пробел, но и любой другой пробельный символ (символ, который не печатается или выгодит как пустое место), например: перевод строки \n, узкий пробел, неразрывный пробел, и тд. В Юникоде штук 10 разных пробелов есть на все случаи жизни: http://jkorpela.fi/chars/spaces.html и символ \s всем им соответствует.
Читай ООП, выбирай любой фреймворк(всё равно сложно в начале будет), смотри его структуру(MVC чаще всего) и разбирайся. Официальная документация обычно хорошо написана, и гайдики по первому приложению есть.
>>1099280
Господа, я вам настоятельно рекомендую начать экранировать тире и прочие подобные символы, чтобы потом не обосраться где-нибудь. От лишнего бэкслеша ничего не сломается.
Может с микрофреймворка Slim или Silex ? Микрофреймворк он простой, ты можешь его код целиком прочитать если надо.
Сделать можно (прорекламирую) задачу на студентов из Оп поста. На ее примере ты научишься работать с формами, шаблонами, базой данных и тд. К ней идут подробные комментарии.
Потом можешь брать Юи, Ларавель или Симфони.
>>1099257
Если у тебя есть отладчик (например в IDE) и xdebug, можно попробовать запустить код из-под него и пошагово место завершения, но phpunit, может быть применяет всякие хаки и как бы от них отладчик не сломался.
Но вообще, было бы полезно тебе поучиться пользоваться отладчиком.
>>1099190
Почитай урок про интерфейсы https://github.com/codedokode/pasta/blob/master/php/interfaces.md
Это вообще разные вещи и даже сравнивать их между собой не очень логично.
Алсо, если это задают на собеседовании, и ты видишь, что проваливаешься, спроси, а есть ли у них в проекте интерфейсы и абстрактные классы и как используются. И затем объясни им, что они просто их используют "чтобы были", не думая, нужны ли они на самом деле, и код от этого не становится лучше. И объясни как на самом деле их надо использовать.
Да, и ведь в уроке про исключения по моему про это в конце написано, как раз про эту страницу. Логгировать только ошибку не забывай.
Спасибо за ответ.
>А ты случайно content-type: application/json в неправильном ответе не получаешь? Это не может быть баг в инструментах разработчика?
Нет, text/html, на скрине заголовки типичного пустого ответа.
>Если ты отправляешь AJAX через GET, попробуй открыть этот URL просто в браузере. Если через POST - поменяй временно PHP код, чтобы он принимал GET. И посмотри, что будет - тоже белая страница или нет?
Пробовал отправлять форму через расширение для хрома (RESTED) в разных кодировках json, urlencoded, эффект тот же самый, пробовал разные браузеры и разные сборки (на работе XAMPP + win, дома linunx + nginx). Из всех своих потуг, понял что проблема в middleware, то есть если запрос обрабатывается middleware то ошибка не выводится, неважно где допущена сама ошибка внутри middleware или внутри самого приложения, например прямо в контроллере - выведена она не будет. Допустим мы отправляем json с формой логина, а в контроллере допущена синтаксическая ошибка, если контроллер покрыт миддлварс то получаем пустой ответ, либо если было eсho или другой вывод в middleware он будет выведен, но текста ошибки все-равно не будет. Убираем middleware и получаем нормальный синтакс еррор. Шизняк какой-то. Если будет желание разобраться, то
Вот мой файл с роутами: https://github.com/honeydev/fileshare/blob/master/app/Routes.php
Вот контроллер:
https://github.com/honeydev/fileshare/blob/master/app/Controllers/MainPageController.php
Вот миддлварсы:
https://github.com/honeydev/fileshare/tree/master/app/Middlewares
Сап, почаны! Помогите вникнуть в логику циклов. Третий урок из начальных. Почему, когда я присваиваю в Условии_1 $x=10000, то программа считает, что на счету через год будет та же сумма (10000) https://ideone.com/hNqkv9 ? Когда я выношу команду echo за пределы тела цикла, оно отображает действительную сумму больше миллиона через 49 лет, вкладчику 65 лет (ответ правильный). Получается, что есть разница, где писать echo: если в теле цикла, то echo выводит на экран результаты вычисления до того момента, когда условие выполняется, но почему echo за телом цикла показывает результат, когда условие цикла уже не выполняется? https://ideone.com/juIFDU
Подскажите, где я делаю ошибку?
А, всё понял: в первый год нужно тоже добавлять процентную ставку, т.е. в Условие_1 тоже нужно прописать $x=$pay*1.1 . Остаётся вопрос про echo. Почему echo после тела цикла выдаёт значение, при котором условие уже не выполняется?
Нашел проблему: у меня все приложение крутится в Докере, там порт для БД 8002 и другой пароль, я же запускал тесты вне докера с другими переменными доступа к БД на 5432 порт. И это фейлилось без ошибок, что странно.
Вообще в Yii много мест, где БД фейлится без ошибок. Уже такое было в системном логгере, когда в одно из полей поступал странный символ в неизвестной кодировке. Просто логгер ничего не логгировал и молчал.
я тут случайно наткнулся на некоего чувака, который заявляет следующее:
1. заканчивать названия объектов на -er - это анти ооп http://www.yegor256.com/2015/03/09/objects-end-with-er.html
2. составные имена типа textLength - это code smell, т.к. скоуп данной переменной слишком большой http://www.yegor256.com/2015/01/12/compound-name-is-code-smell.html
3. пустые строки - это тоже code smell, т.к. они означают, что метод не соблюдает принцип единой обязанности. http://www.yegor256.com/2014/11/03/empty-line-code-smell.html
он там еще много всего заявляет, притом он вроде не из серии "ооп это грех, покайтесь господу", он там какие-то награды раздает за код, вот например им https://github.com/php-ai/php-ml (я так на него и наткнулся)
что ты думаешь об этих идеях? это полная хуйня или он прав?
просто так-то все это звучит логично, но вот например
public function validateEmail($email)
{
if (!StringUtil::isEmail($email)) {
$message = sprintf('"%s" is not a valid login', $email);
throw new InvalidArgumentException($message);
}
return true;
}
чем тут мешает пустая строка? мне наоборот кажется, они улучшают читаемость кода, а упростить его еще дальше тут хз как.
и если он прав, то не слишком ли это высокие материи, чтобы задумываться о них на джун-уровне?
И ещё вопрос про программу с айфоном в кредит из того же урока. Нашёл решение задачи, но оно какое-то кривое и мне не нравится (сука, говнокод уже со старта выходит какой-то) https://ideone.com/8BK2Rq
Правильно ли я решил задачу, и можно ли её оптимизировать? Спасибо.
не до конца понял вопрос. что значит "после echo тело цикла выдает значение"? после echo оно уже ничего не выдает, т.к. цикл не выполняется.
если ты спрашивал "почему значение x больше миллиона, хотя в цикле указано условие чтобы икс был меньше миллиона", то у тебя же идет сначала условие выполнения ЦИКЛА x<1000000, а затем этот x умножается на 1.1. цикл поэтому и не выполняется, а значение увеличивается.
также посмотри, что такое пост-инкремент и используй лучше его, чем +1.
Немного не в том вопрос. Почему, если echo я вставляю после тела цикла, то программа выполняет его до тех пор, пока на счету не будет больше миллиона и результатом выводит 49 лет, миллион с копейками, а если echo находится внутри цикла, то программа выдаёт 48 лет и сумму, в которой не хватает ещё одного выполнения цикла до выполнения условия х>1000000?
Песдец я криво выражаю мысли
ты нормально выражаешь мысли, просто я тебе на этот вопрос и ответил. программа выполняет цикл всегда одно и то же количество раз независимо от того, где находится echo. echo просто выводит текущее на данный момент значение переменной, а оно разное 1. до цикла, 2. в каждой новой итерации цикла, 3. после цикла.
цикл выполняется допустим 10 раз. все это время условие цикла верно, и поэтому интерпретатор не выходит из этого цикла дальше по коду (на echo, которое после него). на 11-й условие цикла уже не верно, т.е. x уже больше миллиона. тогда не интерпретатор не выполняет цикл, а идет вниз по коду и видит там echo, и выводит значение x, которое больше миллиона.
если же echo лежит внутри цикла, то там никогда не может быть x больше миллиона. соответственно и год - 48, а не 49. чтобы понять, представь, последовательность, с которой выполняется код. можешь там блок-схему нарисовать.
инкремент лучше хотя бы потому, что $y++ короче, чем $y = $y + 1. и еще потому, что это по сути не арифметическое действие, а счетчик, т.е. семантически это более верно.
Так получается если echo стоит внутри цикла, то цикл выполняется 10 раз, а если за циклом, то 11, но на 11 раз это уже не цикл, а простой код?
Спасибо, няша, добра тебе.
Что касается ситуации с 10 цифрами, там надо написать так:
- сначала напиши "ровно 1 скобка, минус или пробел"
- затем напиши "любое число минусов, скобок или пробелов"
- затем напиши "любое число минусов, скобок или пробелов, за ними ровно 1 цифра"
- затем возьми это в скобки и припишеи повторение 10 раз: (....){10}
Но я не знаю, где может быть, а может и не быть скобка! Подразумевается, что пользователь может быть поехавшим и написать хоть (911) 123 45 67, что (911) (123) (45) (67)!
на 11-й уже не цикл, верно.
Да, прикинь, возврат из оператора условия из середины функции — это что-то плохое.
Типичный же случай, когда макака начинает учить других макак.
братка, виды отношений знаю, работал.
я рассматривал вариант разделения сущностей на : тесты, вопросы, ответы, прописывая внешние ключи.
по поводу json:
табличка tests,
табличка questions со столбиком questions (json данных по вопросу - тип, варианты ответа).
нуб
Спасибо за чтиво. Там в комментах его называют троллем от ООП. Тоже хочу мнение ОПа на его статьи.
Ебать меня понесло из-за тебя. https://ideone.com/DazJGT
Во-первых, названия таблиц должны быть в единственном числе и мелкими буквами: "test", "question".
Во-вторых, не храни JSON и XML в таблицах, об этом ещё Андрей Орлов писал, в 90-е уже все грабли посчитаны были.
табличка tests,
табличка questions,
табличка answers,
табличка tags,
табличка tests_to_tags
только что набросал, так более менее?
По поводу названий предлагаю ориентироваться на этот гайд http://www.sqlstyle.guide/ru/
> Используйте собирательные имена или, что менее предпочтительно, форму множественного числа. Например, staff и employees (в порядке убывания предпочтения).
>>1099641
Нормально, но ты не учел, что бывают разные типы вопросов и ответов (числовые, текстовые, с выбором). И получается типичное наследование таблиц.
спасибо, я в sql почти что ноль, все хотел подтянуть, но руки не доходили. благодарю, что направил и мотивировал.
>разные типы вопросов и ответов
думал проскочить, сделав в type_answer
https://github.com/codedokode/pasta/blob/master/php/templates.md
Решил опробовать код и выдает ошибку
Parse error: syntax error, unexpected end of file, expecting elseif (T_ELSEIF) or else (T_ELSE) or endif (T_ENDIF) in C:\Apache24\htdocs\student\template.html on line 13
Почему?
Вот шаблон
https://ideone.com/BhgZOK с расширением .html
Вот логика
https://ideone.com/4giVWT с расширением .php
<?php if ($result): ?>
<?php else: ?>
<?php endif; ?>
короткие теги <? уже не используются и их выключают в настройках php
Спасибо большое, помогло.
Что означает знак вопроса двоеточие и ноль тут?
У меня указано 10 итераций по принципу "вначале может быть какой-то символ, а потом число", но получается, что каждый символ съедает один подход.
Как указать, что {10} - это не для вас, молодой человек спец. символов и пробелов, а только для чисел?
Если у тебя номеров очень много будет, то ручками придется убирать плюсик, а это очень долго, скучно, нудно, однообразно, верно?
Можно заменить плюсик на ничего с помощью preg_replace или в регулярку забить +7 или 8 чтобы искало
Спасибо большое.
>+7
Просто так низя, ибо ОП сделал вариант "+ 7".
Я записал так (8|\+\ *7) , но регулярка срабатывает на +8.
>Просто так низя, ибо ОП сделал вариант "+ 7".
Что мешает искать +,пустое пространство которое возможно много раз или нет, семь или восемь вместо всего этого?
Это я уже решил. Единственная проблема - как заставить систему не тригериться на +8?
накалякал быстро. что-то типо этого. смотри, там идет +,пустое пространство от 0 до бесконечности, 7 ИЛИ 8 вместо всего что было до
https://regex101.com/r/jGHwK6/1
Лол, у тебя не работает, если использовать примеры ОП-а:
'84951234567', '+74951234567', '8-495-1-234-567',
' 8 (8122) 56-56-56', '8-911-1234567', '8 (911) 12 345 67',
'8-911 12 345 67', '8 (911) - 123 - 45 - 67', '+ 7 999 123 4567',
'8 ( 999 ) 1234567', '8 999 123 4567'
incorrectNumbers = [
'02', '84951234567 позвать люсю', '849512345', '849512345678',
'8 (409) 123-123-123', '7900123467', '5005005001', '8888-8888-88',
'84951a234567', '8495123456a',
'+1 234 5678901', / неверный код страны /
'+8 234 5678901', / либо 8 либо +7 /
'7 234 5678901' / нет + /
Верный. На нем ты составляешь регулярное выражение. preg_match проверяет, соответствует ли данное значение шаблону, который мы написали и если все окей, то возвращает 1.
С помощью этих знаний, можно попробовать сделать условие, которое будет отрасывать все, что не попадает под регулярное.
https://ideone.com/3pTSSD
GET.
Если я хочу создать две формы, которые считывают числа и выводят их сумму, то что лучше?
формы
https://ideone.com/leEIwL
скрипт
https://ideone.com/vyBa8T
Если что я новичок. Сделал задачу про вектор, но ужаснулся студентов и не знаю, что дальше делать
Короткий ответ: Файл не исполняется в лоб построчно. Если функция в этом же файле, PHP ее найдет.
Вот это уже упадет с ошибкой:
<?php
foo();
require_once "file_with_foo.php";
Тебе никто не отвечает, потому что ты не сформулировал вопрос. Более того, во всём твоём посте даже знака вопроса нет, шизик )))
За два месяца реально вкатиться только в двухмесячного вкатывальщика, нодискасс.
Лучше сразу приучить себя к IDE, из бесплатных -- Eclipse, из платных -- phpStorm
> 1)
Здесь написано, что параметром функции1 set_exception_handler должно быть имя функции2, в свою очередь принимающей в качестве параметра объект типа 'исключение'
Мануал с примерами: http://php.net/manual/ru/function.set-exception-handler.php
> 2)// В try пишется код, в котором мы хотим перехватывать исключения
> $users = loadUsersFromFile(...);
> Это значит, что в переменную $users будут класться исключения?
Нет. В блоке try { } обычный код твоей программы, который должен выполняться без ошибок. Обработка исключений(ошибок) -- в блоке catch {}
> 3) $e->getMessage() это метод встроенного класса Exception ?
Да
> И что она выводит?
http://php.net/manual/ru/exception.getmessage.php
<?php
try {
throw new Exception("Какое-нибудь сообщение об ошибке");
} catch(Exception $e) {
echo $e->getMessage();
}
> 1)
Здесь написано, что параметром функции1 set_exception_handler должно быть имя функции2, в свою очередь принимающей в качестве параметра объект типа 'исключение'
Мануал с примерами: http://php.net/manual/ru/function.set-exception-handler.php
> 2)// В try пишется код, в котором мы хотим перехватывать исключения
> $users = loadUsersFromFile(...);
> Это значит, что в переменную $users будут класться исключения?
Нет. В блоке try { } обычный код твоей программы, который должен выполняться без ошибок. Обработка исключений(ошибок) -- в блоке catch {}
> 3) $e->getMessage() это метод встроенного класса Exception ?
Да
> И что она выводит?
http://php.net/manual/ru/exception.getmessage.php
<?php
try {
throw new Exception("Какое-нибудь сообщение об ошибке");
} catch(Exception $e) {
echo $e->getMessage();
}
Выебоны не по делу, важен результат
>>1099139
Короче, блэт,
<?php
try {
//Тут код нашей программы
$a = 2*2;
//Который мы проверяем
if ( $a !== 4 )
throw new Exception("Пиздос!");
} catch(Exception $e) {
//А тут обработка ошибок. Можно показать её, записать в лог, отправить себе на имейл и т.д.
echo $e->getMessage();
//в некоторых случаях можно попытаться её исправить
$a = 4;
//или остановить программу
exit(1);
}
Тебе нужна функция array_key_exists(). in_array() ищет по значениям, а не по ключу.
Спасибо, добрый анон.
Понятно.
Так-с, теперь у меня 2 вопроса:
1.Как логически указывается, чтобы пробел/дефис/что-то ещё не считалось за цифру?
2.Как указывать жесткое "или", чтобы не срабатывало на +8?
Garbage Collector
Убирается в офисе, что непонятного?
у меня есть опыт работы джуниором в дс без переезда лол. думаю, имеет смысл сначала прокачаться по максимуму (может, что-то на фрилансе поделать), сделать какое-то портфолио на гитхабе, потом приехать в дс, снять комнатку и уже параллельно искать работу. а получить оффер из дс, находясь в мухосранске, мне кажется, очень сложно. надо быть прямо на голову выше местных дсшных студентиков и перекатившихся.
плюс в дс есть определенные конторы-потогонки, которые набирают студентов работать по 12 часов в день за гроши и типа их "выращивают". они могут заинтересоваться чуваком, который будет полностью от них зависим. я в такой работал, это на любителя, хотя и прокачивает хорошо.
Будет что внукам рассказать!
не то чтобы говнокодишь, там большой проект и нормальный аудит. через год такой работы я пошел на другую за норм бабки
Ещё один бамп вопросу
>Как логически указывается, чтобы пробел/дефис/что-то ещё не считалось за цифру
Пробел/дефис/что-то кроме цифры никогда не считается за цифру. Переформулируй вопрос.
>Как указывать жесткое "или", чтобы не срабатывало на +8?
(+7|8)
Андвансед левел, чтобы не засорять бэкрефы - (?:+7|8)
Теперь результат совпадения этой подмаски не будет сохранен в массиве $matches.
ну пойдешь курьером поработаешь месяц, если не получится. а потом работу джуном в дс не так сложно найти, если знания есть.
>Пробел/дефис/что-то кроме цифры никогда не считается за цифру. Переформулируй вопрос.
Я написал, может быть херовое, но такое выражение:
[- \(-\(\)\d]{10})
Т.е. вначале может быть, а может и не быть знак, а потом идет число.
Система засчитывает любой символ, как одно из 10-ти значений, которые нужно найти.
Вот скрины. +8 проглатывается.
>>1100079
>У меня денег только на первый месяц проживания в ДС
Ну так иди в какой-нить саппорт по-приличнее, чтобы
1)Опыт работы в ДС появился.
2)Бабло было на поиски.
Но да, может случиться "проклятье острова Баунти".
Вдогонку. Чтобы не трахаться с пробелами и дефисами, просто сделай strtr($phoneNumber, [' ' => '', '-' => '', '(' => '', ')' => '']); перед сравнением с регуляркой.
А то я заметил, что + 7 у тебя тоже должно матчится. Да и к тому же, ты не сможешь предугадать, куда твой юзер поставит пробелы, дефисы и даже скобки.
https://ideone.com/uwW1i1
Но если ты хочешь заморочиться и решить все регулярками, то даю подсказку.
Кстати, в реальной жизни может быть так и даже так. ОП как-то не подумал.
ага, в симфони наверное тоже пишут и аудируют код макаки
https://github.com/symfony/symfony/blob/ed2222bb855fe3006509d4570ab0bc9f78b5b69d/src/Symfony/Component/Workflow/Workflow.php#L159
только вася с двача знает как правильно.
прикинь, возврат и завершение скрипта с помощью throw - это разные вещи
За месяц учёбы по учебнику ОПа через день по вечерам, только закончил регулярки. Я совсем глупый или это норм?
Нормально, просто у тебя нет временных рамок. Если бы ты работал и тебе на работе дали такое же задание с указанием "сделать к вечеру", ты бы скорее всего сделал его к вечеру или к ночи.
btw будет совсем правильно поставить флаг httpOnly = true. Будет больно, потому что он в самом конце необязательных параметров.
Изучи, какие параметры есть у кук.
Ты не указал параметр path. Это значит, что для куки он будет выставлен по умолчанию как путь к скрипту - например, /folder/script.php. Когда у тебя один скрипт, это не проблема, но когда их много, кука будет видна не везде.
Лучше сразу привыкать ставить /, чтобы кука была доступна на всем сайте, а не только в одном скрипте.
Лол, в треде 7.1 сегфолтится, а вы еще и релиз кандидат накатываете? Храбрые вы парни.
Все бы ничего, но php и web в целом до этого не трогал вообще, сейчас сижу и не понимаю за что хвататься-то, как хоть что-то сделать, помогите советом
добавлю: всё писалось изначально на 7,
если на 5 -- может быть, и возможны проблемы, мы не знаем
[quote user="codedokode"]
Есть Гостиница, в ней есть Номера. Для каждого Номера известен его номер,
количество Гостей, которое в него влезет, а также цена за сутки. В Гостиницу
приезжают Гости. Нужно сделать ООП-модель Гостиницы с такими возможностями:
- получить список свободных номеров на определенную дату
- получить список свободных номеров, которые будут свободны в определенный
диапазон дат (от A до B)
- дан список Гостей и диапазон дат, в которые они хотели бы заселиться. Необходимо
подобрать им самый дешевый и маленький Номер, который их вместит и который
свободен в это время.
- то же самое, но при отстутствии одного подходящего номера для Гостей разрешается
заселить их в несколько номеров, опять же, начиная с самых дешевых. Например,
приехало 3 Гостя, но все 3-местные номера заняты и мы выделяем 2 2-местных, или 3
1-местных или 1-местный + 2-местный.
- зарегистрировать проживание данных Гостей в данных Номерах на данный период
- получить историю заселения Номера (кто в нем когда жил)
- получить историю заселения Гостя (в каких номерах он жил)
- получить статистику доходов Гостиницы за данный диапазон дат (в день A отдель
заработал X тугриков, в день B - Y тугриков и так далее)
-------------------
Сделать достаточно только ООП-модель, то есть классы (но конечно можно для
проверки дописать код, который проверяет, что все сложные методы работают). Для
представления даты в PHP есть класс DateTimeImmutable (
http://php.net/manual/ru/class.datetimeimmutable.php ), почему я рекомендую его, а
не DateTime, подумай сам.
[/quote]
Правда, я еще реализую код, проверяющий все это - строящий отель, заселяющий гостей, и т.д.
[quote user="codedokode"]
Есть Гостиница, в ней есть Номера. Для каждого Номера известен его номер,
количество Гостей, которое в него влезет, а также цена за сутки. В Гостиницу
приезжают Гости. Нужно сделать ООП-модель Гостиницы с такими возможностями:
- получить список свободных номеров на определенную дату
- получить список свободных номеров, которые будут свободны в определенный
диапазон дат (от A до B)
- дан список Гостей и диапазон дат, в которые они хотели бы заселиться. Необходимо
подобрать им самый дешевый и маленький Номер, который их вместит и который
свободен в это время.
- то же самое, но при отстутствии одного подходящего номера для Гостей разрешается
заселить их в несколько номеров, опять же, начиная с самых дешевых. Например,
приехало 3 Гостя, но все 3-местные номера заняты и мы выделяем 2 2-местных, или 3
1-местных или 1-местный + 2-местный.
- зарегистрировать проживание данных Гостей в данных Номерах на данный период
- получить историю заселения Номера (кто в нем когда жил)
- получить историю заселения Гостя (в каких номерах он жил)
- получить статистику доходов Гостиницы за данный диапазон дат (в день A отдель
заработал X тугриков, в день B - Y тугриков и так далее)
-------------------
Сделать достаточно только ООП-модель, то есть классы (но конечно можно для
проверки дописать код, который проверяет, что все сложные методы работают). Для
представления даты в PHP есть класс DateTimeImmutable (
http://php.net/manual/ru/class.datetimeimmutable.php ), почему я рекомендую его, а
не DateTime, подумай сам.
[/quote]
Правда, я еще реализую код, проверяющий все это - строящий отель, заселяющий гостей, и т.д.
а трогал всякий десктоп, в принципе, подобие того, что просят делал, но на шарпе с wpf-ом.
А PHP потому что пытаюсь податься на стажировку и просят там тестовое именно на PHP
>Насчет данных с paypal - не знаю, скорее всего нет. Но думаю, они будут доступны для американской разведки.
Скорее для российской. Я сомневаюсь, что в условиях информационной войны, российские спец.службы позволят владеть данными своих граждан. Если конечно, они не было получины задолго до этого.
>Авторское право © PayPal, 1999–2017 гг. Все права сохранены. Общество с ограниченной ответственностью Небанковская кредитная организация «ПэйПал РУ». Юридический адрес: Российская Федерация, 125047, Москва, ул. Бутырский Вал, д. 10. Деятельность осуществляется на основании лицензии Центрального банка России № 3517-К.
Но у российской разведки уже есть мои данные, так что волноваться не о чём.
>> Мне видеться использовать JSON-объект с свойствами каждого вложения.
>Скорее всего что-то такое и было.
Я думаю, вот можно было для какой-нибудь сущности иметь колонку temp с типом JSON и сохранять туда какие-нибудь второстепенные/временные/неважные данные. Можно былоо бы гибче обращаться с записями. Как вам идея?
>- кеширование - кеш снижает нагрузку на чтение из БД, при условии, что запросы повторяются, и что обновление данных происходит реже, чем чтение.
Можете посоветовать какой-нибудь софт/библеотеку для этого?
>> Как можно заранее построить схему, если со временём неизбежно придётся что-то менять, а данных слишком много?
>Вот ты думаешь, что проблема - это слишком много данных, а реальная проблема - это то, что у тебя слишком мало пользователей. Если у тебя будет очень много пользователей, то скорее всего и будет много денег для покупки серверов.
>
>А так, сохранять стоит все, что есть.
Нет, я имел ввиду что структура таблицы может поменяться и старые данные могут не соответствовать этой структуре.
К примеру, что-то не предусмотрели, например, понадобилось в список чатов добавить ещё время добавления пользователя в чат, но уже в созданных чатах есть добавленные пользователи и невозможно получить их время добавления.
Нужно заранее подготавливать "правильную" структуру, но такое было бы возможно если бы прогресс стоял на месте.
Но я только что понял, что такой вопрос нужно решать на стадии миграции.
>Насчет данных с paypal - не знаю, скорее всего нет. Но думаю, они будут доступны для американской разведки.
Скорее для российской. Я сомневаюсь, что в условиях информационной войны, российские спец.службы позволят владеть данными своих граждан. Если конечно, они не было получины задолго до этого.
>Авторское право © PayPal, 1999–2017 гг. Все права сохранены. Общество с ограниченной ответственностью Небанковская кредитная организация «ПэйПал РУ». Юридический адрес: Российская Федерация, 125047, Москва, ул. Бутырский Вал, д. 10. Деятельность осуществляется на основании лицензии Центрального банка России № 3517-К.
Но у российской разведки уже есть мои данные, так что волноваться не о чём.
>> Мне видеться использовать JSON-объект с свойствами каждого вложения.
>Скорее всего что-то такое и было.
Я думаю, вот можно было для какой-нибудь сущности иметь колонку temp с типом JSON и сохранять туда какие-нибудь второстепенные/временные/неважные данные. Можно былоо бы гибче обращаться с записями. Как вам идея?
>- кеширование - кеш снижает нагрузку на чтение из БД, при условии, что запросы повторяются, и что обновление данных происходит реже, чем чтение.
Можете посоветовать какой-нибудь софт/библеотеку для этого?
>> Как можно заранее построить схему, если со временём неизбежно придётся что-то менять, а данных слишком много?
>Вот ты думаешь, что проблема - это слишком много данных, а реальная проблема - это то, что у тебя слишком мало пользователей. Если у тебя будет очень много пользователей, то скорее всего и будет много денег для покупки серверов.
>
>А так, сохранять стоит все, что есть.
Нет, я имел ввиду что структура таблицы может поменяться и старые данные могут не соответствовать этой структуре.
К примеру, что-то не предусмотрели, например, понадобилось в список чатов добавить ещё время добавления пользователя в чат, но уже в созданных чатах есть добавленные пользователи и невозможно получить их время добавления.
Нужно заранее подготавливать "правильную" структуру, но такое было бы возможно если бы прогресс стоял на месте.
Но я только что понял, что такой вопрос нужно решать на стадии миграции.
Спасибо. Я когда вектор говношлепал тоже вышло много строчек а толкового ничего. Переделывал полностью раза три все с горящим пердаком.
Для специалиста (но не факт, что тебя, как я понял) по шарпу освоить синтаксис PHP -- не такая уж большая проблема, значит -- кури в первую очередь официальный мануал: http://php.net/manual/en/
Тебе понадобятся азы (переменные, приведение типов, функции, строковые функции, ООП),
и, если просят работу с БД, то раздел PDO.
Не поспоришь. Но ничего. Мой максимализм еще никому не удалось победить!
>дан список Гостей и диапазон дат, в которые они хотели бы заселиться. Необходимо подобрать им самый дешевый и маленький Номер, который их вместит и который свободен в это время.
На данный момент я пренебрегаю ценой, но селю каждую партию гостей в минимально маленький номер.
Допустим, у меня два номер, за 1000 тугриков для двоих, и за 500 для троих. И две группы гостей - двое и трое. Я селю двоих в номер за 1000 и троих за 500. То есть двое могли сэкономить, засели я их в номер для троих, но тогда бы я не смог заселить группу из троих человек.
Я правильно понимаю, что подразумевается, я должен заселить максимальное количество человек, а не экономить им деньги и оставлять кого-то на улице?
Тогда я все правильно делаю.
Но есть еще вопрос.
Допустим, у меня есть два трехместных номера, один за 300, другой за 500. И две заявки, номер 0 - на троих персон и номер 1 - на одного. Сейчас я обрабатываю их по порядку, и выходит, что три человека заселятся в номер за 300, а один - за 500. Но по факту мне пофиг, кого куда селить в такой ситуации, бабло я получу, а вот бедный одиночка будет платить 500 тугриков, а троица - по сотне с носа.
Должен ли я проявлять человечность и в таком случае селить одиночку в номер за 300?
Накой ты за них вообще решаешь? Выдавай им варианты, пусть сами думают куда им заселяться.
Я же объяснил в >>1100105.
?: - именно в такой комбинации - не запоминать результат в скобках. Всегда пишется сразу после открывающей скобки. Можешь безболезненно убрать эти символы, тут это лишнее, если тебе нужно просто сравнить строку с регуляркой. У меня просто привычка не засирать массив с результатами, пишу на автомате.
>Это имеется в виду, когда говорится, что можно так украсть кукисы и прочие данные?
Да.
>Как можно запретить вводить скрипт в эштиэмэль формы?
Никак, ты должен применять htmlspecialchars($text) при выводе пользовательских текстов.
Спасибо за ответ.
> ты должен применять htmlspecialchars($text) при выводе пользовательских текстов.
Можно пример пожалуйста?
>Можно пример пожалуйста?
echo htmlspecialchars('<script>alert('hi');</script>');
Результат отобразится как простой текст.
>>1100326
Back references, обратные ссылки. В них по умолчанию сохраняется содержимое скобок. Они же кладутся в массив $matches. В регулярке доступны в виде $цифра либо \цифра. Например, ловим парные html-теги: /<(div|a|b)>.*?</$1>/g.
Если не понял, ни ссы, еще поймешь. С регулярками всегда так.
Фикс примера: echo htmlspecialchars("<script>alert('hi');</script>");
>htmlspecialchars('<script>alert('hi');</script>');
Спасибо. А как сделать если через форму?
Допустим у меня вывод формы echo $_GET["text"];
он все равно выводит нежданный скрипт
Извиняюсь, я понял. Все. Выводит нормально
>>1100286
Советую обязательно решить. Ваши мучения не пропадут даром. В большинстве учебников, а тем более в видеокурсах на ютубе, вам никто нормально ООП не объяснит. В лучшем случае вас заставят вызубрить дословно 3 определения принципов ООП (инкапсуляция/наследование/полиморфизм, и может быть, SOLID), которые вы не поймете, и расскажут как объявить класс. А на задачах про Гостиницу и про Продюсерское Агенство вы более-менее сможете увидеть реальное применение ООП, как оно облегчает написание кода за счет разбиения на отдельные классы (если думаете, что не облегчает, попробуйте без классов решить). Научитесь проектировать ООП-модель для задачи.
Надеюсь, что в итоге вы будете сильнее тех кандидатов, которые заучили 3 определения. Но это не точно, ведь может оказаться, что собеседующий тоже толком не понимает ООП. Но ООП вам точно пригодится, если захотите разобраться с той же Симфони.
>>1100305
Вообще, у меня в задаче была речь про обработку одной заявки. Если их несколько - обрабатываем в порядке поступления, кто первый подал заявку, тот и получает номер получше.
> Должен ли я проявлять человечность и в таком случае селить одиночку в номер за 300?
Это здравое рассуждение. Одиночка с меньшей вероятностью заплатит 500, чем трое человек - те же 500. Следовательно, замена номеров повышает вероятность, что Гость захочет воспользоваться услугами нашей, а не чужой Гостиницы. Гости ведь тоже не дураки, и про букинг и airbnb в курсе.
Раз ты так хочешь, давай сделаем дополнительно оптимизацию: добавим метод, который принимает N заявок, и пытается распределить их так, чтобы обеспечить максимальную вероятность заселения.
При этом перераспределение должно быть таким, чтобы гостиница не теряла прибыль. То есть после перераспределения общая оплата не должна уменьшиться.
Предлагать надо номер с минимальной ценой, нельзя предложить дорогой номер, если есть более дешевый.
Мы должны так же стараться оставить как можно больше свободных мест. Не предлагать 5-местный номер для 1 гостя, если есть номера меньше за ту же цену.
Это типичная задача на оптимизацию. Любую задачу на оптимизацию можно решить полным перебором. Нужно лишь определить функцию-критерий ( целевую функцию ) оптимизации (которую мы хотим максимизировать/минимизировать), посчитать ее значение для каждого варианта, и выбрать наилучший.
Иногда, конечно, перебор не реализуем, так как факторов очень много, и нужны специальные алгоритмы (гугли: задача коммивояжера), но у нас не тот случай и перебор допустим.
Сделать это можно попробовать так:
- берем K заявок
- для каждой заявки находим все варианты заселения. Ну то есть N номеров, куда можно поселить этих гостей.
- для каждой пары (1 заявка - 1 вариант заселения) вычисляем очки. Формула для вычисления очков подбирается так, чтобы можно было численно измерить, какой вариант "лучше", "выгоднее" для нас:
-- при прочих равных, чем меньше плата с группы за номер, тем больше очков (то есть лучше предложить номер за 300, чем за 500)
-- при прочих равных, чем меньше плата с 1 человека, тем лучше (лучше заселить одиночку в номер за 300, а группу в номер за 500, чем наоборот)
-- при прочих равных, чем меньше остается в номере свободных мест, тем лучше (одиночку лучше всего селить в одноместный номер)
Каждый критерий вносит вклад в общую оценку с определенным весом. Ну например, можно сделать так, что первый критерий всегда перевешивает остальные, и
они принимаются во внимание, только если первый критерий одинаков. А можно выбрать веса как-то еще.
Теперь, мы можем взять распределение (кто конкретно в какие номера заселяется), просуммировать оценки для каждой пары заявка-номер и мы получим численную оценку этого распределения. Вычислив оценку для всех возможных распределений, мы сможем найти оптимальное.
Казалось бы, задача решена.
Но тут, увы, грабли нам подсовывает комбинаторика. https://ru.wikipedia.org/wiki/Комбинаторика
Если у нас K заявок и N номеров, то число возможных распределений (вариантов заселения) - это размещение из N по K : https://ru.wikipedia.org/wiki/Размещение
И так как в формуле использован факториал, то при сотне номеров и десятке заявок числа получаются гигантские (100! / 90! = 100 x 99 x 98 x 97 ... 91 ~ 1 x 10^20).
Потому предлагаю придумать способ попроще. Например, такой:
- берем N заявок
- для каждой заявки находим K подходящих номеров, считаем очки для каждого варианта и получаем отсортированный список, от наилучшего к наихудшему варианту.
- теперь мы имеем N заявок и N отсортированных списков предложений номеров
- берем из каждого списка предложений первый вариант (лучший внутри списка) и ищем среди них лучший по очкам. Находим, заселяем. Убираем эту заявку и список предложений для нее. Удаляем занятый номер из остальных списков (или игнорируем его впредь).
- затем берем из оставшихся первых элементов списков следующий, чуть похуже. Заселяем, удаляем заявку и список.
- и так далее, пока списки не кончатся и все гости не будут заселены (либо пока не закончатся номера и списки предложений не станут пустыми)
Я этот алгоритм написал по интуиции, без доказательств, но думаю, что в твоем случае он бы сработал. Очевидно, что имея N отсортированных списков по K элементов, их обход, пусть даже неоднократный, займет не так много времени.
Что остается сделать тебе:
- понять идею
- выбрать критерии для вычисления очков. На вход функции подается заявка и номер, и она должна оценить эту пару численно.
- сделать тесты, проверяющие, что алгоритм оптимален. То есть сделать набор ситуаций, и проверить, что в каждой алгоритм дает оптимальное решение. Это могут быть тесты вида: проверяем, что при прочих равных выбирается номер подешевле, поменьше и тд. И твоя ситуация, где есть 2 варианта заселения.
Как, справишься? Заодно поучишься оптимизации.
Понятно, что задачи оптимизации очень даже жизненные и встречаются везде, и в науке, и в бизнесе. Потому они хорошо изучены.
Если тебя вдруг заинтересовала эта тема, и хочется знать еще больше - гугл в помощь: https://www.google.ru/search?q=методы+оптимизации&newwindow=1&dcr=0&gbv=1&sei=JjQfWqvDKoLE6QTwzq-ADw
>>1100309
Тем оптимизации пересекается с машинным обучением, так что ты недалек от истины.
>>1100286
Советую обязательно решить. Ваши мучения не пропадут даром. В большинстве учебников, а тем более в видеокурсах на ютубе, вам никто нормально ООП не объяснит. В лучшем случае вас заставят вызубрить дословно 3 определения принципов ООП (инкапсуляция/наследование/полиморфизм, и может быть, SOLID), которые вы не поймете, и расскажут как объявить класс. А на задачах про Гостиницу и про Продюсерское Агенство вы более-менее сможете увидеть реальное применение ООП, как оно облегчает написание кода за счет разбиения на отдельные классы (если думаете, что не облегчает, попробуйте без классов решить). Научитесь проектировать ООП-модель для задачи.
Надеюсь, что в итоге вы будете сильнее тех кандидатов, которые заучили 3 определения. Но это не точно, ведь может оказаться, что собеседующий тоже толком не понимает ООП. Но ООП вам точно пригодится, если захотите разобраться с той же Симфони.
>>1100305
Вообще, у меня в задаче была речь про обработку одной заявки. Если их несколько - обрабатываем в порядке поступления, кто первый подал заявку, тот и получает номер получше.
> Должен ли я проявлять человечность и в таком случае селить одиночку в номер за 300?
Это здравое рассуждение. Одиночка с меньшей вероятностью заплатит 500, чем трое человек - те же 500. Следовательно, замена номеров повышает вероятность, что Гость захочет воспользоваться услугами нашей, а не чужой Гостиницы. Гости ведь тоже не дураки, и про букинг и airbnb в курсе.
Раз ты так хочешь, давай сделаем дополнительно оптимизацию: добавим метод, который принимает N заявок, и пытается распределить их так, чтобы обеспечить максимальную вероятность заселения.
При этом перераспределение должно быть таким, чтобы гостиница не теряла прибыль. То есть после перераспределения общая оплата не должна уменьшиться.
Предлагать надо номер с минимальной ценой, нельзя предложить дорогой номер, если есть более дешевый.
Мы должны так же стараться оставить как можно больше свободных мест. Не предлагать 5-местный номер для 1 гостя, если есть номера меньше за ту же цену.
Это типичная задача на оптимизацию. Любую задачу на оптимизацию можно решить полным перебором. Нужно лишь определить функцию-критерий ( целевую функцию ) оптимизации (которую мы хотим максимизировать/минимизировать), посчитать ее значение для каждого варианта, и выбрать наилучший.
Иногда, конечно, перебор не реализуем, так как факторов очень много, и нужны специальные алгоритмы (гугли: задача коммивояжера), но у нас не тот случай и перебор допустим.
Сделать это можно попробовать так:
- берем K заявок
- для каждой заявки находим все варианты заселения. Ну то есть N номеров, куда можно поселить этих гостей.
- для каждой пары (1 заявка - 1 вариант заселения) вычисляем очки. Формула для вычисления очков подбирается так, чтобы можно было численно измерить, какой вариант "лучше", "выгоднее" для нас:
-- при прочих равных, чем меньше плата с группы за номер, тем больше очков (то есть лучше предложить номер за 300, чем за 500)
-- при прочих равных, чем меньше плата с 1 человека, тем лучше (лучше заселить одиночку в номер за 300, а группу в номер за 500, чем наоборот)
-- при прочих равных, чем меньше остается в номере свободных мест, тем лучше (одиночку лучше всего селить в одноместный номер)
Каждый критерий вносит вклад в общую оценку с определенным весом. Ну например, можно сделать так, что первый критерий всегда перевешивает остальные, и
они принимаются во внимание, только если первый критерий одинаков. А можно выбрать веса как-то еще.
Теперь, мы можем взять распределение (кто конкретно в какие номера заселяется), просуммировать оценки для каждой пары заявка-номер и мы получим численную оценку этого распределения. Вычислив оценку для всех возможных распределений, мы сможем найти оптимальное.
Казалось бы, задача решена.
Но тут, увы, грабли нам подсовывает комбинаторика. https://ru.wikipedia.org/wiki/Комбинаторика
Если у нас K заявок и N номеров, то число возможных распределений (вариантов заселения) - это размещение из N по K : https://ru.wikipedia.org/wiki/Размещение
И так как в формуле использован факториал, то при сотне номеров и десятке заявок числа получаются гигантские (100! / 90! = 100 x 99 x 98 x 97 ... 91 ~ 1 x 10^20).
Потому предлагаю придумать способ попроще. Например, такой:
- берем N заявок
- для каждой заявки находим K подходящих номеров, считаем очки для каждого варианта и получаем отсортированный список, от наилучшего к наихудшему варианту.
- теперь мы имеем N заявок и N отсортированных списков предложений номеров
- берем из каждого списка предложений первый вариант (лучший внутри списка) и ищем среди них лучший по очкам. Находим, заселяем. Убираем эту заявку и список предложений для нее. Удаляем занятый номер из остальных списков (или игнорируем его впредь).
- затем берем из оставшихся первых элементов списков следующий, чуть похуже. Заселяем, удаляем заявку и список.
- и так далее, пока списки не кончатся и все гости не будут заселены (либо пока не закончатся номера и списки предложений не станут пустыми)
Я этот алгоритм написал по интуиции, без доказательств, но думаю, что в твоем случае он бы сработал. Очевидно, что имея N отсортированных списков по K элементов, их обход, пусть даже неоднократный, займет не так много времени.
Что остается сделать тебе:
- понять идею
- выбрать критерии для вычисления очков. На вход функции подается заявка и номер, и она должна оценить эту пару численно.
- сделать тесты, проверяющие, что алгоритм оптимален. То есть сделать набор ситуаций, и проверить, что в каждой алгоритм дает оптимальное решение. Это могут быть тесты вида: проверяем, что при прочих равных выбирается номер подешевле, поменьше и тд. И твоя ситуация, где есть 2 варианта заселения.
Как, справишься? Заодно поучишься оптимизации.
Понятно, что задачи оптимизации очень даже жизненные и встречаются везде, и в науке, и в бизнесе. Потому они хорошо изучены.
Если тебя вдруг заинтересовала эта тема, и хочется знать еще больше - гугл в помощь: https://www.google.ru/search?q=методы+оптимизации&newwindow=1&dcr=0&gbv=1&sei=JjQfWqvDKoLE6QTwzq-ADw
>>1100309
Тем оптимизации пересекается с машинным обучением, так что ты недалек от истины.
Я написал урок специально по этой теме https://github.com/codedokode/pasta/blob/master/security/xss.md
Там и теория, и методы защиты.
Тебе наверно сложно сразу понять алгоритм, потому дам аналогию. представим себе таблицу, где по горизонтали идут свободные номера, а по вертикали - заявки на заселение. В каждую клеточку мы записываем оценку данного варианта заселения - чем оно лучше, тем выше оценка. Если заселить нельзя, пишем 0. Также, в уголке клеточки запишем Номер, к которому она относится (это пригодится позже).
Допустим, у нас 10 заявок и 100 номеров.
Наша цель - закрасить 10 клеточек в таблице так, чтобы они дали максимальную сумму.
Если функция оценки произвольная, то нам придется перебирать все возможные варианты заселения.
Но у нас функция не произвольная. Она растет довольно линейно: все хотят номер подешевле и поменьше. Единственное, что в разных заявках разное число человек, разная плата на человека и потому оценка одного номера для разных заявок различается.
За счет этого мы можем вместо полного перебора отсортировать каждую строку таблицы по убыванию (при этом Номер записан в углу ячейки и не теряется) - чтобы в каждой строке сначала шел номер с наибольшей оценкой. После чего мы берем первую колонку таблицы, и ищем в ней наибольшее число. Закрашиваем эту клеточку, удаляем клеточки с таким же номером (так как он уже заселен). Ищем среди оставшихся наибольшее число, закрашиваем. И так, пока не закрасим все 10 клеточек.
Так понятнее, надеюсь?
Ого, слишком сложно, я все-таки больше ООП хочу выучить.
На данный момент я реализовал:
1. Чтобы всегда заселять максимум народа не дробя группы (дробление еще не сделал).
2. Чтобы мелкие группы получали N-местные номера дешевле, чем N-местные номера для больших групп. То есть двое арендуют трехместный за 300, а трое за 500, и никогда наоборот.
Улучшить алгоритм не напрягаясь можно так: селим сначала каждую группу в самый дешевый вмещающий номер, при этом меньшая по размеру группа получит номер дешевле. Если всех заселили, мы молодцы. Если кто-то остался на улице, применяем старый алгоритм "заселять максимум народа не дробя группы" и заселяем всех заново.
Так и сделаю. На глаз тут будет работать принцип Парето - 20% усилий на разработку алгоритма (от системы с баллами) покроет 80% случаев несправедливости.
Заселить нужно всех. Но я думаю, ситуация малореалистична, скорее номер на 3-х будет стоить 1000. А то мой оптимизированный алгоритм может и не заработать на таких данных.
Алсо, если ты попробуешь нарисовать таблицу с очками, как я написал выше, то выбор будет очевиден.
Я прикинул сейчас с таблицей, все же мой алгоритм сработает верно тут. При условии, что заселение 3 человек в 3-местный номер даст больше очков, чем 2 человек в тот же номер.
Эх, математика бы сюда, разбирающегося в методах оптимизации. .. Эй, аноны-математики из /pr/, смотрите, какая у нас задача интересная получилась.
У тебя ведь и получается система с баллами, в неявном виде. Ты пишешь "сначала буду заселять туда" - а это эквивалентно присвоению баллов и выборе клеточки с наибольшим числом баллов.
Ты попробуй нарисовать таблицу, как я предложил, на ней твои ситуации очень наглядно выглядят.
Да, понятно. Я уже сейчас сортирую вместимости + оплате, то есть 1 - 100, 1 - 130, 2 - 90, 2 - 100 и так далее, а группы - по количеству. Но при этом вместимость играет ключевую роль. То есть я отправлю человека в одноместный номер, если он один, даже если он стоит 100500 денег.
Как оценивать в баллах вместимость? Я не представляю.
Тут игра на два фронта. Клиент хочет дешевле, а я хочу вселить больше. Разумеется, я и вселяю как можно больше. Но если я могу вселить всех по минимальному прайсу, не оставив никого на улице, я сделаю так в первую очередь. Вот.
Конечно, может случится ситуация, что я вселил одиночку в четырехместный номер за 100, а на улице осталась группа из четырех человек и одноместный номер за 1000. И в таком случае, хм, можно попробовать заселить того, кто на улице в минимально дешевый занятый номер на 4 персоны, жильцов того номера попробовать заселить в пустой номер, если не выходит, то заселить в минимально дешевый занятый номер, а других переселить в пустой номер, но если не выходит... И так далее, пока не заселю всех! Бинго! Спорю, это самый выгодный алгоритм!
Нет, так тоже не годится. Если у тебя есть свободный номер за 100, а ты предлагаешь номер за 200, то Гость может просто открыть букинг и пойти в другую Гостиницу. Нужно бы, если есть возможность, предлагать самый дешевый из имеющихся вариантов.
> Как оценивать в баллах вместимость? Я не представляю.
Если остается 0 пустых мест в номере = 1000 баллов
Если одно = 500 баллов
Если два = 250 баллов
...
Или использовать отрицательные баллы: -100 x (число незанятых мест в номере).
> если не выходит, то заселить в минимально дешевый занятый номер, а других переселить в пустой номер, но если не выходит... И так далее, пока не заселю всех!
Так (пробуя менять местами) ты в неудачном случае придешь к полному перебору. То есть будешь перебирать все способы закрасить 10 клеток в описанной выше таблице, а таких комбинаций там порядка 10 ^ 20 как я описал выше.
Так как в варианте "пробуем менять местами" я не вижу какой-то защиты от большого числа таких попыток.
>Здесь не очень понятно, зачем этот класс. Если он для того, чтобы хранить объект mysqli, то что мешает его хранить просто в переменной без всяких ConnectDb? Также, непонятно, зачем в нем поля вроде db_address? Где и как они будут использоваться?
Класс для соединения с бд. А где хранить хранить этот объект, как метод в Util? Или как? Как просто переменную, если да то где? Здесь не понятно. db_adress и подобные нужны были для того чтобы держать в них информацию о конфиге, понял, что можно сразу из массива pasre_ini_file пихать в mysqli
>Как ты выбираешь, что поставить, public или private?
Поставил private, паблик для вызова снаружи класса и наследников, приват только для опредленного класса
>Пропусти код класса через phpformatter.com
Сделал
>но нет проверки, что она содержит разрешенное значение, а значит тут может быть SQL инъекция.
Теперь есть
>Это можно сделать одной командой вместо цикла.
Как?
>Почему не foreach тут?
Пофиксил
> у тебя функции в TableDataGateway принимают и возвращают массивы
Теперь объекты по идее
> Не нужно писать 5 однотипных блоков кода, нужно использовать цикл.
Подскажи как тут использовать цикл, я не понял
>Методы findPage и getStudent не дублируют друг друга?
Теперь один метод getStudent
>Далее, я вижу в Authorisatin метод isEmailUsed. Какое отношение он имеет к авторизации? Никакого. Этот метод лучше сделать в классе TSG.
Сделал в TSG isEmailUsed
>- запрашиваем у TSG данные по студенту с логином login
>- если не нашлись, значит логи неправильный
>- если такие данные нашлись, сверяем хеш
Сделал это в TSG метод getLoginPass, как его разделить по частям чтобы вытягивание из БД было в TSG а проверка в Authoristaion ума не приложу, или так нормально?
>Здесь не очень понятно, зачем этот класс. Если он для того, чтобы хранить объект mysqli, то что мешает его хранить просто в переменной без всяких ConnectDb? Также, непонятно, зачем в нем поля вроде db_address? Где и как они будут использоваться?
Класс для соединения с бд. А где хранить хранить этот объект, как метод в Util? Или как? Как просто переменную, если да то где? Здесь не понятно. db_adress и подобные нужны были для того чтобы держать в них информацию о конфиге, понял, что можно сразу из массива pasre_ini_file пихать в mysqli
>Как ты выбираешь, что поставить, public или private?
Поставил private, паблик для вызова снаружи класса и наследников, приват только для опредленного класса
>Пропусти код класса через phpformatter.com
Сделал
>но нет проверки, что она содержит разрешенное значение, а значит тут может быть SQL инъекция.
Теперь есть
>Это можно сделать одной командой вместо цикла.
Как?
>Почему не foreach тут?
Пофиксил
> у тебя функции в TableDataGateway принимают и возвращают массивы
Теперь объекты по идее
> Не нужно писать 5 однотипных блоков кода, нужно использовать цикл.
Подскажи как тут использовать цикл, я не понял
>Методы findPage и getStudent не дублируют друг друга?
Теперь один метод getStudent
>Далее, я вижу в Authorisatin метод isEmailUsed. Какое отношение он имеет к авторизации? Никакого. Этот метод лучше сделать в классе TSG.
Сделал в TSG isEmailUsed
>- запрашиваем у TSG данные по студенту с логином login
>- если не нашлись, значит логи неправильный
>- если такие данные нашлись, сверяем хеш
Сделал это в TSG метод getLoginPass, как его разделить по частям чтобы вытягивание из БД было в TSG а проверка в Authoristaion ума не приложу, или так нормально?
>Если у тебя есть свободный номер за 100, а ты предлагаешь номер за 200, то Гость может просто открыть букинг и пойти в другую Гостиницу.
Какая разница, если у меня все равно кто-то на улице, а значит, я продам этот номер в любом случае? А так я могу заселить всех, и выгодно для абсолютного большинства. Мало того, у меня 4 довольных клиента вместо одного. Но в то же время, чем больше клиентов, тем больше толкучка у шведского стола.
Упрощаем: представь, что у меня только одноместные номера разной стоимости, в любом случае придется селить кого-то в самый дорогой.
>Если остается 0 пустых мест в номере = 1000 баллов
Хорошо, а деньги как оценивать в баллах? Раз меньше - это лучше?
Вычитать из стоимости самого дорогого номера? Давай предположим, что у нас есть президентский люкс на одного за 100к тугриков, а остальные номера стоят 1000-2000 тугриков. Все номера получают 98000 баллов. Плохо.
Значит, берем медиану, она будет около 1700, вычитаем баллы из нее. Да, будет логично.
Но пускай медиана 10к и разброс от 2000 до 20000. Что будем делать? Тогда 250 баллов будут погрешностью. Надо делать баллы от пустых мест зависимыми от баллов за деньги. А как?
>Так как в варианте "пробуем менять местами" я не вижу какой-то защиты от большого числа таких попыток.
Защита от бесконечного цикла точно есть. Если методом уплотниловки все влезают - задача имеет решение.
Интуитивно мне кажется, что цикл открутится за приемлемое время.
У меня текущая гостиница полностью строится за 2-4 секунды, учитывая, что шанс выбить последнюю комнату 1/640. Просто номер комнаты я даю рандомно, чтобы можно было построить 10 случайных комнат для теста, а не всю гостиницу. В итоге, когда 639 номеров из 640 разобраны, рандому должно хорошо посчастливиться.
> Какая разница, если у меня все равно кто-то на улице, а значит, я продам этот номер
Такого условия нет. Заявок может быть ограниченное количество за период времени. Гостиницы и другие предприятия сферы обслуживания вообще редко бывают заняты на 100% (если бы так было, они бы расширялись).
Оценивать по стоимости очень просто. Берем заведомо большое число и из него вычитаем по 1000 за каждый тугрик стоимости.
Ну или можно сделать баллы наоборот, чем больше баллов- тем хуже.
Можно разрешить отрицательные баллы, берем в начале 0 и вычитаем по 1000 за каждый тугрик стоимости.
> Все номера получают 98000 баллов. Плохо.
Не плохо. Железяке все равно, что цифры не красивые.
> Тогда 250 баллов будут погрешностью. Надо делать баллы от пустых мест зависимыми от баллов за деньги. А как?
Можно брать маленький вес. Например, за тугрик стоимости вычитаем 1000 баллов. А за незанятое место вычитаем всего 10 баллов. Незанятых мест в 1 номере всяко меньше 100, так что это будет влиять только если цена 2 вариантов одинаковая.
То есть вес стоимости в 1000 раз больше чем вес фактора незанятых мест.
> Интуитивно мне кажется, что цикл открутится за приемлемое время.
А ты посчитать попробуй. Используя комбинаторику. Там почти все формулы с факториалами.
>>1100357
Ой-ой, хочешь заставить ОПа решать учебные задачки для начинающих? Где такое видано? Если Оп пишет задачу, предполагается, что он ее решить может в уме (хотя бы примерно).
Я наконец-то понял твой принцип!
Можно обойтись без баллов. Сортируем комнаты по возрастанию цены. Сортируем заявки по уменьшению персон. Для каждой заявки пробуем комнаты, первую подходящую заселяем. Всё.
Затем вспоминаем, что у нас еще есть интервал бронирования, и надо бы в некомплектные номера селить тех, кто останавливается на короткий срок. И теряем сознание.
Алгоритм, не дающий захватить одному захватить номер для шести на длительный срок:
Сортируем комнаты по возрастанию цены. Сортируем заявки по уменьшению персон, внутри одинакового кол-ва персон по уменьшению срока брони. Для каждой заявки пробуем комнаты, первую подходящую заселяем, при этом подходящей считаем только ту, где вместимость = количество персон, а не >=. Заселенные заявки удаляем. Проходим цикл с оставшимися заявками, с условием вместимость = количество персон + 1. И так далее до исчезновения заявок, либо количество персон + N > вместимостьМаксимальногоНомера === true для каждой заявки, эти заявки заселить невозможно.
Таким образом, 4 человека, приехавшие на месяц, живут в 4-местном номере, а 4 человека, приехавшие на день, занимают, допустим, единственный 6-местный номер всего на день.
В предыдущей версии алгоритма 4 человека, приехавшие на месяц, могли заблокировать возможность принимать 6 человек на целый месяц, заняв 6-местный номер, при том, что 4-местный номер стоял бы пустым спустя день.
И еще один полезный бонус: не влезают в нашу гостиницу те, кто собрался вписаться на короткий срок, а долгим стабильно платящим клиентам местечко завсегда найдется.
У меня вообще появилась идея перешагнуть через регулярки и потом уже вернуться к этому делу.
Так стоит поступать?
Ты уже можешь решить задачу, удалив лишнее через strtr, как я показывал выше. И тогда регулярка будет выглядеть (+7|8)\d{10}. Самое забавное, в свое время я ее вроде так и решил.
Давай добьем загадочное зеленое пятно в скобках. Нам нужно 10 цифр железно, верно? Для начала напишем (\d){10} и вот мы уже матчим первые два примера.
Теперь нам нужно игнорировать пробелы, дефисы и скобки, то есть кушать их и не давиться. Для начала, придумай выражение в квадратных скобках, совпадающее с ними всеми. Затем помести его в скобки перед цифрой и после цифры. Затем поставь нужный квантификатор к квадратным скобкам.
Просто то, что ты мне описываешь, подразумевает наличие двух регулярных выражений, что, как мне кажется, нереализуемо в рамках сайта, если только нет "трубы" для перенаправления результата из одного регулярного выражения в другое.
И вот, что я выяснил за время своих рассуждений:
Я немножко долбаеб.
Я тупо брал и копировал на сайт массив
'84951234567', '+74951234567', '8-495-1-234-567',
' 8 (8122) 56-56-56', '8-911-1234567', '8 (911) 12 345 67',
'8-911 12 345 67', '8 (911) - 123 - 45 - 67', '+ 7 999 123 4567',
'8 ( 999 ) 1234567', '8 999 123 4567'
а потом удивлялся, с каких таких хуев у меня не все корректно работает И ТОЛЬКО СУКА СЕЙЧАС Я УВИДЕЛ КАК У ТЕБЯ СДЕЛАНО И КАК ДОЛЖЕН БЫЛ СДЕЛАТЬ Я!11
Именно из-за этого у меня не работала херня с ^
Регулярки можно комбинировать как угодно. В скобках как раз скрывается подвыражение, которое должно стрельнуть 10 раз подряд.
Да, еще выставь модификатор m, чтобы крышечка и доллар были началом и концом строки, а не всего текста.
Но тут случайно наткнулся на проект на JS, из gulp, который этим и занимается. Посмотрите, если еще интересно: https://github.com/gulpjs/vinyl
Ну и есть еще Symfony Filesystem, который абстрагирует файловую систему и который наверно тоже можно как-то тут использовать, наверняка что-то есть.
И есть еще Flysystem https://github.com/thephpleague/flysystem
-----------------
Также, напомню, что в прошлом треде были проверены:
https://github.com/Qevg/Student-list , вот тут >>1091604
Ну и все остальные задачи, что там были запощены, там же и проверены.
Спасибо ОПу и компании!
как '?foo=bar&biz=buz' ?
это значит, что в скрипт по адресу '/'
передаются get-параметры
их можно увидеть так:
<?php
echo '<pre>'.printf( $_GET, true ).'</pre>';
Но она же реально охуенная
или print_r
/test
?x
//test.example.com
#test
../1.txt
./1.txt
Ответы
http://example.com:81/some/test
http://example.com:81/some/page.html?x
http://test.example.com
http://example.com:81/some/page.html?a=1&b=2#test
http://example.com:81/1.txt
http://example.com:81/some/1.txt
Вижу уже, что где-то мимо, но не написав этого сюда бы не заметил, так что извините
//test.example.com
http://test.example.com
Так вернее?
А нет походу. Ведь написано что если с одного слэша, то порт берется.
1.http://example.com:81/1.txt
2.http://test.example.com/1.txt
3.http://example.com:81/some/page2.html#hash
4.http://example.com:81/some/page.html?x=1
1) /1.txt
2) //1.txt
3) /#hash
4) /?x=1
/test полностью замещает path (путь) и все, что дальше. И получается http://example.com:81/test
правило там примерно такое:
Если относительный URL начинается с ....
http://... - замещает все целиком
//... - замещает все, начиная с host и далее
/.. - замещает path и далее
?... - замещает query и далее
#... - замещает hash
xyzxyz... - замещает последний файл в path и далее (самое сложное место)
./xyzxyz.. - примерно то же самое
../xyzxyz - примерно то же самое, но .. значит подъем на 1 папку вверх
Ты в первом варианте ошибся.
Вариант 2) даст при разрещении http://1.txt что явно неправильно.
Вариант 3) даст http://example.com:81/#hash
Ну и с 4) та же проблема.
Смотри правила выше.
>/test полностью замещает path (путь) и все, что дальше. И получается...
Вроде теперь правильно понял.
>>1100804
>Вариант 2) даст при разрещении http://1.txt что явно неправильно.
/1.txt
>Вариант 3) даст http://example.com:81/#hash
#hash
?x1
Так верно? Спасибо большое за ответ.
>Время бы лучше указать как-то понятнее, вроде текущее + 10 лет, а то не очень понятно, почему именно 7ffff... и сколько это в привычных нам единицах измерения.
Пофиксил
>Для удаления кук надо указывать время в прошлом, посмотри мануал.
Пофиксил
>В валидаторе, при проверке поля score, надо проверять, что оно содержит цифры. А то можно ввести "30 cats". Для года надо проверять что там указан реалистичный год.
Пофиксил
>Также, нужно подумать, как избавиться от повторяющегося кода в методах validateStudent и validateProfile.
Сделал
>зачем ты конфиг с паролями положил в публично доступную папку? Хочешь со всеми поделиться своими секретами?
Перелолил в папку cfg
>У тебя нет проверки, что файл ../controller/'.$class.'.php'; существует
Теперь есть
>Не надо никогда редиректить на страницу ошибки, надо ее показывать.
Теперь я её просто подключаю, правильно?
>Но почему-то ты ловишь только исключения при создании нескольких объектов, а остальной код не проверяешь.
Там по всему коду try catch на методах где ловятся исключения, или я что то не понял?
> Лучше писать $e->__toString()
Сделано
>Их функции можно объединить в один контроллер, ведь поиск - это тоже просмотр списка студентов, только с фильтром по имени.
В процессе
>Зачем из контроллера вынсоить кусок в отдельный файл? Не лучше ли сюда этот код и вписать?
Сделал
>В view не должно быть работы с POST/GET. Оно просто отображает то, что дал контроллер.
Убарл по идее
>Лучше сделать функцию или метод где-нибудь в Util, который будет формировать URL из переданных ему параметров. И не забывай про htmlspecialchars.
В процессе
>Взять какой-нибудь аккаунт, например с id=1. Нужно, чтобы ты после захода на специальную страницу был залогинен под этим аккаунтом. То есть залогиниться под чьим-то аккаунтом не вводя логин или пароль (представь, что это нужно администратору например, или тестировщику).
Всё равно не понимаю
>Время бы лучше указать как-то понятнее, вроде текущее + 10 лет, а то не очень понятно, почему именно 7ffff... и сколько это в привычных нам единицах измерения.
Пофиксил
>Для удаления кук надо указывать время в прошлом, посмотри мануал.
Пофиксил
>В валидаторе, при проверке поля score, надо проверять, что оно содержит цифры. А то можно ввести "30 cats". Для года надо проверять что там указан реалистичный год.
Пофиксил
>Также, нужно подумать, как избавиться от повторяющегося кода в методах validateStudent и validateProfile.
Сделал
>зачем ты конфиг с паролями положил в публично доступную папку? Хочешь со всеми поделиться своими секретами?
Перелолил в папку cfg
>У тебя нет проверки, что файл ../controller/'.$class.'.php'; существует
Теперь есть
>Не надо никогда редиректить на страницу ошибки, надо ее показывать.
Теперь я её просто подключаю, правильно?
>Но почему-то ты ловишь только исключения при создании нескольких объектов, а остальной код не проверяешь.
Там по всему коду try catch на методах где ловятся исключения, или я что то не понял?
> Лучше писать $e->__toString()
Сделано
>Их функции можно объединить в один контроллер, ведь поиск - это тоже просмотр списка студентов, только с фильтром по имени.
В процессе
>Зачем из контроллера вынсоить кусок в отдельный файл? Не лучше ли сюда этот код и вписать?
Сделал
>В view не должно быть работы с POST/GET. Оно просто отображает то, что дал контроллер.
Убарл по идее
>Лучше сделать функцию или метод где-нибудь в Util, который будет формировать URL из переданных ему параметров. И не забывай про htmlspecialchars.
В процессе
>Взять какой-нибудь аккаунт, например с id=1. Нужно, чтобы ты после захода на специальную страницу был залогинен под этим аккаунтом. То есть залогиниться под чьим-то аккаунтом не вводя логин или пароль (представь, что это нужно администратору например, или тестировщику).
Всё равно не понимаю
Для поиска в одной колонке по части строки в SQL есть оператор LIKE: WHERE x LIKE '%hello%' (% здесь соответствует любым символам). Для поиска по всем колонкам можно применить оператор LIKE к соединенным через пробел значениям столбцов.
это я спрашивал. спасибо, посмотрю этот vinyl
ты тогда посоветовал мне задуматься о DI и создании объекта FileSystem. я объект делать не хотел, т.к. он требовал бы в коде библиотеки зависимости от библиотеки виртуальной файловой системы, которая по сути нужна только для тестов (т.е. идет в require-dev). В итоге я так сделал: в классе, который работает с файлами, есть путь по дефолту типа
CONST ROOT_DIR = __DIR__ . '/..';
private $someFilePath = SELF::ROOT_DIR . '/var/file.txt';
и сделал сеттер, который может менять путь для тестов. в тестах подменял ее на путь, который начинается с vfs:// (его генерирует сама либа файловой системы) и все работает ок
единственное, в чем я не разобрался - это как Flysystem работает в плане тестов. поэтому воспользовался вот этой https://github.com/mikey179/vfsStream
она у phpunit указана в документации в кач-ве примера.
http://exercism.io/ вот шикарный сайт с хорошими задачами и написанными тестами под них. можно смотреть код других участников
по поводу образования, тут дело не в рф конечно. сама идея "образования" - очень наивная вещь. типа я приду и меня научат. хуй там. в моей бывшей конторе брали студентов, выпускников и перекатившихся 30-летних. и вот студенты с выпускниками все как один с кодом общались как слепые котята. я почему-то наивно ожидал, что люди с профильным образованием смогут быстрее в реальном проекте что-то понять, но оказалось наоборот.
в то же время у меня есть очень прошаренные знакомые с большим опытом и ВО, но они в момент учебы постоянно что-то писали, где-то работали, что-то сами ковыряли и т.д.
Есть образовательные проекты, которые вузы проводят с крупными компаниями например:
https://sphere.mail.ru/pages/index/
https://track.mail.ru/pages/about/
https://park.mail.ru/pages/index/
https://academy.yandex.ru/ (там есть список вузов)
В ИТМО (Спб) вроде тоже как IT преподают.
Ну то есть надо хотя бы погуглить.
Если же ты не в одном из таких вузов, то конечно, учить тебя ничему не будут. Препод будет занудно рассказывать на лекциях про GUI на турбопаскале, реляционную алгебру и, если повезет, про PHP4. То есть не те знания, с которыми можно куда-то устроиться.
Учебников по какому предмету? По веб-разработке вообще?
Это малореально, как мне кажется, пока учебник напишут, пока одобрят, выйдет 1 новая версия PHP и 10 новых названий для ноды.
как в школе - это учебник по информатике разве что. то, что ты спрашиваешь - это как просить учебник "как чинить форд фокус".
if ($_POST) {
echo '<pre>';
echo htmlspecialchars(print_r($_POST, true));
echo '</pre>';
}
?>
<form action="" method="post">
Имя: <input type="text" name="personal[name]" /><br />
Email: <input type="text" name="personal[email]" /><br />
Пиво: <br />
<select multiple name="beer[]">
<option value="warthog">Warthog</option>
<option value="guinness">Guinness</option>
<option value="stuttgarter">Stuttgarter Schwabenbräu</option>
</select><br />
<input type="submit" value="Отправь меня!" />
</form>
Для чего тут нужен параметр true?
return
Если вы хотите перехватить вывод print_r(), используйте параметр return. Если его значение равно TRUE, то print_r() вернет результат вывода вместо вывода в браузер (который производится по умолчанию).
http://php.net/manual/ru/function.print-r.php
PHP Warning: Module 'sodium' already loaded in Unknown on line 0
пришлось закомментировать вызов модуля в /etc/php/7.2/mods-available/sodium.ini. warning пропал, а содиум работает ок, т.е. он подгружается еще в каком-то месте помимо конфига, что как-то странно само по себе. зачем тогда было запиливать кривой конфиг по умолчанию
Понятно. Спасибо.
Почитай список изменений для 7.2:
http://php.net/archive/2017.php#id2017-11-30-1
Конкретно про Sodium - теперь это входит в ядро:
https://wiki.php.net/rfc/libsodium
хех, на одном курсе повышения квалификации встретил препода какого-то "вузика",
который упрашивал меня спиратить мой учебный материал (мы разные курсы проходили), послал его с этой просьбой,
но с высоты своего огромного практического опыта ответил на вопросы и дал советов премудрых например, учить SQL хотя бы на Postgre
>>Их функции можно объединить в один контроллер, ведь поиск - это тоже просмотр списка студентов, только с фильтром по имени.
Сделал
>>Лучше сделать функцию или метод где-нибудь в Util, который будет формировать URL из переданных ему параметров. И не забывай про htmlspecialchars.
Сделал
для вкатывальщика-2018 имеет смысл только убить себя как можно быстрее, осознавая свою отсталость;
Тем не менее, mariadb -- это форк mysql, так что это, условно, одно и то же. Практический плюс мускуля в том, что он является самой распространённой СУБД на виртуальных хостингах, то есть, 99% малых и средних проектов. Самая крупная установка мускуля, вроде -- Booking.com
Postgresql круче (больше возможностей, больше объём БД) для больших систем и имеет хорошие перспективы в РФ в рамках импортозамещения как "бесплатный оракл"
>для вкатывальщика-2018 имеет смысл только убить себя как можно быстрее, осознавая свою отсталость;
Мне это не подходит.
Значит похуй че ставить?
Значит, осознание ещё не наступило.
Нет, не похуй, но из форков mysql можешь выбирать любой, в том числе mariadb.
у кого-нибудь есть хороший, годный (со всеми плюшками) bash-скрипт инсталяции php-fpm + nginx для CentOS?
а там прям скрипт нужен? на убунте все работает после apt install php7-fpm nginx
Ну как-то работает, да, это не проблема, я имел ввиду прям годную установку с настройкой безопасности, нормально работающих пакетов типа php-fpm-cli, etc.
Олсо, ИМХО бубунты на продакшне точно не должно быть, разве что у тотально выживших из ума хипсторов
ну если тебе нужно отвечать за безопасность, все надо делать самому. вот modsec поставить, например https://geekflare.com/install-modsecurity-on-nginx/
опять же на убунте все пакеты нормально работают из коробки после apt install php7.1*.
ну ок, в дебиане те же команды и тоже все работает из коробки (почти) но я впрочем не предлагаю тебе менять дистр на сервере, а просто выебываюсь
Да это понятно, у нас на текущих серверах всё очень в порядке, просто пытаюсь найти скрипт (не факт, что он есть), который делал бы на новых установках все кайфуши автоматом.
RHEL/CentOS, BSD для старообрядцев.
Но Debian, Slackware (раньше) тоже норм.
Олсо, в некоторых отраслях (банки, гос.конторы) в РФ важна сертификация дистрибутива в соответствующих органах.
>>1101394
в смысле, для просто-установки тебе не нужно ничего настраивать.
Это начинается уже на реальных проектах.
Развлекательное чтиво по теме: http://www.pvsm.ru/mysql/247358
Там написано: "указанные ниже продукты требуют установить такие-то библиотеки". Но очевидно, что если эти "продукты" ты не будешь ставить, то и библиотеки можно не ставить и не заморачиваться.
>>1101404
А ты английский понимаешь?
Во-первых, там стоит галочка "открыть порт 3306 на фаерволле". Если ты не собираешься подсоединяться к MySQL снаружи, с другого компьютера, то это делать незачем.
На второй картинке требуют придумать пароль администратора. Current root password - это я думаю, должна быть пустая строка.
Ну и ниже можно еще создать обычные аккаунты, хотя я бы советовал учиться их создавать командой CREATE USER в консоли.
Спасибо за ответ. У меня ошибка. Я пытался запустить консоль mysql unicode или как-то так она называлась, она крашилась сразу же.
Я все удалил попробую заново.
................................................
Так. Все установилось. Все открылось. Теперь я могу начать работать с mysql? Спасибо большое за ответ. Он мне очень помог.
Английский плохо знаю, маленький словарный запас.
бедняжечка :3
Человеку, который пока не разобрался с установкой mysql, рановато читать про архитектуру поиска.
Алсо по поводу букинга у меня конечно двоякие ощущения. С одной стороны вроде продвинутый сервис, но с другой стороны - там столько всего понавешано, постоянно всякие надписи выскакивают, они все анимированы, написаны красным цветом, и тд. А на мобильной версии отсутствуют некоторые опции (например: не показывать многоместные номера в хостелах).
Я помню, по моему на хабре читал эту статью и конечно у меня ощущение, что как-то у них все костыльно сделано. Если бы это делали вконтакте, они бы просто на Си написали поисковый демон с хранением данных в RAM и поиском того, что требуется (и это не так сложно, как кажется). Если бы это был я, я бы попробовал в порядке эксперимента сделать то же на Го - может чуть медленнее, но язык приятнее. Не очень понимаю, почему они городят что-то сложное на СУБД общего назначения. На Си пройтись в цикле по 1000 предложений займет меньше миллисекунды, я думаю.
(если кто-то из анонов не верит, давайте сформулируем задание, и вы напишете на Го и померяете).
Они там пишут миллион отелей, но ведь поиск идет в рамках одного города, и отелей там меньше. Там 30000 отелей - максимум был.
Может, конечно, я чего-то не знаю.
>>1101390
Вообще, MySQL настраивается с помощью редактирования файла конфигурации my.ini и перезапуска сервера. В файле конфигурации можно указать много разных опций, я могу дать только ссылку на англ. мануал, так как их очень много: https://dev.mysql.com/doc/refman/5.7/en/server-options.html
Но тебе скорее всего подойдут настройки по умолчанию.
Можно написать playbook для ansible. Ansible - это штука, которая умеет соединяться с сервером по ssh и настраивать его по описанным в конфиге правилам. Ну например, ты можешь сделать playbook, который устанавливает все нужное для веб-сервера или playbook, который добавляет новый virtual host в Апач. Если ты какую-то настройку делаешь больше 1 раза, ее надо автоматизировать.
Ну например, я хочу себе сделать playbook для быстрой установки openvpn на любой сервер.
Из недостатков ansible - он не поддерживает винду и его сложно ставить на cygwin (то каких-то заголовочных файлов не хватает, то openssl).
>>1101335
Часто еще надо модули ставить, настройки менять.
>>1101329
Не надо тут устраивать чат пожалуйста. Это тред про программирование.
>>1101326
На линуксе часто расширения идут как отдельные пакеты.
>>1101321
Не знаю, крупная или нет, но mysql еще использовался в фейсбуке, используется в википедии и в Uber недавно на него перешли.
>>1101317
Тебе надо учить стандартный SQL. Там есть отличия у разных БД, но на 80-90% они используют стандартный SQL и 10-20% дополнений к нему.
Можно написать playbook для ansible. Ansible - это штука, которая умеет соединяться с сервером по ssh и настраивать его по описанным в конфиге правилам. Ну например, ты можешь сделать playbook, который устанавливает все нужное для веб-сервера или playbook, который добавляет новый virtual host в Апач. Если ты какую-то настройку делаешь больше 1 раза, ее надо автоматизировать.
Ну например, я хочу себе сделать playbook для быстрой установки openvpn на любой сервер.
Из недостатков ansible - он не поддерживает винду и его сложно ставить на cygwin (то каких-то заголовочных файлов не хватает, то openssl).
>>1101335
Часто еще надо модули ставить, настройки менять.
>>1101329
Не надо тут устраивать чат пожалуйста. Это тред про программирование.
>>1101326
На линуксе часто расширения идут как отдельные пакеты.
>>1101321
Не знаю, крупная или нет, но mysql еще использовался в фейсбуке, используется в википедии и в Uber недавно на него перешли.
>>1101317
Тебе надо учить стандартный SQL. Там есть отличия у разных БД, но на 80-90% они используют стандартный SQL и 10-20% дополнений к нему.
Хеш и соль описаны в уроке про то, как правильно хранить пароли: https://github.com/codedokode/pasta/blob/master/security/password-hashing.md
Мы храним хеши вместо самих паролей, чтобы их было труднее украсть. Хеш позволяет проверить, правильно ли пользователь ввел свой пароль, но он не позволяет определить этот пароль.
>>1101261
Вообще, у нас тут есть анон, который "пилит" убийцу телеграм, может ему пригодится этот libsodium.
>>1101099
> но под него еще нет xdebug
Через pecl не поставить? Под линуксом вроде не проблема.
> зачем тогда было запиливать кривой конфиг по умолчанию
Скорее всего это твой старый конфиг. Обычно при обновлении пакета конфиги не заменяют, так как в них могут быть твои правки.
>>1100946
Я думаю, что для тестов там предназначен Memory Adapter: https://github.com/thephpleague/flysystem-memory
> ты тогда посоветовал мне задуматься о DI и создании объекта FileSystem. я объект делать не хотел, т.к. он требовал бы в коде библиотеки зависимости от библиотеки виртуальной файловой системы, которая по сути нужна только для тестов
Это да.
> поэтому воспользовался вот этой https://github.com/mikey179/vfsStream
Тоже вариант.
Хеш и соль описаны в уроке про то, как правильно хранить пароли: https://github.com/codedokode/pasta/blob/master/security/password-hashing.md
Мы храним хеши вместо самих паролей, чтобы их было труднее украсть. Хеш позволяет проверить, правильно ли пользователь ввел свой пароль, но он не позволяет определить этот пароль.
>>1101261
Вообще, у нас тут есть анон, который "пилит" убийцу телеграм, может ему пригодится этот libsodium.
>>1101099
> но под него еще нет xdebug
Через pecl не поставить? Под линуксом вроде не проблема.
> зачем тогда было запиливать кривой конфиг по умолчанию
Скорее всего это твой старый конфиг. Обычно при обновлении пакета конфиги не заменяют, так как в них могут быть твои правки.
>>1100946
Я думаю, что для тестов там предназначен Memory Adapter: https://github.com/thephpleague/flysystem-memory
> ты тогда посоветовал мне задуматься о DI и создании объекта FileSystem. я объект делать не хотел, т.к. он требовал бы в коде библиотеки зависимости от библиотеки виртуальной файловой системы, которая по сути нужна только для тестов
Это да.
> поэтому воспользовался вот этой https://github.com/mikey179/vfsStream
Тоже вариант.
На лекциях препод занудно рассказвыает про реляционную алгебру (сама по себе эта тема важная, но объясняют так, что ты все равно ничего не поймешь), потом немного рассказывает про SQL.
На практике наверно потребуют сделать какие-то SQL запросы.
Учебник по SQL будет прочитать куда как полезнее.
У нас в ОП посте кстати есть простые задачки по SQL.
Кстати, кто разбирается в стандартном SQL - они там LIMIT завезли уже?
>>1100849
Соединяем значения столбцов: CONCAT(name, ' ', surname, ' ', email,....)
Добавляем LIKE: WHERE CONCAT(...) LIKE '...'
Дописываем оставшуюся часть запроса (SELECT .. FROM ... ORDER ... LIMIT)
>>1100810
По прежнему неверно. Ссылка /1.txt разрешится в http://example.com:81/1.txt , а надо http://test.example.com/1.txt
> 3) #hash
Там должно быть page2.html, а у тебя будет page.html
> ?x1
Знак равно забыл.
>>1100790
Он замещает в базовом URL query и все, что дальше.
Базовый URL http://x.com/123?aaa
Относительный ?bbb
Результат http://x.com/123?bbb
На лекциях препод занудно рассказвыает про реляционную алгебру (сама по себе эта тема важная, но объясняют так, что ты все равно ничего не поймешь), потом немного рассказывает про SQL.
На практике наверно потребуют сделать какие-то SQL запросы.
Учебник по SQL будет прочитать куда как полезнее.
У нас в ОП посте кстати есть простые задачки по SQL.
Кстати, кто разбирается в стандартном SQL - они там LIMIT завезли уже?
>>1100849
Соединяем значения столбцов: CONCAT(name, ' ', surname, ' ', email,....)
Добавляем LIKE: WHERE CONCAT(...) LIKE '...'
Дописываем оставшуюся часть запроса (SELECT .. FROM ... ORDER ... LIMIT)
>>1100810
По прежнему неверно. Ссылка /1.txt разрешится в http://example.com:81/1.txt , а надо http://test.example.com/1.txt
> 3) #hash
Там должно быть page2.html, а у тебя будет page.html
> ?x1
Знак равно забыл.
>>1100790
Он замещает в базовом URL query и все, что дальше.
Базовый URL http://x.com/123?aaa
Относительный ?bbb
Результат http://x.com/123?bbb
Если я пропишу в composer.json "symfony/framework-bundle": "3.0" , то эта проблема уйдёт и появится подобная с другой библой уже. Что-то мне подсказывает, что заполнять это руками неразумно. Я вообще не могу понять (и нагуглить) сути проблемы. Вот содержимое composer.json https://pastebin.com/udYZyZim
Я не понял когда нужно трай/кетч сувать. На каждый чих что ли?
Еще пытался фронконтролер сделать и получилась какая та хуйня.
Так же не делал валидацию очень серьезную.
А еще все это без ксс. Деревянное все.
https://github.com/dsgaljkeguhodgiosetuhsegjposguh/studlist
>Через pecl не поставить? Под линуксом вроде не проблема.
пока проблема :(
checking Check for supported PHP versions... configure: error: not supported. Need a PHP version >= 5.5.0 and < 7.2.0 (found 7.2.0-1+ubuntu16.04.1+deb.sury.org+1)
но шторм понимает несколько интерпретаторов, поэтому пока пользуюсь 7.1 для хдебага
>Я думаю, что для тестов там предназначен Memory Adapter: https://github.com/thephpleague/flysystem-memory
о, спасибо
404
План:
1) простейшая реализация правил с выводом в консоль, играешь с рандомом.
2) простейшая графическая часть
3) искусственный интеллект (вот тут хотелось бы твоих советов, хочется сделать его обучающимся в процессе)
Основной смысл: хочу писать маленькие объекты, и сразу покрывать все тестами. Когда по тестам все будет работать как часы, пройдусь пару игр против генератора случайных чисел, если все работает, можно делать AI (самая интересная часть, так как вообще не представляю как тут что делается).
Вопросы:
1) js(знаю) или typescript(не пробовал) или фреймворки(работал с angular)?
2) хороший тестировщик для js(/typescript)?
Делал, ситуация такая же что и при composer update symfony/symfony --with-dependencies
и при composer update
В очень редких случая используется при работе с массивами использую его. Работает не со всеми типами, иногда PHP иногда PHP его игнорирует.
я не ОП и не знаю, надо ли оно, но часто вижу в коде что-то типа
foreach ($array as &$item) {
$item = ...
}
в том же симфони такого много:
foreach ($namespacedCommands as &$commandsSet) {
ksort($commandsSet);
}
foreach ($namespacedCommands as &$commandsSet) {
ksort($commandsSet);
}
$fileRecorder = function ($extension, $path) use (&$files) {
$files['yaml' === $extension ? 'yml' : $extension][] = $path;
};
и т.д.
$rnd = mt_rand(1, 6)
if ( $rnd == 1) {
echo "Значение1";
} elseif ( $rnd == 2 ) {
echo "Значение2";
} elseif ( $rnd == 3 ) {
echo "Значение3";
} elseif ( $rnd == 4 ) {
echo "Значение4";
} elseif ( $rnd == 5 ) {
echo "Значение5";
} elseif ( $rnd == 6 ) {
echo "Значение6";
}
?>
> Parse error: syntax error, unexpected 'if' (T_IF)
Я перед этим говнокодил на питоне и теперь не могу понять чего оно от меня хочет? Что с if не так?
Тогда VSCode или Atom, мне больше первый нравится.
>pycharm
А теперь подумай над своим вопросом и осознай насколько он тупой.
если у тебя что-то там лагает, то хоть в блокноте пиши. все, кто профессионально пишут код или стремятся к этому, пользуются штормом. это промышленный стандарт. ты придешь в контору работать и тебя там с твоим атомом, нетбинсом и прочим говном пошлют нахуй также, как анон выше.
а шторм достаточно долго осваивать со всеми его фишечками, поэтому лучше начинать уже сейчас
>а шторм достаточно долго осваивать со всеми его фишечками
Никогда не пользовался этими комбайнами, можно в двух словах о его преимуществах по сравнения с редакторами которые просто подсвечивают синтаксис?
я перечислю то, чем сам пользуюсь постоянно:
тесты - запуск и покрытие (смотреть, что не покрыто)
переход по методу или свойству класса
иерархия классов
контроль версий - порешать конфликты, сравнить файл с какой-то конкретной версией, посмотреть чьи правки
автозаполнение по аннотациям
инспекция кода
рест апи клиент для тестирования запросов
композер - автоапдейт, автоинсталл
консолью из шторма пользуюсь
автодеплой
ну просто запустить файл в кли из интерфейса шторма удобно
икс дебаг конечно же (который в 7.2 еще не завезли)
рефакторинг - это наверное самое ценное, что он умеет
плюс он умеет в автоформат по пср или по кодстайлу твоей конторы, авто неймспейсы по пср0 и 4, авто use, авто аннотации
сложно все вспомнить, может что-то забыл. еще он умеет работать с БД, но я пользуюсь воркбенчем, и всякие штуки с фронтом и версткой (в чем я не шарю).
Нихуйственно. Спасибо за инфу.
почти так. допустим, поменять название метода, чтобы он поменялся во всем проекте, вынести код в другой класс и т.д., захуярить автоматически интрерфейс на основе класса - это все рефакторинг.
>>1101737
можно. по поводу скобок, они там есть, но только в одном месте. лучше посмотри пример http://php.net/manual/ru/control-structures.switch.php
не знаю, кстати, как в 7 (кто-нибудт знает?), а раньше это экономило память (при передачи по ссылке значение переменной не копируется)
Да.
как я понимаю, мы тестируем не весь код втупую, а логику работы приложения, т.е. не тестируем непубличные методы, а тестируем публичные, которые их используют. это вроде логично.
а вот если у нас есть композиция классов (или как тут верно сказать), т.е. допустим есть класс FormHandler и у него в конструкторе создается объект класса FormValidator, который вне этого хендлера больше нигде не будет использоваться, нам его как тестировать? через FormHandlerTest или напрямую через FormValidatorTest? Я сам склоняюсь к первому варианту, но смущает то, что в валидаторе может быть какая-то хитрая логика, которую в таком случае лучше тестить напрямую.
>у него в конструкторе создается объект класса FormValidator
Нет же.
Ему в конструктор передаётся, а тестировать их — отдельно.
если бы передавался, то понятно, но не передается, а именно создается:
class FormHandler
{
private $formValidator;
public function __construct()
{
$this->formValidator = new FormValidator();
}
}
Есть задача: написать интернет магазин (фейковый).
Что там должно быть?
Админпанель (разные варианты для админа, продавца, покупателя?).
Корзина (ХЗ как её реализовать).
Главная страница.
Меню с видами продуктов.
Меню с опциями для сортировки продуктов внутри вида (по производителю, цене, ?,?,?).
Страница продукта.
Пагинация страниц результатов (или этот модный скроллинг, но я ХЗ как его реализовать).
?.
?.
?.
Знаю, что надо использовать MVC, но на деле с ним знаком плохо. Почитать бы чего, или посмотреть как сделано.
Еще знаю, что надо использовать подготовленные запросы при обращениях к БД, чтоб избежать иньекции.
Еще подводные?
>объект API содержит в себе под-объекты, которые независимо от него не используются. Логично потому их создавать в конструкторе.
А пол-года спустя уже используются. Логично потому их не создавать в конструкторе. Ибо нехер плодить зависимости на пустом месте.
>>1102021
>>1102057
>>1102132
Если что-то можно создать в конструкторе, значит можно это безболезненно поместить в текущий класс. Или боишься файла на 600 строк вместо 300? Так и думать про
>через FormHandlerTest или напрямую через FormValidatorTest?
не придется.
Если хоть мысль пролетит
>А пол-года спустя уже используются.
делай DI.
>А пол-года спустя уже используются.
это надо в каждом конкретном случае смотреть. в общем случае это получается беспредметный спор. я могу возразить, что попытка загадать, что там будет через полгода, может привести к написанию лишнего на данный момент кода, а это вредно, т.к. через полгода понадобится не та реализация, которую ты представляешь сейчас. это помимо траты времени на ненужный код.
плюс, предполагаю, что ты говоришь про mvc, где можно 20 зависимостей передать через контейнер.
>Или боишься файла на 600 строк вместо 300?
честно говоря, да. немного побаиваюсь god object
>Если хоть мысль пролетит
>>А пол-года спустя уже используются.
>делай DI.
тут соглашусь
https://www.youtube.com/watch?v=w4_1SagLY94
Как сделать эту задачу?
Просто жопой чую, что можно пройти через дверь, а не лезть через забор
https://ideone.com/dEcffB
Доделай шифрование до нормального уровня
Доделай расшифровку зашифрованного текста. Посказка для глупеньких: тебе поможет array_flip()
я не ОП и хочется услышать его мнение. мое мнение: чтобы не нарушать принцип единой ответственности и чтобы не было классов по 1000 строк.
mysql - это устаревшая библиотека, ее нельзя использовать. mysqli можно, но нормальные люди пользуются pdo. осваивать одинаково, если ты хоть как-то знаешь ооп, если не знаешь - mysqli будет попроще. но пользоваться им нельзя, также как сейчас нельзя писать процедурный код, поэтому лучше сразу учи pdo.
Поцце-дурный код как раз можно. Эх как создам, бывало, просранства имён и в них функций каак насру...
В задаче про массивы и генерацию имени для питомца
С задачей я справился так:
https://ideone.com/BKUeFG
и вот так:
https://ideone.com/Jt8nm5
Так вот у меня такой вопрос:
$petName = implode(array_rand($letters,4));
echo $petName;
Печатаются ключи ,которые получились при рандоме,а как получить доступ к значениям?
На сервак поступает запрос с требованием создать HTML элемент в корзине с данными, формами и т.д в свою очередь в хранилище есть готовый CSS файл со стилем для этих элементов, так?
Т.е запрос создать в HTML доп. элементы с уже готовым стилем в CSS файле который содержит инфу об отступах от первого элемента в корзине, от второго и до бесконечности > выноска с HTML кодом добавляется в пользовательский HTML файл и инфа со стилем не меняется, а остается нетронутой. Правильно?
Да, всё правильно. Впрочем при необходимости на php можно генерировать даже CSS файлы.
Спасибо.
https://ideone.com/cPiQC3
Делаю задачу с опечатками.
Не могу понять в чём проблема. Почему у меня выдаёт только часть слова с ошибкой? Когда я прописываю просто одно слово с ошибкой в виде переменной ($text = "Постaвка";), то всё определяется нормально и выводится как и должно, а после разбивки строки на массив и прохождения по нему циклом выдаёт только кусок слова. Хелп ми.
$this::staticMethod() и
self::staticMethod()
В первом обращение к статичному методу объекта, во втором обращение к классу объекта.
в первом обращение к объекту, а во втором к классу, да. но в случае со статическим методом там не может быть состояния, которое привносит созданный объект. то есть, по сути это всегда обращение к классу. так получается, что разницы нет?
вакансия стажера-верстальщика?
не парься, первое время все тупые. через полгода будет лучше.
Так ты бы поигрался с ними. Например:
https://ideone.com/3c2QaY
Попробуй объяснить, что не так?
в случае с
public static function durr() {
$this::staticMethod();
}
идет обращение к $this в контексте статического метода, что нельзя делать, поэтому фатал. это понятно
я спрашивал про
public function yarr() {
$this::staticMethod();
}
и
public function hurr() {
self::staticMethod();
}
которые выводят одинаковый результат. то есть в данном случае разницы нет. так?
я понимаю, что так $this::staticMethod() делать не надо, т.к. это идиотская конструкция. но мне непонятно, зачем в языке до сих пор присутствует эта возможность. насколько я понимаю, она там с 5.3. просто руки не дошли выпилить?
Порой такая штука удобна, например когда надо вызвать динамичный метод, причем не важно статик он или нет
$this->{$methodName}($arg)
Кстати $this::method() алиас static::method(), а не self::method()
>>1102795
Хех... Сложно... Ну смотри тогда такой пример:
https://ideone.com/4FhUeP
И статью:
http://php.net/manual/ru/language.oop5.late-static-bindings.php
Разница есть, и выпиливать нечего.
благодарю. про отличие static от self знаю, а про то, что с помощью $this->{$methodName}($arg) можно вызывать в т.ч. статический метод, не знал.
self::staticMethod() так правильно,
$this::staticMethod() так не правильно, но все равно работает.
abstract class cA
{
static function A()
{
static::B();
}
abstract static function B();
}
class cB extends cA
{
static function B()
{
echo "ok\n";
}
}
cB::A();
cB::B();
этот код у меня выполняется на 7.1 с error_reporting e_all без ошибок, то есть бывают. но история темная, тут она описана https://stackoverflow.com/questions/999066/why-does-php-5-2-disallow-abstract-static-class-methods/31235907#31235907
получается, что в версии <7 такой код вызывал бы нотис уровня strict, а в 7 все ок.
у нас есть абстрактный класс, как его тестировать?
вижу такие варианты:
1. через существующих наследников
2. через анонимный класс-потомок (начиная с 7)
3. через getMockBuilder в PHPUnit
4. через getMockForAbstractClass в юните же
притом вариантов 1 и 4 сам нигде не нашел (кроме как 4 в мануале). также сам не смог протестировать через getMockForAbstractClass - код в шторме не покрывается. а через getMockBuilder тоже нихуя непонятно - он же подменяет методы класса, почему они тогда отрабатываются.
интересно кто что думает.
А где это может понадобиться? По идее, абстрактные нестатические методы используются в ситуации с наследованием: есть базовый класс Base с абстр. методом doSmth() и его наследники X, Y, Z. В коде ниже мы не знаем, объект какого именно класса перед нами, но знаем, что в нем есть метод doSmth (для таких ситуаций и придуманы абстрактные методы):
function test(Base $b)
{
$b->doSmth();
}
Но статические методы вызываются, как правило, с указанием имени класса:
X::doSmth();
Так как мы знаем имя класса, мы можем проверить, какие в нем методы есть, и задавать абстрактный метод в предке (Base) не обязательно. Потому в той же Яве абстрактных статических методов нет.
Тут я нашел такое объяснение: https://stackoverflow.com/questions/370962/why-cant-static-methods-be-abstract-in-java
> Because "abstract" means: "Implements no functionality", and "static" means: "There is functionality even if you don't have an object instance". And that's a logical contradiction.
Но в PHP все "не так однозначно". Там можно вызывать статические методы через self:: и static::, и в случае со static, вызывается метод, который объявлен в наследнике. То есть при использовании static:: получается что-то похожее на обычные методы ("позднее связывание", "позднее" тут значит, что определение, какой именно метод будет вызван ("связывание"), делается во время выполнения кода, а не во время его компиляции. В случае с self получается "раннее связывание"). Вообще, мне эта фича не нравится: для этого были придуманы обычные методы. Но раз уж такая фича есть, то получается, что логично добавить абстрактные статические методы, чтобы мы могли писать
static::doSmth()
в классе Base, когда метод doSmth абстрактный.
https://stackoverflow.com/questions/999066/why-does-php-5-2-disallow-abstract-static-class-methods
Тут пишут, что абстрактных статических методов в PHP нет (выше анон опровергает, эти разработчики там совсем двинулись уже). Напомню еще раз, что мне сама идея с переопределением статических методов и использованием static не очень нравится.
А в какой ситуации они тебе нужны?
А где это может понадобиться? По идее, абстрактные нестатические методы используются в ситуации с наследованием: есть базовый класс Base с абстр. методом doSmth() и его наследники X, Y, Z. В коде ниже мы не знаем, объект какого именно класса перед нами, но знаем, что в нем есть метод doSmth (для таких ситуаций и придуманы абстрактные методы):
function test(Base $b)
{
$b->doSmth();
}
Но статические методы вызываются, как правило, с указанием имени класса:
X::doSmth();
Так как мы знаем имя класса, мы можем проверить, какие в нем методы есть, и задавать абстрактный метод в предке (Base) не обязательно. Потому в той же Яве абстрактных статических методов нет.
Тут я нашел такое объяснение: https://stackoverflow.com/questions/370962/why-cant-static-methods-be-abstract-in-java
> Because "abstract" means: "Implements no functionality", and "static" means: "There is functionality even if you don't have an object instance". And that's a logical contradiction.
Но в PHP все "не так однозначно". Там можно вызывать статические методы через self:: и static::, и в случае со static, вызывается метод, который объявлен в наследнике. То есть при использовании static:: получается что-то похожее на обычные методы ("позднее связывание", "позднее" тут значит, что определение, какой именно метод будет вызван ("связывание"), делается во время выполнения кода, а не во время его компиляции. В случае с self получается "раннее связывание"). Вообще, мне эта фича не нравится: для этого были придуманы обычные методы. Но раз уж такая фича есть, то получается, что логично добавить абстрактные статические методы, чтобы мы могли писать
static::doSmth()
в классе Base, когда метод doSmth абстрактный.
https://stackoverflow.com/questions/999066/why-does-php-5-2-disallow-abstract-static-class-methods
Тут пишут, что абстрактных статических методов в PHP нет (выше анон опровергает, эти разработчики там совсем двинулись уже). Напомню еще раз, что мне сама идея с переопределением статических методов и использованием static не очень нравится.
А в какой ситуации они тебе нужны?
Для чего нужен абстрактный класс? Как заготовка для создания наследников.
Можно создать тестового наследника и тестировать его. То есть пишешь class TestChild extends Parent { ... }.
Либо можно тестировать только наследников этого класса, если создание дополнительных наследников не планируется.
> через анонимный класс-потомок (начиная с 7)
Можно и так.
Моки, мне кажется, не для этого. Они для подмены существующий конкретных классов.
Вообще, это неправильно, вызывать статические методы через $this, на мой взгляд. Статические методы вызваются на классе (у класса), а не на объекте (не у объекта).
Если нужен динамический вызов, имхо, лучше будет написать self::$method(), call_user_func("self::$method") или call_user_func(['self', $method]).
>>1102805
В PHP вообще с ООП много проблем, так как часть разработчиков (по моим ощущениям) сишники и ООП вообще толком не понимают. Ну например, раньше там была такая "фича", что при вызыве из одного класса статического метода другого класса передавалось значение $this:
class A
{
public function a()
{
B::b();
}
}
class B
{
public static function b()
{
// $this указывает на объект класса $a
}
}
$a = new A;
$a->a();
Так что да, делать так ни в коем случае не надо.
>>1102730
Первый вариант мне не нравится. Статические методы вызывают на классе, а не на объекте.
>>1102727
Скорее всего, в слове больше одной латинской буквы. И твое выражение не захватывает все слово из-за этого. Например: П(о)(с)т(а)вка. Видишь, как хорошо зашифровано, даже твоя программа его не может справиться.
> foreach($piece as $error) {
лучше foreach ($words as $word)
Вообще, это неправильно, вызывать статические методы через $this, на мой взгляд. Статические методы вызваются на классе (у класса), а не на объекте (не у объекта).
Если нужен динамический вызов, имхо, лучше будет написать self::$method(), call_user_func("self::$method") или call_user_func(['self', $method]).
>>1102805
В PHP вообще с ООП много проблем, так как часть разработчиков (по моим ощущениям) сишники и ООП вообще толком не понимают. Ну например, раньше там была такая "фича", что при вызыве из одного класса статического метода другого класса передавалось значение $this:
class A
{
public function a()
{
B::b();
}
}
class B
{
public static function b()
{
// $this указывает на объект класса $a
}
}
$a = new A;
$a->a();
Так что да, делать так ни в коем случае не надо.
>>1102730
Первый вариант мне не нравится. Статические методы вызывают на классе, а не на объекте.
>>1102727
Скорее всего, в слове больше одной латинской буквы. И твое выражение не захватывает все слово из-за этого. Например: П(о)(с)т(а)вка. Видишь, как хорошо зашифровано, даже твоя программа его не может справиться.
> foreach($piece as $error) {
лучше foreach ($words as $word)
Я не очень понимаю суть вопроса, но постараюсь прокомментировать.
> Т.е запрос создать в HTML доп. элементы с уже готовым стилем в CSS файле который содержит инфу об отступах от первого элемента в корзине, от второго и до бесконечности
Зачем эта "инфа" об отступах? В HTML/CSS тебе не надо указывать расположение каждого элемента на экране. Ты просто указываешь, что они должны идти, например, вертикально, и задаешь расстояние между ними. Или я тебя не понял, или тебе стоит подучить CSS. То есть ты пишешь что-то вроде "все товары в корзине расположены вертикально c отступом в 10px, текст в них написан черным цветом на белом фоне".
CSS файлы пишет разработчик и в них ничего программно обычно не добавляется.
Ну и не понял, при чем тут HTML файлы. В динамических сайтах HTML файлы не генерируются. Почитай-ка мой урок https://github.com/codedokode/pasta/blob/master/soft/web-server.md#Статические-и-динамические-страницы
>>1102565
Оба варианта правильные. Только переменная названа не очень удачно, не $index, а например $syllable (слог) лучше было назвать.
>>1102585
Неудобно же, исключения не поддерживает, надо вручную результат вызова проверять.
>>1102354
Библиотека mysql удалена в PHP7. Объяснение, почему, на английском https://wiki.php.net/rfc/mysql_deprecation#why
Вроде у тебя все правильно сделано. Но, конечно, помни, что это лишь задача и метод шифрования тут вскрывается элементарно, полным перебором либо статическим анализом.
>>1102107
Может, надо писать не с нуля, а взять готовую CMS? Много работы же получается.
>>1101890
> как я понимаю, мы тестируем не весь код втупую, а логику работы приложения, т.е. не тестируем непубличные методы, а тестируем публичные,
Да. Тогда тесты не будут ломаться при внутренних изменениях в классе.
> т.е. допустим есть класс FormHandler и у него в конструкторе создается объект класса FormValidator, который вне этого хендлера больше нигде не будет использоваться, нам его как тестировать?
> через FormHandlerTest или напрямую через FormValidatorTest? Я сам склоняюсь к первому варианту, но смущает то, что в валидаторе может быть какая-то хитрая логика, которую в таком случае лучше тестить напрямую.
В Яве есть такая штука, как "приватные" классы, то есть вспомогательные классы, объявленные внутри другого класса и недоступные/невидимые снаружи этого класса. Их, конечно, можно не тестировать.
Если твой класс FormValidator по смыслу такой же "вспомогательный", то ты можешь тестирвать только FormHandler. Но на практике, скорее всего, у тебя как-то распределены обязанности между этими 2 классами. И удобнее тестировать их по отдельности.
То есть FormValidator тестирвоать на то, что он обнаруживает все виды ошибок. А FormHandler тогда можно уже не тестировать на все виды ошибок, а только на одну, что он правильно обрабатывает такую ситуацию.
>>1101449
Про исключения почитай урок https://github.com/codedokode/pasta/blob/master/php/exceptions.md
Если ты хочешь как-то специально обработать конкретное исключение, ты пишешь try/catch. Ну например, ты скачиваешь файл, а при ошибке - берешь его с диска:
try {
$file = downloadFile();
} catch (DownloadException $e) {
log("Error downloading file: $e->getMessage()");
$file = loadFromDisk();
}
Если же ты не хочешь как-то специально обрабатывать исключение, а просто показать страницу ошибки, то нужно использовать обработчик исключений по умолчанию либо один большой try/catch на самом верхнем уровне программы.
Код на гитхабе недоступен.
Вроде у тебя все правильно сделано. Но, конечно, помни, что это лишь задача и метод шифрования тут вскрывается элементарно, полным перебором либо статическим анализом.
>>1102107
Может, надо писать не с нуля, а взять готовую CMS? Много работы же получается.
>>1101890
> как я понимаю, мы тестируем не весь код втупую, а логику работы приложения, т.е. не тестируем непубличные методы, а тестируем публичные,
Да. Тогда тесты не будут ломаться при внутренних изменениях в классе.
> т.е. допустим есть класс FormHandler и у него в конструкторе создается объект класса FormValidator, который вне этого хендлера больше нигде не будет использоваться, нам его как тестировать?
> через FormHandlerTest или напрямую через FormValidatorTest? Я сам склоняюсь к первому варианту, но смущает то, что в валидаторе может быть какая-то хитрая логика, которую в таком случае лучше тестить напрямую.
В Яве есть такая штука, как "приватные" классы, то есть вспомогательные классы, объявленные внутри другого класса и недоступные/невидимые снаружи этого класса. Их, конечно, можно не тестировать.
Если твой класс FormValidator по смыслу такой же "вспомогательный", то ты можешь тестирвать только FormHandler. Но на практике, скорее всего, у тебя как-то распределены обязанности между этими 2 классами. И удобнее тестировать их по отдельности.
То есть FormValidator тестирвоать на то, что он обнаруживает все виды ошибок. А FormHandler тогда можно уже не тестировать на все виды ошибок, а только на одну, что он правильно обрабатывает такую ситуацию.
>>1101449
Про исключения почитай урок https://github.com/codedokode/pasta/blob/master/php/exceptions.md
Если ты хочешь как-то специально обработать конкретное исключение, ты пишешь try/catch. Ну например, ты скачиваешь файл, а при ошибке - берешь его с диска:
try {
$file = downloadFile();
} catch (DownloadException $e) {
log("Error downloading file: $e->getMessage()");
$file = loadFromDisk();
}
Если же ты не хочешь как-то специально обрабатывать исключение, а просто показать страницу ошибки, то нужно использовать обработчик исключений по умолчанию либо один большой try/catch на самом верхнем уровне программы.
Код на гитхабе недоступен.
Насчет симфони. Мне кажется, проблема в том, что ты используешь несовместимые с симфони 4 пакеты.
Вот смотри, что пишет композер:
> Problem 1
> - stof/doctrine-extensions-bundle v1.2.2 requires symfony/framework-bundle ~2.1|~3.0
Это сторонняя библиотека, не часть Симфони. Открываем эту библиотеку на гитхабе: https://github.com/stof/StofDoctrineExtensionsBundle/blob/master/composer.json
> "require": {
> "symfony/framework-bundle": "~2.1|~3.0",
То есть она не совместима с Symfony 4. Что можно сделать:
- отказаться от нее
- попросить авторов сделать поддержку Symfony 4 (уже: https://github.com/stof/StofDoctrineExtensionsBundle/issues/354 )
- сделать поддержку самому и запушить пулл реквест, а пока он не принят, использовать версию из своего гитхаба (уже сделали: https://github.com/stof/StofDoctrineExtensionsBundle/pull/358 и ты можешь подключить версию из того гитхаба)
То есть композер тебе все правильно написал, он перебрал все версии библиотек и не нашел совместимых. Как удобно. А представь, без композера, руками обновлять такую кучу библиотек и только потом обнаружить, что они не совместимы?
> Что-то мне подсказывает, что заполнять это руками неразумно. Я вообще не могу понять (и нагуглить) сути проблемы.
Тут сложность в том, что Симфони состоит не из одного, а из множества пакетов. И обновлять их надо синхронно. Проще всего взять стандартное приложение на Симфони и список версий оттуда https://github.com/symfony/symfony-standard
Затем ты пробуешь обновиться и смотришь, что напишет композер. И разбираешься с проблемными библиотеками.
> , то эта проблема уйдёт и появится подобная с другой библой уже.
Без подробностей помочь не могу.
Насчет симфони. Мне кажется, проблема в том, что ты используешь несовместимые с симфони 4 пакеты.
Вот смотри, что пишет композер:
> Problem 1
> - stof/doctrine-extensions-bundle v1.2.2 requires symfony/framework-bundle ~2.1|~3.0
Это сторонняя библиотека, не часть Симфони. Открываем эту библиотеку на гитхабе: https://github.com/stof/StofDoctrineExtensionsBundle/blob/master/composer.json
> "require": {
> "symfony/framework-bundle": "~2.1|~3.0",
То есть она не совместима с Symfony 4. Что можно сделать:
- отказаться от нее
- попросить авторов сделать поддержку Symfony 4 (уже: https://github.com/stof/StofDoctrineExtensionsBundle/issues/354 )
- сделать поддержку самому и запушить пулл реквест, а пока он не принят, использовать версию из своего гитхаба (уже сделали: https://github.com/stof/StofDoctrineExtensionsBundle/pull/358 и ты можешь подключить версию из того гитхаба)
То есть композер тебе все правильно написал, он перебрал все версии библиотек и не нашел совместимых. Как удобно. А представь, без композера, руками обновлять такую кучу библиотек и только потом обнаружить, что они не совместимы?
> Что-то мне подсказывает, что заполнять это руками неразумно. Я вообще не могу понять (и нагуглить) сути проблемы.
Тут сложность в том, что Симфони состоит не из одного, а из множества пакетов. И обновлять их надо синхронно. Проще всего взять стандартное приложение на Симфони и список версий оттуда https://github.com/symfony/symfony-standard
Затем ты пробуешь обновиться и смотришь, что напишет композер. И разбираешься с проблемными библиотеками.
> , то эта проблема уйдёт и появится подобная с другой библой уже.
Без подробностей помочь не могу.
Ubuntu server (не desktop) вполне адекватная вроде. Разве что у меня в виртуалке логин притормаживает в сравнении с дебианом. А что тебе-то не нравится?
>>1101898
Можно и создавать. Зависит от ситуации. Ну например, если не может быть причин заменять класс на что-то другое, то можно его там же и создать. Ну например, если у нас форма редактирования студента, то валидатор для этой формы вряд ли понадобится менять на другой и можно его там и создать.
Также, если внутренний класс представляет собой не сервис, а сущность, и они иногда должны создаваться, тоже проще обойтись без DI.
DI должен использоваться там, где это уместно, где это решает какую-то проблему, а не вообще для любых классов. Использование DI подразумевает, что мы можем передать другую реализацию зависимости. Но тут ведь это явно не так. Нам нужен один конкретный валидатор и нельзя сюда передать какой-то модифицированный валидатор.
На практике, может показаться, что DI тут использовать удобнее. Ведь скорее всего, у FormValidator есть тоже какие-то зависимости, например, доступ к БД. Его надо как-то передать туда, и получается, что удобнее тут использовать DI и передать ответственность за получение зависимостей DI контейнеру.
Если зависимостей у FormValidator нет, можно не использовать DI.
Есть еще вариант передавать зависимости в FormHandler:
class FormHandler
{
public function __construct($dep1, $dep2, $dep3)
{
$validator = new FormValidator($dep1, $dep2, $dep3);
}
Но тут видна нелогичность: не проще ли передавать сразу $validator вместо 3 зависимостей? Но если мы сделаем DI (будет принимать $validator снаружи), то получается, что мы готовы работать с несколькими вариантами валидатора. Что тоже нелогично. Это говорит о том, что мы не очень удачно сделали разделение ответственности между классами.
Потому что у нас и FormHandler заточен на работу только с одной конкретной формой, и FormValidator - тоже. Может есть смысл как-то перераспределить код так, чтобы был отдельно универсальный валидатор или класс для работы с любыми формами, а отдельно - класс, хранящий информацию (правила валидации) для какой-то конкретной формы. Или объелдинить оба класса в один.
Понятно ли я объяснил? Увы, без примеров кода объяснения получаются абстрактными.
Когда ты посмотришь примеры разных ООП-фреймворков, у тебя со временем появится интуитивное понимание, где что лучше использовать.
>>1102132
Ну когда будут использоваться, тогда можно код переделать. Почитай-ка статью и узнай про YAGNI: https://habrahabr.ru/post/153225/
Напомню всем любителям поломать голову над ООП, что в этом треде есть задача про Гостиницу и Продюсерское Агенство (ищите поиском), и я пока что-то ни одного решения не видел, только обсуждения.
Ubuntu server (не desktop) вполне адекватная вроде. Разве что у меня в виртуалке логин притормаживает в сравнении с дебианом. А что тебе-то не нравится?
>>1101898
Можно и создавать. Зависит от ситуации. Ну например, если не может быть причин заменять класс на что-то другое, то можно его там же и создать. Ну например, если у нас форма редактирования студента, то валидатор для этой формы вряд ли понадобится менять на другой и можно его там и создать.
Также, если внутренний класс представляет собой не сервис, а сущность, и они иногда должны создаваться, тоже проще обойтись без DI.
DI должен использоваться там, где это уместно, где это решает какую-то проблему, а не вообще для любых классов. Использование DI подразумевает, что мы можем передать другую реализацию зависимости. Но тут ведь это явно не так. Нам нужен один конкретный валидатор и нельзя сюда передать какой-то модифицированный валидатор.
На практике, может показаться, что DI тут использовать удобнее. Ведь скорее всего, у FormValidator есть тоже какие-то зависимости, например, доступ к БД. Его надо как-то передать туда, и получается, что удобнее тут использовать DI и передать ответственность за получение зависимостей DI контейнеру.
Если зависимостей у FormValidator нет, можно не использовать DI.
Есть еще вариант передавать зависимости в FormHandler:
class FormHandler
{
public function __construct($dep1, $dep2, $dep3)
{
$validator = new FormValidator($dep1, $dep2, $dep3);
}
Но тут видна нелогичность: не проще ли передавать сразу $validator вместо 3 зависимостей? Но если мы сделаем DI (будет принимать $validator снаружи), то получается, что мы готовы работать с несколькими вариантами валидатора. Что тоже нелогично. Это говорит о том, что мы не очень удачно сделали разделение ответственности между классами.
Потому что у нас и FormHandler заточен на работу только с одной конкретной формой, и FormValidator - тоже. Может есть смысл как-то перераспределить код так, чтобы был отдельно универсальный валидатор или класс для работы с любыми формами, а отдельно - класс, хранящий информацию (правила валидации) для какой-то конкретной формы. Или объелдинить оба класса в один.
Понятно ли я объяснил? Увы, без примеров кода объяснения получаются абстрактными.
Когда ты посмотришь примеры разных ООП-фреймворков, у тебя со временем появится интуитивное понимание, где что лучше использовать.
>>1102132
Ну когда будут использоваться, тогда можно код переделать. Почитай-ка статью и узнай про YAGNI: https://habrahabr.ru/post/153225/
Напомню всем любителям поломать голову над ООП, что в этом треде есть задача про Гостиницу и Продюсерское Агенство (ищите поиском), и я пока что-то ни одного решения не видел, только обсуждения.
что я делаю не так с таблицой умножения?
Может быть дело в "++"?
https://ideone.com/KUFAQ8
спасибо
WINNER!
Вот я хлебушек, разобрался.
$a < 10, $b < 10
тут ошибка. Учитываться будет только последнее условие. Надо писать с использованием оператора "И", то есть &&:
$a < 10 && $b < 10
Потому что в первой и третьей части ты просто указываешь действия. А в средней части - условие проверки, и тут запятую использовать нельзя.
Прокомментирую, почему так: запятая - это оператор, который отбрасывает значение выражения слева, и возвращает значение выражения справа. Этот оператор можно использовать только в заголовке for.
То есть $x, $y даст тот же результат что и $y (если $x не выполняет никаких действий, а только что-то проверяет).
ну вот скачал я ваш netbeans php
настроил всё, не самодельничал
и не могу подключиться к локалхосту
Алсо, может тебе помогут такие команды композера:
> prohibits Shows which packages prevent the given package from being installed.
> why Shows which packages cause the given package to be installed.
> why-not Shows which packages prevent the given package from being installed.
Игру сапер или другие задания отсюда: https://gist.github.com/codedokode/ce30e7a036f18f416ae0#3-Сапер (прокрути до сапера, там вначале идут простые задачи, а потом поинтереснее)
Слишком просто? Есть игра поинтереснее, Арканоид: https://gist.github.com/codedokode/9933897
Хочется что-то более реалистичное? Сделай сайт-приложение (SPA), где можно просматривать ленту картинок, разбитых по категориям, можно ставить лайки и сохранять в избранное. Разумеется, SPA должен частично сохранять работоспособность даже при пропадании связи с интернетом.
Еще сложнее? Сделай простой мессенджер.
Слишком просто??? Ну ладно, так и быть, держи задание уровня nightmare (его решило 0 человек): https://github.com/codedokode/pasta/blob/master/js/spa.md Молодец, что ты не ищешь легких путей, и просишь задачи посложнее, это тебе наверняка поможет в будущем.
Если совсем вкратце, то в большом количестве nosql бд, ты жертвуешь фичами и гарантиями современных реляционных бд ради красивых цифр в бенчмарках.
То есть некоторые специализированные nosql вполне ничего, но,например, какую-нибудь монгу не очень понятно зачем вообще использовать в среднем проекте.
бывает, чо.
алсо, нетбинс тут не любят.
если ты на винде, ставь openserver - там все сразу работает из коробки. также в шторме есть простой способ запускать вебсервер, который дает пхп. также в пхп есть встроенный вебсервер по php -S, кажется.
Я не совсем уверен, что сказал @kubk по поводу старых тредов, но они скоро появиться
>>1099200
>2.Как вообще запихивать скобки в регулярные выражения?
Ещё можно экранировать с помощью символа \
https://secure.php.net/manual/ru/regexp.reference.escape.php
Чтобы подключиться к чему-то нужно иметь веб-сервер принимающий HTTP-запросы. К примеру Apache2.
В&О по установке https://github.com/codedokode/pasta/blob/master/soft/apache-install.md
Если хочешь продвинутой информации, вот урок по http-запросам https://github.com/codedokode/pasta/blob/master/network/http.md
Если тебе просто пробежаться по синтаксису можешь попробовать какие нибудь ущербные курсы вроде codeacademy пролистать, если серьезно вникать то по php, наверное один нормальный учебник это http://www.phptherightway.com/
https://ideone.com/9fjsix
У тебя скобка после return не закрыта, функцию вызываешь уже после вывода, если хочешь вывести переменную в строке используй обратные ковычки `{$var}`.
Спасибо большущее, разобрался
Дали тестовое задание, не могу разобраться с позиционированием и актуальными инструментами для верстки, тут фреймворк, там reset.css, тут хуй рассказывает как верстать через костыли актуальные в 2008.
Ссылка на /chain/ стоит на значке № и хрен догадаешься, что она там есть. Лучше сделать ее более заметной, например, сделав надпись "цепочка сообщений" или как-то еще.
Также, можно убрать прокрутку у длинных постов - это ведь по идее защита от постеров-шутников, которых в архиве скорее всего нету.
>Ссылка на /chain/ стоит на значке № и хрен догадаешься, что она там есть. Лучше сделать ее более заметной, например, сделав надпись "цепочка сообщений" или как-то еще.
Я вообще хочу убрать эту функцию. Я когда проектировал, хотел чтобы обсуждения, которые растягиваются на несколько тредов, вывелись по одному клику. Но вместо этого, если в цепочку попадает ОП-пост или ещё какой-нибудь пост с кучей ответов, то всё превращается в кучу молу.
За место этого, я хочу сделать, чтобы пользователи сами добавляли нужные им посты в "Избранное". Всё равно я планирую прикрутить чатик, поэтому регистрация в любом случае понадобиться.
Нужно обсудить это ещё с моей командой.
>Также, можно убрать прокрутку у длинных постов - это ведь по идее защита от постеров-шутников, которых в архиве скорее всего нету.
Что за защита? Если что будет в посте, то это тоже спарситься из активных тредов.
Я имею в виду, здесь стоит ограничение на высоту поста для защиты от вайперов, которые могут постить посты на 5000 строк из 1 символа. В архиве в этом нет необходимости и прокрутка только мешает читать сообщение.
Если тебе тяжело решить тестовое задание, то представь как тяжело будет решить боевое. Лучше подтянуть свои знания. У нас, кстати, есть задача на вёрстку лэндинга(?) из .psd макета https://github.com/codedokode/pasta/blob/master/html/html.md#Главное-задание-на-верстку-макета
И ещё относительно простые задачки по html/css, которые научат тебя базовым трюкам https://github.com/codedokode/pasta/blob/master/html/html.md#Задания
Ок, я уже добавил это к себе в задачи. Мне тоже не удобно читать посты с прокруткой.
Ссылочка https://mackeepersecurity.com/post/virtual-keyboard-developer-leaked-31-million-of-client-records
Какое отношение это имеет к веб-разработке? Прямое. В веб-разработке точно также используется MongoDB.
Большое спасибо, попробую разобраться. Проблема в том, что я смотрю в psd шаблон и понимаю как все должно выглядеть и какие должны быть параметры/отступы, в каких блоках какие типы элементов должны распологаться, но когда доходит до верски - то все идет по пизде и я понимаю что все свои мысли для решения не могу перенести в html/css код, буду учиться, еще раз благодарю.
Тебе надо изучать позиционирование. У меня есть такой недописанный урок, и в нем картинка со всеми имеющимися видами позиционирования элементов: https://github.com/codedokode/pasta/blob/master/html/positioning.md#Виды-позиционирования
Тебе надо знать их все. И тогда ты, глядя на макет, просто в уме представляешь как это реализовать.
То есть ты просто пока плоховато знаешь CSS или учил его по урокам, которые не рассказывают подробно про позиционирование, как мне кажется.
Я например в большинстве случаев могу написать CSS код не проверяя его в браузере, затем открыть страницу и она, скорее всего, отобразится как задумано с небольшими косяками, которые я исправляю. Я также стараюсь заранее продумать такие вещи, что например, текст может быть короче или длиннее, пунктов в меню может быть больше итд.
А вот те, кто делают верстку "опытным" путем, постоянно правя что-то и смотря результат в браузере - у них конечно все это идет медленно и неэффективно.
Вообще, в большинстве случаев там все просто - обычно сайт собран из вертикально расположенных блоки, которые иногда деляnся на несколько частей или колонок.
CREATE DATABASE ...
CREATE TABLE ...
INSERT ...
UPDATE ...
SELECT ... ORDER BY/OFFSET/LIMIT
DELETE ...
Но в боевых задачах, практически, всегда нужно будет работать с БД. Поэтому, запросы нужно знать хорошо.
Есть урок и задачи по SQL https://github.com/codedokode/pasta/blob/master/db/databases.md
Спасибо.
Я тут еще один вопрос задам. Возможно глупый.
Чтобы подключить базу данных к PHP нужно PDO изучить, да?
Увы, этот сайт недоступен на русском языке. Что, конечно, создает проблемы. Но! Ты, анон, да-да вот именно ты, можешь это изменить.
Они запилили поддержку переводов https://github.com/firasdib/regex101-translations/
Чтобы на сайте появился русский или другой близкий и понятный тебе язык, нужно взять файл вроде https://github.com/firasdib/regex101-translations/blob/master/english.json , и в каждой паре слов справа заменить английские слова на переведенные.
В файле есть специальные конструкции вроде {0}, они обозначают места, куда будет вставлен какой-то дополнительный текст, их надо оставить.
Я бы также советовал параллельно читать мануал http://php.net/manual/ru/pcre.pattern.php и делать перевод, используя одинаковые термины, чтобы не сбить читателя с толку.
Более того, чтобы не делать это руками, запилен сайт для переводов https:// r101 cf / projects/regex101/ (русского там нет). Если перевод уже есть - не беда, можно его проверить и одобрить/предложить исправление.
Если у тебя, анон, есть время, и если ты сейчас изучаешь регулярки, почему бы не поучастовать? Ты лучше будешь знать английский язык, выучишь полезные термины.
Если ты, анон, уже чем-то занят и делаешь сложный проект, то эта задача наверно не для тебя.
>>1103688
Если будешь делать бекенд на PHP, то больше сможешь изучить (reactphp например).
Можно. Так же как и с массивам не в виде байтов.
Да. Строка в PHP это и есть массив байтов (не символов).
$s = '12345';
// запись байта в массив
$s[0] = ord(0x35);
// или
$s[0] = "\x35";
// чтение
echo chr($s[1]);
// размер массива
echo strlen($s);
Для масштабируемых чатов, я бы волшебный обратил внимание на akka и java/scala или вообще какой-нибудь erlang. Акторная модель многопоточности, которая там и там используется, очень хорошо подходит для чатов
Да, но там ничего сложного. В задаче о студентах всё написано https://github.com/codedokode/pasta/blob/master/student-list.md#Работа-с-базой-данных-из-php
Не забудь прочитать статью на хабре https://habrahabr.ru/post/137664/ она поможет разобраться в том чем является PDO
>волшебный
Надо было и не фиксить, мне приятно.
Знаю только JS/php/sql и начал изучать Golang читаю доки в свободнее от работы и чтения других доков время
Не могу же заказчику заявить, мол я буду делать на незнакомом мне языке чат, поэтому это займет в 3 раза больше времени чем нужно.
Кстати, го тоже неплохо пойдет под задачу.
А так я думал, что это для себя пишется. Если для заказчика, то да, надо брать знакомое и проверенное.
Оп, ну хоть намекнуть можешь?
Всё было хорошо да, почему странное поведение такое у гибкого сравнения?
В JS пикрелейтед.
Даже если логически подумать - сравниваются значения с разными типами, почему бы их просто не привести к булевому значению и не сравнить их между собой? 0 => false, не пустая строка => true . Как итог false == true => false
Все эти блоки запихиваю в хедер, телефон, две кнопки в правую часть хедера с помощью списка, логотип по центру который заезжает на слайдер, плюс меню, на которое опять же заезжает логотип, как запихнуть меню в ебучую нижнюю часть хедера стык в стык и при этом вставить пробел между 3 и 4 пунктом? Намекните куда смотреть при чтении позиционирования.
>почему странное поведение такое у гибкого сравнения?
А ты ожидал от такого сравнения чего? Меня бы архитектор за такое просто обоссал бы.
>почему бы их просто не привести к булевому значению и не сравнить их между собой?
Привести string к булеву значению? Да ты зелёный.
Блять, не та картинка
Чел, в 2003 версии MVS net С++ можно было делить на ноль ссылкой (пофиксили в 2012 году). Но это не значит что С++ так был задуман. Как то странно косячить, а потом делать вывод что это язык виноват. Нет чел, ты должен понимать что ты делаешь и зачем.
Это баг. В 7.2 его пофиксили.
я бы тебя тоже обоссал
>>1103926
вот таблица сравнения типов http://php.net/manual/en/types.comparisons.php
также почитай про операторы сравнения http://php.net/manual/en/language.operators.comparison.php
конкретно вот: If you compare a number with a string or the comparison involves numerical strings, then each string is converted to a number and the comparison performed numerically.
также если ты думаешь, почему echo выводит строку, то вот ответ http://php.net/manual/en/language.types.string.php A boolean TRUE value is converted to the string "1". Boolean FALSE is converted to "" (the empty string). This allows conversion back and forth between boolean and string values.
>я бы тебя тоже обоссал
Окай, в какой ситуации такое сравнение было бы уместным и при этом не выглядило бы как говнокод?
понятно, что это говнокод. сейчас вообще не используют нестрогое сравнение, а если где-то оно необходимо, то скорее всего за этим кроются дикие костыли.
я это к тому, что если явно чувак вкатывается, учится - то помоги ему, поделись своим ценным опытом. к тому же, вполне вероятно, что php после js кажется ебанутым (уж js после php точно кажется).
А, тогда сорян. Я просто привык что в тред только зелёные с таким вопросом входял (Вопрос кстати скопирован из лурочки).
Я не спец по вёрстке, но, по-моему, проще всего сделать
<ul class="menu">
<li>Menu 1</li>
<li>Menu 2</li>
<li>Menu 3</li>
<li class="slider">Slider</li>
<li>Menu 4</li>
<li>Menu 5</li>
<li>Menu 6</li>
</ul>
.menu li {display:inline-block; margin: 0;} .slider {width: 1020px; //??? heaght:1020px; //???}
Спасибо, я разобрался. Какие-то либы (от symfony и sensiolab) я просто удалил, т.к. в skeleton-проекте их не было, а значит они уже не нужны. У некоторых обновил версию. Ну а с stof/doctrine-extensions-bundle я так и сделал, форкнул себе форк того чувака, что сделал поддержку 4ой версии и её подрубил.
Один плюс - я за эти дни почитал доки composer'а. Стал лучше его понимать
Еще с парой вещей пришлось повозиться, например, папка web теперь public.
>И твое выражение не захватывает все слово из-за этого. Например: П(о)(с)т(а)вка. Видишь, как хорошо зашифровано, даже твоя программа его не может справиться.
Подскажи как для таких слов сделать регулярку, я не совсем понимаю.
Начал учиться вебдеву потихоньку. Кое-какой задел уровня базовых знаний о субд, языках разметки, графических редакторов уровня полупроебанной шараги имеется, но я решил для начала систематизировать всю эту хуйню и дозаполнять пробелы в знаниях (на уровне знания синтаксиса и прочей базы, просто тупо чтобы понимать что как работает), а потом уже приниматься за всякую продвинутую и оптимизирующую рабочий процесс хуету типа фреймворков.
Кароче щас я хочу выдрочить сырой хтмл/цсс/пхп/яваскрипт и мне нужно где-то взять (бисплатна без смс) ворох псд шаблонов чтобы на них потренироваться, может есть че порекомендовать?
Пока только принтскринил чужие сайты и пробовал верстать их, но подумал что мб есть какие-нибудь спец шаблоны для целенаправленной дрочбы обучающихся
с интересными йоба-задачками.
Если я ошибся тредом дайте мне НАПРАВЛЕНИЕ, ток не пиздите ногами. Спс.
Заодно было бы неплохо получить общие рекомендации о том, что учить дальше, мб что в ближайшем будущем может стать актуальным и стоит начать учить уже сейчас.
на лурке статья про php образца начала 2000-х (в плане фраз типа "недавно ввели неймспейсы, но их никто не использует"), у меня до сих пор пиздец как пригорает от нее
Заебись, спасибо
В ОП посте есть задачи на HTML/CSS, начиная с простейших и в конце задание на верстку макета.
Если этого мало, гугли free psd templates, но учти что они в большинстве плохого качества и придется отсеивать нормальные.
>>1104085
Если ты хочешь захватить такое слово, то надо писать регулярку в стиле "кириилица - 1 латинская буква - любые буквы".
Если ты хочешь еще и исправлять или выделять ошибки, то проще разбить текст на массив слов и работать с каждым индивидуально.
>>1103939
Центральный квадрат - это ведь логотип?
Тут можно поступать по-разному.
1) Можно разбить шапку по горизонтали на 3 части (левая, логотип и правая). Это можно сделать за счет float: right/left, за счет inline-block, за счет display: table, flexbox. Два последних варианта (table, flexbox) позволяют сделать резиновую шапку, в которой левая и правая части будут растягиваться под ширину шапки. Первые 2 варианта - только шапку фиксированных либо процентных размеров (впрочем, с флоатами тоже можно сделать резину, если сделать 2 флоата шириной по 50% и внутри них фиксированный отступ под логотип).
Затем добавить в левую/правую части 2 отдельных куска меню, добавив отступ от верха паддингом или маргином. Телефон и кнопку можно зафиксировать с помощью абс. поз либо сделать обычным блоком.
.header
-- .header__left
---- .header__left-menu
---- .header__phone
-- .header__logo
-- .header__right
а можно, как советуют ниже, сделать логотип частью меню. Например, так: добавить в меню средний пункт, такой же высоты, как и другие, а в него с помощью абс. поз. вставить большой логотип так, что низ логотипа прижат к точке чуть ниже пункта меню (bottom: -10px).
Само меню можно сделать на флоатах с процентами, inline-block, на table или flexbox.
2) Можно сделать 2 отдельных меню, прижатых вправо/влево за счет флоата, а логотип закрепить абс. поз., либо сделать его обычным отцентрированным блоком. Абс. позиционирование хорошо тем, что логотип не будет ничего никуда расталкивать. Флоаты при желании можно сделать как 50% шапки, чтобы все было резиновым.
3) Как тут уже предложили, можно сделать в меню пункт под логотип и в него поместить логотип с помощью абс. поз.
ul.header-menu
-- li
-- li
-- li
-- li.header-menu__center
---- .header-logo
-- li
....
То есть вариантов много.
В ОП посте есть задачи на HTML/CSS, начиная с простейших и в конце задание на верстку макета.
Если этого мало, гугли free psd templates, но учти что они в большинстве плохого качества и придется отсеивать нормальные.
>>1104085
Если ты хочешь захватить такое слово, то надо писать регулярку в стиле "кириилица - 1 латинская буква - любые буквы".
Если ты хочешь еще и исправлять или выделять ошибки, то проще разбить текст на массив слов и работать с каждым индивидуально.
>>1103939
Центральный квадрат - это ведь логотип?
Тут можно поступать по-разному.
1) Можно разбить шапку по горизонтали на 3 части (левая, логотип и правая). Это можно сделать за счет float: right/left, за счет inline-block, за счет display: table, flexbox. Два последних варианта (table, flexbox) позволяют сделать резиновую шапку, в которой левая и правая части будут растягиваться под ширину шапки. Первые 2 варианта - только шапку фиксированных либо процентных размеров (впрочем, с флоатами тоже можно сделать резину, если сделать 2 флоата шириной по 50% и внутри них фиксированный отступ под логотип).
Затем добавить в левую/правую части 2 отдельных куска меню, добавив отступ от верха паддингом или маргином. Телефон и кнопку можно зафиксировать с помощью абс. поз либо сделать обычным блоком.
.header
-- .header__left
---- .header__left-menu
---- .header__phone
-- .header__logo
-- .header__right
а можно, как советуют ниже, сделать логотип частью меню. Например, так: добавить в меню средний пункт, такой же высоты, как и другие, а в него с помощью абс. поз. вставить большой логотип так, что низ логотипа прижат к точке чуть ниже пункта меню (bottom: -10px).
Само меню можно сделать на флоатах с процентами, inline-block, на table или flexbox.
2) Можно сделать 2 отдельных меню, прижатых вправо/влево за счет флоата, а логотип закрепить абс. поз., либо сделать его обычным отцентрированным блоком. Абс. позиционирование хорошо тем, что логотип не будет ничего никуда расталкивать. Флоаты при желании можно сделать как 50% шапки, чтобы все было резиновым.
3) Как тут уже предложили, можно сделать в меню пункт под логотип и в него поместить логотип с помощью абс. поз.
ul.header-menu
-- li
-- li
-- li
-- li.header-menu__center
---- .header-logo
-- li
....
То есть вариантов много.
Да, можно. В случае, если ты используешь апач, нужно изучить mod_rewrite и зарулить такие запросы на один скрипт, если нгинкс то просто зарулить все запросы к PHP на один скрипт index.php.
То есть ты можешь настроить любое соответствие между URL и именем файла. Обычно все запросы, которые не идут к статическим файлам, заруливают на index.php и дальше уже в PHP коде анализируют запрос.
С точки зрения SEO и с точки зрения логики иметь 2 страницы с одинаковым контентом это плохо.
>>1103927
Не надо нервно так относиться к вопросу.
>>1103926
Если ты исопльзуешь == и сравниваешь строку с числом, то PHP преобразует эту строку в число. Используй === вместо ==.
>>1103936
Для любителей похоливорить по поводу языков даю справочник https://habrahabr.ru/post/315152/
>>1104106
Почитай https://habrahabr.ru/post/315152/ и успокойся.
Извиняюсь за оффтоп, но:
Статья интересная, но в некоторых местах какая-то странноватая:
> Haskell
> Неприятная система типов.
> Scala
Названы всякие мелочи, основные минусы не сказаны.
>C#
> Продвигает устаревшее (типы вариантов и LINQ, что существенно добавляет беспорядка).
Что хотел сказать автор вообще не понятно.
К тому же жалуются на то, что не компилируются куски совершенно семантически бредового кода типа foreach(var i in ints) { i = i + 1; }
Кстати, php-кун, можешь посоветовать какую-нибудь не сильно долгую задачку на которой можно новую технологию для SPA протестить, а то обычный todoMVC надоел?
я спроектировал продюсерское агентство ну и базу данных для него. Там нет реализации ничего, кроме тех параметров которые как я подумал необходимы. В некоторых функциях возвращаю $this чтобы можно было красиво инициализировать объекты как в шаблоне строитель.
http://sandbox.onlinephpfunctions.com/code/4d9a7a089423b0849ace858480486f55486f9d75
Хорошо, тогда расскажу тебе про подводный камень, который ты не учел. Другие аноны, не сморите под спойлер, если не решили задачу про Агенство: ты забыл, что один человек может быть и Актером, и Моделью. Более того, он может приобретать новые навыки со временем
Также, ты использовал наследование, чтобы добавить некоторым классам свойство "есть менеджер". Недостаток наследования в том, что ты не можешь с его помощью добавить некоторым классам еще какое-то общее свойство. В таких случаях стоит также рассмотреть возможность использовать интерфейсы.
Урок https://github.com/codedokode/pasta/blob/master/php/interfaces.md
Если кому-то интересная задача, то вот она: >>1094213
>Если ты хочешь захватить такое слово, то надо писать регулярку в стиле "кириилица - 1 латинская буква - любые буквы".
Спасибо большое! Чекни код, пожалуйста.
https://ideone.com/5PP57b
Я зашел в php.ini и расскоментил extension=php_pdo_mysql.dll
и перезапустил сервер.
Далее я присоединился к БД ( название базы данных 'zoo' в ней есть таблица 'pet')
https://ideone.com/D5iSIK
А дальше у меня ничего не получается. Я пытался читать мануал, я не знаю, что именно делать. Помогите, пожалуйста
Напиши или заскриншоть что выводится при запуске скрипта. Проверь, что в php.ini стоит display_errors = 1 (показывать ошибки на экране).
Если у тебя все работает, но ты не понял, как пользоваться PDO, что начни с изучения примеров
http://phpfaq.ru/pdo
https://phpdelusions.net/pdo (англ)
https://habrahabr.ru/post/137664/
Запрос без плейсхолдеров на изменение данных делается через exec по моему.
SQL-Запрос на получение данных делается через query либо через prepare + execute.
А, кстати, SQL-то ты знаешь?
Тогда я думаю пихать классы специальностей(Модель, Актер и Музыкант) в поле $talants в класс TalantedPerson, убрать у них наследование от Person. Так же добавить в TalantedPerson метод addTalant getTalant. Ну и получается что TalantedPerson будет реализовывать интерфейс с этими методами.
Для талантов же сделать интрефейс с методами getTalantName и getPropitries, setPropirtes.
Просто мне кажется что свойство-массив это плохо, но ничего другого в голову не приходит
http://sandbox.onlinephpfunctions.com/code/0d1f403bd9d989d3d63aa0ae9dbad81ba64a5490
Учебник из ОП-поста могу читать с телефона, ну и уже накачал Eloquent JavaScript, Dive into Python, по Яве какую-то книгу, которую в факе яватреда порекомендовали.
Использование методов вроде getParams никуда не годится. Вот почему.
Допустим, у тебя есть фукнция такого вида:
function x(TalantInterface $talant) {
}
Что можно сделать с переменной $talant? Можно вызвать единственный метод getParams(), который вернет массив непонятно чего. Пользы от такого интерфейса ноль. Это не ООП.
Более того, название getParams вообще ничего не значит. Оно эквивалентно просто get.
Не нужен тут TalantInterface и метод getparams.
Достаточно просто сделать класс Person и у него массив навыков. Вот и все.
Если ты изучаешь PHP, то тебе достаточно самого интерпретатора (php.exe и другие файлы). Он не требует прав админа и ставится в любую папку, в ОП посте есть инструкция по установке.
В PHP встроен простой веб-сервер, потому тебе на первых порах даже не нужен Апач. Поднять локально сайт можно только с помощью PHP.
Если у тебя сложности с установкой MySQL на компьютер, то можно использовать вместо нее расширение PHP под названием sqlite. Это встраиваемая (внутрь интерпретатора PHP) база данных, поддерживающая язык SQL. Диалект там немного отличается от MysQL, но во многом похож.
Также ты можешь скачать мануал по PHP: http://php.net/download-docs.php
В том числе на русском, в том числе в формате chm с поиском.
Это минимальный набор, если ты можешь установить больше, то конечно ставь. И освой какую-нибудь программу для скачивания сайтов в формат HTML или CHM, чтобы их можно было читать в оффлайне. В Андроиде в встроенном браузере, если что, можно сохранять страницы для чтения.
Мой гитхаб https://github.com/codedokode/pasta/ можно скачать в виде zip-архива (правда, уроки будут в формате .md ).
Главная сложность, конечно, в том, что гуглить нельзя.
Ну хочу в веб вкатиться, для начала научиться в пхп, sql, сервера. Там в процессе уже пойму, что мне интереснее, фронтенд или бэкенд.
>>1104269
>то тебе достаточно самого интерпретатора (php.exe и другие файлы)
Неудобно же, в netbeans подсветка всей хуйни, контроль скобок и т.п.
>Главная сложность, конечно, в том, что гуглить нельзя.
С телефона можно. Проблема в том, что я нищук с Windows Phone, который, сука, запрещает скачивание .exe, .msi и так далее.
>Мой гитхаб https://github.com/codedokode/pasta/ можно скачать в виде zip-архива (правда, уроки будут в формате .md ).
Вот за это спасибо большое.
{
if ($num =0){
return 1;
} else {
$result = 1;
for ($i=2; $i<=$num; $i++) {
$result = $result*$i;
}
return $result;
}
}
почему 1 возвращает?
Я понял что вместо проверки присвоил 0 дурачок.
>Дата последнего редактирования 27 октября 2017
Давай не будем, ок? Практическая польза от этого выражения нулевая. Теоретическая тоже. И я сомневаюсь что ньюфаг сможет догадаться до такого. Спиздил с лурочки, и припёрся в тред потраллировать.
И я задумался, раз мне это так нравится, мб стоит потратить силы, сдать егэ и поехать учиться на программиста, в какой то средний институт в мск/питер или любой другой город
Или все же лучше еще учить пхп и все к нему прилагающее. И если сделаю все задачи от ОП нормально и что то свое, раскидать просто резюме на джуна или фриланс попробывать?
Ну у автора свое мнение.
Да кем бы ты ни стал, хоть программистом, хоть слесарем, хирургом - Все зависит от тебя, результат будет один и тот же, я тебя уверяю.
Почему не работает:
<?php
$filename = "json.txt";
$json = file_get_contents($filename);
$data = json_decode($json,true);
echo "<pre>";
print_r ($data);
Если написать echo $json, он выдает содержимое файла, все ок, если напрямую в $json вписать содержимое файла в виде строки ($json = "содержимое файла";), то декодирует и выводит $data нормально.
Но если запустить то что я дал изначально - нихуя не выводит. echo $data выдает NULL.
Не понимаю. Все по отдельности работает, в связке нихуя.
>Если я даун 23 лвл, живу в мухосранске, без вышки, работаю на дерьмо работе со средним специальным образованием.
Никогда не поздно начать учиться, порой достаточно лишь желания.
>Вот вроде прохожу обучение от ОП, мне это интересно, я получаю кайф когда понимаю как что то сделать, делаю студентов, сижу по пару часов в день за этим занятием(мб я бы сидел больше, если бы у меня было время).
У ОПа все задачки специально сделаны с таким раскладом, чтобы было легко, тебе уже подали на блюде то, что нужно решать, я не критикую, для базы вполне сойдет, сам же выполнял эти задачки. (Хотя я бы отталкивался от спецификации и официальных источников, документации и чем больше информации в плане ссылок, источников и полезностей тем лучше). Т.е советую САМОМУ придумывать себе задачи и самостоятельно писать программы, не считай часы, к черту их, учись сколько можешь, хоть 15 минут, главное чтобы в голову лезло.
>И я задумался, раз мне это так нравится, мб стоит потратить силы, сдать егэ и поехать учиться на программиста, в какой то средний институт в мск/питер или любой другой город
Университет по большей сути ничего тебе не даст, вот серьезно, туда нужно будет идти, отстреливаться и идти на работу джуна. Мой знакомый который учился на матфаке говорил, что когда они программировали их просто запирали и давали кодить, решать задачи, кучу просто, под конец семестра их число превосходило миллион, а у них там C/C++
>Или все же лучше еще учить пхп и все к нему прилагающее. И если сделаю все задачи от ОП нормально и что то свое, раскидать просто резюме на джуна или фриланс попробывать?
Я бы посоветовал параллельно учиться и работать джуном.
То есть мне надо сделать во всех функциях/методах проверку и если ошибка кидать исключение. и что бы грузился уже не контролер а страница ошибки. то есть исключения что бы при ошибки, приложение не работало дальше. что бы ничего не поломалось? а перехватывать исключения это уже на усмотрение.
код заработал вроде
https://github.com/dsgaljkeguhodgiosetuhsegjposguh/studlist
Разобрался, спасибо за помощь.
$randomValue = $array[array_rand($array)]
У меня суть какая. Я нуб-недофрилансер и от меня хотят страницу с именем вида website.ru/iphone-x, а сайт на какой-то самописной CMS и страницы там создаются с именами вида website.ru/index.php?id=100. Мне бы как-нибудь сделать, чтобы в адресной строке было website.ru/iphone-x, а на деле контент отдавался с адреса website.ru/index.php?id=100. Конкретных файлов как таковых нет.
ну в чужую голову не залезешь, так что, да, не будем.
Я на практике сталкивался только с SOA и там все довольно понятно - есть отдельные проекты, для каждого отдельный репозиторий и они общаются по АПИ. А что такое микросервисы?? Читал https://stackoverflow.com/questions/25501098/difference-between-microservices-architecture-and-soa но все формулировки размытые, единственная не размытая - это "в принципе это одно и то же".
mod_rewrite для апача или содомировать конфиг nginx. эта хуйня зовётся https://ru.wikipedia.org/wiki/Семантический_URL.
http://sandbox.onlinephpfunctions.com/code/d2170294a7293a1e73795358d3ebbac14ada7a61
Я видел где-то такое определение: микросервис - это приложение, которое пишется маленькой командой (например, 3 человека) за 2 недели. Если приходит новая команда и ничего не может понять в коде, она просто переписывает микросервис с нуля.
В чем профит микросервисов? Мне кажется, главный профит тут в том, что работа большой командой над одним проектом вызывает какие-то сложности (какие?), и вынесение части кода в микросервисы позволяет выделить небольшие команды, которые занимаются только этим микросервисом.
Также, плюс в возможности распараллеливания и масштабирования проекта на много серверов.
Можно использовать разные языки программирования.
Минусы (в сравнении с монолитом):
- накладные расходы на передачу данных через АПИ
- при обновлении АПИ микросервиса надо обновлять и другие проекты, которые пишут другие команды. Нужно подбирать работающую комбинацию этих микросервисов. Получается как в линуксе: хочешь обновить один пакет, а оказывается что ему нужен пакет версии, которой в твоем дистре нет, или в котором есть баги.
- сложность разворачивания окружения, в том числе локально, приходится тащить докеры, докер-композер и все это, я думаю, здорово тормозит, жрет память и работает только на линуксе.
- проблемы с отладкой: ты не можешь, как в монолите, отслеживать пошагово выполнение кода
- проблемы с репортом ошибок: у каждого сервиса свои логи
- проблемы с пониманием кода: надо при изучении кода прыгать между микросервисами, а ведь они могут быть написаны на разных языках (можно решить качественной документацией)
- если ты нашел баг в другом микросервисе, то кто должен его исправлять? Ты? Другая команда? Это добавляет расходы на коммуникацию.
В общем, видно, что использовать микросервисы не всегда выгодно. С другой стороны, если ты строишь вконтакте, то без этого не обойтись.
спасибки. то есть, получается, что микросервисы от СОА отличаются размером собственно сервисов.
расскажу как у нас в СОА было:
- основная часть была на php, а сервис чатиков на go
- на условно 10 сервисов, которые составляли приложения, шестью занималась "команда веб-разработки", то есть любой из нее мог шариться в любом сервисе, а еще 4 распределялись между командами, где каждая (мобильники, почта, чатик и т.д.) занималась только одним. притом юмор в том, что там каждый тимлид решал, какие использовать фреймворки и они везде были разные (симфони, зенд, ларавел)
- развроачивать все это локально ни у кого даже мысли не было ввиду сложности всей структуры (там еще было миллион баз с шардированием, сервер очередей и т.д.). просто был дев-сервер и к нему можно было подключиться по впн при необходимости. у каждого была своя папочка на сервере и свой хост
- да, логи везде свои и нужно добавлять какой-нибудь идентификатор для каждого запроса, чтобы отслеживать их во всех сервисах. по идее можно сделать какой-нибудь простой клишный скрипт-клиент, который их все по идентификатору будет собирать, но никто с этим не заморачивался
- проблемы из серии "нашел баг в другом сервисе" у нас почему-то ни разу не было. мы в чужих и не лазили
- проблемы с отладкой есть первое время, потом когда понимаешь точки взаимодействия (их обычно не так много и в основном между двумя сервисами), как-то не замечаешь. единственный нюанс - нужно держать несколько проектов шторма одновременно открытами (тут линуксовые воркспейсы решают)
Покажи, что ли.
Если я хочу перенести директорию с сайтом из /var в /home, то в конфиге phpmyadmin ее тоже надо менять или он умный и сам догадается?
Есть базовый класс ApiRequest. У него есть наследники CreateProductRequest и UpdateProductRequest, структура примерно такова:
Request/
- ApiRequest.php
- CreateProductRequest.php - https://ideone.com/vQQA0R (cодержит require_once)
- UpdateProductRequest.php - https://ideone.com/vuJs0A (не содержит require_once)
public/
- api.php - https://ideone.com/hctPzV
При попытке обратиться к api.php просходит ошибка в классе UpdateProductRequest - не удаётся найти класс ApiRequest. Если разобрать порядок подключения файлов в api.php, то должно выйти как-то так:
1) Подключение CreateProductRequest, в котором подключается ApiRequest
2) Подключение UpdateProductRequest
Проблема изчезла после того, как в UpdateProductRequest был добавлен require_once
Нет ни у кого идей? Этот код работал локально и на старом сервере месяца 4, проблемы возникли только на новом сервере. Версии PHP везде 5.5.9
>Теги (темы) — можно указать любые, через запятую, при этом все введенные теги собираются в таблицу и используются для автодополнения. Регистр букв в теге не имеет значения, «физика» и «Физика» — один тег (возможно стоит их принудительно переводить в нижний регистр). Если теги различаются только знаками пунктуации, то же самое (теги могут содержать только знаки дефис, запятая, точка (не в конце названия)).
Немного не понял.
Есть в базе тег "мат анал". Юзер вводит "мат.анал". Что нужно из этого сделать?
- Сохранить "мат.анал" и при поиске по любому их этих тегов суммировать результаты по обоим? Тут будет проблема в наличии дубликатов.
- Преобразовать пользовательский тег к "мат анал", что бы не было дубликатов. Тут будет проблема, что юзер вводит одно, а сохраняется другое. Юзер нервничает и материться
- Мой вариант. Разрешить только символы алфавита и пробел. И выводить ошибку валидации, если юзер вводит недопустимые символы. Это решает и первую и вторую проблемы
Как правильней, пхп в хтмл писать иди хтмл внутри пхп?
>>ХТМЛ и пхп код могут быть вместе в одном файле.
Они могут быть вместе. Например шаблон страницы с хтмл тэгами внутри которых есть пхп переменные.
>> Как правильней, пхп в хтмл писать иди хтмл внутри пхп?
в файлах пхп писать хтмл тэги.
Лучше все же разделять. Урок про шаблоны в помощь https://github.com/codedokode/pasta/blob/master/php/templates.md
>>1105675
Надо разбить задачу на более простые части:
- разбиваем число на группы по 3 цифры
- пишем функцию, которая переводит в строку число от 1 до 999
- пишем функцию, которая выбирает форму слова (миллион/миллиона/миллионов)
>>1105271
Да, можно ограничить набор символов. Также, иногда используют автодополнение из существующих тегов при вводе.
Дубликаты все равно в любом случае будут, и кому-то придется потом их склеивать.
spl_autoload_register(function ($class) {
// Получаем путь к файлу из имени класса
$path = __DIR__ . $class . '.php';
// Если в текущей папке есть такой файл, то выполняем код из него
if (file_exists($path)) {
require_once $path;
}
// Если файла нет, то ничего не делаем - может быть, класс
// загрузит какой-то другой автозагрузчик или может быть,
// такого класса нет
});
Немного не понимаю жирный текст.
1)Мы объявляем функцию внутри функции?
2)Например у меня есть класс Cat. Как написать код, чтобы автозагружался класс Cat?
3) Как поступать с абстрактными классами?
Дополню.
index.php:
spl_autoload_register(function ($class) {
// Получаем путь к файлу из имени класса
$path = __DIR__ . $class . '.php';
// Если в текущей папке есть такой файл, то выполняем код из него
if (file_exists($path)) {
require_once $path;
}
// Если файла нет, то ничего не делаем - может быть, класс
// загрузит какой-то другой автозагрузчик или может быть,
// такого класса нет
});
spl_autoload_call("Cat");
$pet = new Cat;
Fatal error: Uncaught Error: Class 'Cat' not found in C:\Apache24\htdocs\index.php:19 Stack trace: #0 {main} thrown in C:\Apache24\htdocs\index.php on line 19
Cat.php
<?php
class Cat
{
public $color;
public $paws;
public $tail;
}
Дополню.
index.php:
spl_autoload_register(function ($class) {
// Получаем путь к файлу из имени класса
$path = __DIR__ . $class . '.php';
// Если в текущей папке есть такой файл, то выполняем код из него
if (file_exists($path)) {
require_once $path;
}
// Если файла нет, то ничего не делаем - может быть, класс
// загрузит какой-то другой автозагрузчик или может быть,
// такого класса нет
});
spl_autoload_call("Cat");
$pet = new Cat;
Fatal error: Uncaught Error: Class 'Cat' not found in C:\Apache24\htdocs\index.php:19 Stack trace: #0 {main} thrown in C:\Apache24\htdocs\index.php on line 19
Cat.php
<?php
class Cat
{
public $color;
public $paws;
public $tail;
}
Чем плох NetBeans?
Единственная нормальная IDE.
Портативная, бесплатная, гибкая, имеет кучу плагинов, красивая, функциональная.
Хотелось бы спросить хотябы какова структура файлов там, че оно вообще такое в общих чертах?
Буду благодарен если кто-то расскажет развернуто по хардкору
в фигурных скобках
петросян.жпг
Когда ты выводишь значение через echo например, в двойных кавычках, то не обязательно делать конкатенацию, как в одинарных.
echo "Меня зовут $name";
А если нужно допилить например окончание?
echo "Меня зовут $namer";
где "r" - не часть имени переменно, то как быть? Берешь название переменной в фигурные скобки:
echo "Меня зовут {$name}r";
Я реально не понимаю. Просто в тредах нет нет, да проскакивают посты о том какое нетбинс гавно и мол phpstorm незаменим. Хотел просто узнать причины и всё.
хз, какой-то он странный мне кажется. Был момент когда PHPStorm мне казался отвратительным, а потом они добавили тёмные темы и мне он показался уютненьким и я на него перескочил с какого-то древнего редактора, возможно даже с Notepad. А это вот NetBeans был прямотаки недружелюбен.
Запомни одно. Все люди в интернете, с которыми ты споришь, просто повторяют, то, что услышали. Аргументов не имеют. Если тебе нравится и всем устраивает- знач збс.
Я вообще долго писали сейчас часто это делаю все на notepad++, ибо он гибкий имеет кучу нужных плагинов и пр. И постоянно был вынужден ловить необоснованные струи мочи
Пишет он в PHP треде. В котором каждый необоснованно (на самом деле иногда обоснованно) ловит струи мочи.
Что за дела?
Система Debian 9, PHP 7.2, Apache 2.4 если это как то поможет :(
Нашёл это: https://pastebin.com/2gPL3vBH
Вот только mysql_ модуль же устарел, по крайней мере так на php.net сказано, да и IDE у меня эти команды не понимает. Говорит, малаца, но переделывай под mysqli_. А я не понимаю как. В качестве аналогов функций типа mysql_tablename указаны запросы, которые, по итогу, возвращают не строку, а какой-то совсем другой объект. Что мне этим делать?
https://dev.1c-bitrix.ru/learning/course/index.php?COURSE_ID=43&LESSON_ID=2287
госпаде, пробежавшись по началу статьи, я уже нашел три оправдания в духе "bitix не говно, просто так проще вам будет говнокодить". Надеюсь, ты сможешь отмазаться от этого проекта, мен
1) Это анонимная функция
http://php.net/manual/ru/functions.anonymous.php
https://habrahabr.ru/post/147620/
https://habrahabr.ru/company/mailru/blog/103983/
2) Автозагрузчик пишется не для одного конкретного класса, а для группы классов. Тебе надо из имени класса получить путь к файлу с ним, и, если такой файл есть, то подключить его.
3)
> Как поступать с абстрактными классами?
Так же, как и с конкретными, ничего специально для них делать не надо. PHP сам вызовет твой автозагрузчик столько раз, сколько потребуется.
> $path = __DIR__ . $class . '.php';
Нету разделителя (слеша) между DIR и именем класса.
Для отладки ты можешь поставить в автозагрузчик echo и выводить имя класса и путь к файлу.
Еще лучше - PDO, тут, например, объясняется, как с ним работать: https://habrahabr.ru/post/137664/
Что касается твоего кода, его очень тяжело читать из-за того, что он написан стеной без разделения на части. Как текст принято делить на абзацы, так же принято делить и код. Ну и названия переменных вроде number1 или sq3 сбивают с толку.
>>1105880
Если ты работаешь без htaccess, то тебе надо приписывать в URL имя скрипта вроде index.php, чтобы было http://localhost/index.php/some/path. Может даже не index.php, а index_dev.php. Надо смотреть, что там у тебя за скрипты.
Также, можно попробовать разобраться с mod_rewrite:
https://habrahabr.ru/company/sprinthost/blog/129560/
http://httpd.apache.org/docs/current/mod/mod_rewrite.html
>>1105832
В мануале написано http://php.net/manual/ru/language.types.string.php#language.types.string.parsing
Я бы для начала в UpdateProductRequest.php дописал бы require для ApiRequest, так как ты не должен рассчитывать на то, что какие-то файлы уже кем-то подключены. Либо же сделать все require в api.php и убрать из других мест.
Также, не используются ли неймспейсы?
Также, нет ли проблем из-за перепутанных маленьких/больших букв в имени файла? Из-за русской буквы в имени файла или класса?
Если ты хочешь увидеть, какие файлы подключаются, ты можешь запустить программу из командной строки из-под strace (только в linux):
strace php public/api.php
Предупреждение: выведется много данных.
Также, можно запустить из под strace встроенный веб-сервер:
strace php -S 0.0.0.0:9000 -t public
И зайти браузером на http://ip-адрес:9000/api.php (в случае хостинга порт 9000 может быть у них заблокирован и это не получится) и опять же посмотреть.
strace показывает все системные вызовы (обращения к ОС), которые делает программа, и там будет видно обращение к файлам. Там среди прочих будут строчки с open - это системный вызов для открытия файла.
Также, может быть, на хостинге используется opcache, и там закешировалась старая версия файла. В этом случае надо очистить opcache.
>>1105066
А она прописана в конфиге? Если да, то надо менять.
Я бы для начала в UpdateProductRequest.php дописал бы require для ApiRequest, так как ты не должен рассчитывать на то, что какие-то файлы уже кем-то подключены. Либо же сделать все require в api.php и убрать из других мест.
Также, не используются ли неймспейсы?
Также, нет ли проблем из-за перепутанных маленьких/больших букв в имени файла? Из-за русской буквы в имени файла или класса?
Если ты хочешь увидеть, какие файлы подключаются, ты можешь запустить программу из командной строки из-под strace (только в linux):
strace php public/api.php
Предупреждение: выведется много данных.
Также, можно запустить из под strace встроенный веб-сервер:
strace php -S 0.0.0.0:9000 -t public
И зайти браузером на http://ip-адрес:9000/api.php (в случае хостинга порт 9000 может быть у них заблокирован и это не получится) и опять же посмотреть.
strace показывает все системные вызовы (обращения к ОС), которые делает программа, и там будет видно обращение к файлам. Там среди прочих будут строчки с open - это системный вызов для открытия файла.
Также, может быть, на хостинге используется opcache, и там закешировалась старая версия файла. В этом случае надо очистить opcache.
>>1105066
А она прописана в конфиге? Если да, то надо менять.
> $word = preg_split
Лучше назвать $words
Программа обнаруживает только слова, где в русское слово вставлена латинница, а хорошо бы еще обнаруживать и исправлять случаи, когда в латинское слово вставлена кириллица.
>>1105675
Ты можешь также показать код, который получился, и спросить, что делать дальше. Хотя бы частично-то ты наверно можешь решить?
>>1104766
У тебя вся логика засунута в Hotel, хотя часть ее лучше поместить в другие классы, например:
> if (($value->getExpireDate() <= $date) || ($value->getExpiredDate() == null)) {
Лучше if ($room->isOccupied($date))
> public function isFreeSpecificRoomsNumber($rooms, $date)
Не лучше ли это сделать методов у объекта Number?
Также, тебе надо разобраться, какие есть сущности и какие у них свойства:
> class Hotel
> private $date;
Почему дата - это свойство отеля? Что-то я не понимаю, где тут логика. дата заезда - это свойство заявки на размещение.
Насчет свойства logs - не логичнее ли историю заселения в номер хранить в самом номере? А то у тебя есть там только expireDate, который не отражает историю заселения. Ну и он не позволяет учесть ситуацию, что номер может быть забронирован в будушем с числа X по число Y.
Логичнее по моему сделать объект "бронь" и в номере сделать список броней. Если группа заселяется в несколько номеров, то можно сделать одну бронь с несколькими номерами, а можно привязать к группе несколько броней - тут уж как решишь.
В теории, список броней в номере позволяет посчитать доход на любую дату. Но на практике, я думаю, можно сделать еще отдельно лог операций. Так как фактическая оплата не всегда соответствует той, что в брони: отель мог сделать скидку за какие-то неудобства, или наоборот, взять дополнительную плату за услуги. Или гость мог сбежать и не заплатить. Или не приехать. В этой задаче лог платежей делать не требуется, но если тебе хочется реализма, то стоит сделать. Плюс, лог позволяет учесть, как именно были оплачены услуги, какие способом (карта/наличные и тд), когда именно. Учесть предоплату за бронирование.
Вот какие я сущности вижу:
- Гостиница
- Номер
- Группа гостей
- Гость
- Бронь (то, что связывает 1 Группу и 1..N Номеров - или 1 Группу и 1 Номер - тут есть разные варианты)
- при желании реализма, объект Оплаты (Счет? не силен в бухгалтерии)
Дальше, мы уже можем решить какие у них есть свойства, и какие между ними есть связи (отношения). Например: Группа содержит Гостей, Группа размещает Бронь, Бронь относится к 1 или нескольким Номерам, Номер содержит список относящихся к нему Броней.
Ты можешь даже попытаться нарисовать эти сущности и связи между ними (есть даже язык диаграмм UML для этого).
Вот не знаю, поможет эта статья или нет, тут упоминаются связи между классами: https://habrahabr.ru/post/150041/
И тут https://ru.wikipedia.org/wiki/Диаграмма_классов
А тут рассказывается про ER модель: https://ru.wikipedia.org/wiki/ER-модель
> private $money;
Тоже не очень понятно назначение свойства
> private function getTotalRooms($freeNumbers)
Не очень понятно, зачем эта функция вообще и что она делает.
> if ($this->getTotalRooms($this->getFreeNumbers($checkIn)) >= count($persons)) {
Это трудно читать из-за обилия скобок. Ну и тут
> foreach ($this->numbers as $key => $value) {
Лучше $numbers as $number
> public function createHotel(Number $number)
Лучше назвать addNumber
То есть у тебя не очень удачно спроектированы классы и из-за этого ты громоздишь весь код в один класс Hotel. И получается уже не совсем ООП.
> $word = preg_split
Лучше назвать $words
Программа обнаруживает только слова, где в русское слово вставлена латинница, а хорошо бы еще обнаруживать и исправлять случаи, когда в латинское слово вставлена кириллица.
>>1105675
Ты можешь также показать код, который получился, и спросить, что делать дальше. Хотя бы частично-то ты наверно можешь решить?
>>1104766
У тебя вся логика засунута в Hotel, хотя часть ее лучше поместить в другие классы, например:
> if (($value->getExpireDate() <= $date) || ($value->getExpiredDate() == null)) {
Лучше if ($room->isOccupied($date))
> public function isFreeSpecificRoomsNumber($rooms, $date)
Не лучше ли это сделать методов у объекта Number?
Также, тебе надо разобраться, какие есть сущности и какие у них свойства:
> class Hotel
> private $date;
Почему дата - это свойство отеля? Что-то я не понимаю, где тут логика. дата заезда - это свойство заявки на размещение.
Насчет свойства logs - не логичнее ли историю заселения в номер хранить в самом номере? А то у тебя есть там только expireDate, который не отражает историю заселения. Ну и он не позволяет учесть ситуацию, что номер может быть забронирован в будушем с числа X по число Y.
Логичнее по моему сделать объект "бронь" и в номере сделать список броней. Если группа заселяется в несколько номеров, то можно сделать одну бронь с несколькими номерами, а можно привязать к группе несколько броней - тут уж как решишь.
В теории, список броней в номере позволяет посчитать доход на любую дату. Но на практике, я думаю, можно сделать еще отдельно лог операций. Так как фактическая оплата не всегда соответствует той, что в брони: отель мог сделать скидку за какие-то неудобства, или наоборот, взять дополнительную плату за услуги. Или гость мог сбежать и не заплатить. Или не приехать. В этой задаче лог платежей делать не требуется, но если тебе хочется реализма, то стоит сделать. Плюс, лог позволяет учесть, как именно были оплачены услуги, какие способом (карта/наличные и тд), когда именно. Учесть предоплату за бронирование.
Вот какие я сущности вижу:
- Гостиница
- Номер
- Группа гостей
- Гость
- Бронь (то, что связывает 1 Группу и 1..N Номеров - или 1 Группу и 1 Номер - тут есть разные варианты)
- при желании реализма, объект Оплаты (Счет? не силен в бухгалтерии)
Дальше, мы уже можем решить какие у них есть свойства, и какие между ними есть связи (отношения). Например: Группа содержит Гостей, Группа размещает Бронь, Бронь относится к 1 или нескольким Номерам, Номер содержит список относящихся к нему Броней.
Ты можешь даже попытаться нарисовать эти сущности и связи между ними (есть даже язык диаграмм UML для этого).
Вот не знаю, поможет эта статья или нет, тут упоминаются связи между классами: https://habrahabr.ru/post/150041/
И тут https://ru.wikipedia.org/wiki/Диаграмма_классов
А тут рассказывается про ER модель: https://ru.wikipedia.org/wiki/ER-модель
> private $money;
Тоже не очень понятно назначение свойства
> private function getTotalRooms($freeNumbers)
Не очень понятно, зачем эта функция вообще и что она делает.
> if ($this->getTotalRooms($this->getFreeNumbers($checkIn)) >= count($persons)) {
Это трудно читать из-за обилия скобок. Ну и тут
> foreach ($this->numbers as $key => $value) {
Лучше $numbers as $number
> public function createHotel(Number $number)
Лучше назвать addNumber
То есть у тебя не очень удачно спроектированы классы и из-за этого ты громоздишь весь код в один класс Hotel. И получается уже не совсем ООП.
> То есть мне надо сделать во всех функциях/методах проверку и если ошибка кидать исключение. и что бы грузился уже не контролер а страница ошибки.
Да. Исключение - это способ для функции сообщить о непреодолимой, неожиданной ошибке. А тот, кто ее вызвал, может, если захочет, его обработать, но это не обязательно.
> то есть исключения что бы при ошибки, приложение не работало дальше.
Да. Какой смысл продолжать выполнять код, если что-то не удалось сделать?
https://github.com/dsgaljkeguhodgiosetuhsegjposguh/studlist/blob/master/дамп для создания бд
Этот файл лучше назвать dump.sql или students.sql. Из него стоит убрать название БД (tables), чтобы он не был привязан к конкретной базе.
При оформлении SQL кода стоит придерживаться этого руководства по стилю: http://www.sqlstyle.guide/ru/
В дальнейшем тебе стоит также подумать о создании отдельной публичной папки, а сейчас у тебя по сути все файлы вывалены в общий доступ.
В репозиторий стоит добавить README с кратким описанием проекта и инструкцией по установке. Образцы (можно даже более кратко сделать):
- https://github.com/Al-faqun/Students/blob/master/README.md
- https://github.com/moroz95/StudentList/blob/master/README.md
- https://github.com/TheSidSpears/Students/blob/master/README.md
- https://github.com/foobar1643/student-list/blob/master/README.md
(если нажать Raw то можно увидеть исходный текст с разметкой)
- мнение про то, как писать: http://qaru.site/questions/19638/how-to-write-a-good-readme
(я тут вообще попробовал сделать поиск и немного удивился от наличия нескольких десятков решений задачи).
https://github.com/dsgaljkeguhodgiosetuhsegjposguh/studlist/blob/master/src/CheckForm/CheckForm.php
> preg_match('/[a-zA-Z1-90]{6,32}/iu',
нет привязки к краям строки (^$), также, для пароля стоит разрешить использовать разные символы.
> [а-яА-Яa]{2,32}
Буква ё в Юникоде идет отдельно от алфавита (не входит в а-я) и ее надо указать отдельно.
> class CheckForm
> const REG_FORM_SEX_MAN = "Мужской";
Эту константу уместнее поместить в студента, а не в проверяльщик формы. Также, в БД лучше сделать для ENUM значения латинницей, так как они просто обозначают пол, но обычно не используются для вывода.
Сообщения об ошибках, конечно, лучше делать более понятные.
> (!preg_match('/[1990-9]{4}/iu'
Неправильная регулярка. [1990-9] значит "одна любая цифра" и равносильно [0-9]. [1990] значит "одна любая из цифр 0, 1 или 9".
Методы checkRegForm() и checkProfileInfo() содержат много одинакового кода. Копипаста кода - это зло. Потому что изучать такой код в 2 раза дольше, править в 2 раза дольше.
https://github.com/dsgaljkeguhodgiosetuhsegjposguh/studlist/blob/master/src/Student/Student.php
Функции setStudent и updateStudentInfo можно объединить в одну, которая принимает массив и обновляет присутствующие в нем поля.
Папку лучше назвать не Student, а Entity или Model.
https://github.com/dsgaljkeguhodgiosetuhsegjposguh/studlist/blob/master/src/DbConnect/DbConnect.php
Этот класс не очень-то и нужен, тебе ведь никто не запрещает просто создать PDO через new.
Ну и сам способ использования класса очень странный:
> $dbConnect = new DbConnect;
> $db = $dbConnect->connect;
Тебе не кажется, что это было бы проще записать так:
$db = connectToDb();
$db = DbConnector::connect();
$db = $dbConnector->connect();
$db = new PDO(...);
То есть, возвращать результат через return а не через записть в свойство?
> }catch (PDOException $e) {
> throw new Exception("Database connection error");
не очень понятен смысл catch. Зачем менять тип исключения с конкретного на более общее?
https://github.com/dsgaljkeguhodgiosetuhsegjposguh/studlist/blob/master/src/UsersTableGateway/UsersTableGateway.php
Тут стоит попробовать применить Dependency Injection: https://github.com/codedokode/pasta/blob/master/arch/di.md
> public function checkEmail($email)
Лучше назвать getEmailUsageCount(), а еще лучше сделать функцию isEmailUsed/isEmailUnique.
То же относится к checkLogin.
> public function addToken($login, $token)
лучше updateToken, или setTokenForLogin.
https://github.com/dsgaljkeguhodgiosetuhsegjposguh/studlist/blob/master/src/Table/Table.php
Это странный класс. Почему он с маленькой буквы? почему назывется table? Это ведь параметры отображения таблицы. Логичнее назвать TableViewParameters или TableParameters, или или TableFilter или ViewFilter. И убрать оттуда работу с БД, работу с GET. Взамен можно добавить ключевое слово.
> $this->countStudents = $this->db->getStudentsCount()['COUNT(*)'];
Это странный код, что мешает из функции getStudentsCount возвращать сразу число? Почему такой странный тип результата функции?
Также, ты не должен для каждого класса создавать по папке. Некоторые можно класть просто в корень, если их мало.
> public function SearchStudents($search, table $table)
Здесь проблема в том, что ты возвращаешь "неполноценные" объекты Student, у которых не заполнена часть полей. Это усложняет код, так как в нем где-то гуляют полностью заполненные объекты, а где-то нет и различить их невозможно. Получив такой объект, ты не знаешь - у студента пустое название группы или оно просто не загружено. Если ты хочешь вернуть только 4 поля, надо использовать массив или отдельный объект. Но лучше бы вернуть полноценных студентов.
https://github.com/dsgaljkeguhodgiosetuhsegjposguh/studlist/blob/master/controllers/Router/Router.php
лучше анализировать только path из URL, без query string, тогда проверка может быть очень простая, в стиле if ($path == '/list').
> $title = 'Таблица';
> $body = 'view/table.phtml';
> require_once "controllers/table.php";
> require_once 'view/headers.phtml';
Вообще, это наверно задача контроллера - определять название страницы и какой используется шаблон. А не роутера.
Вместо exit лучше бы поставить return.
> Меняю имя страницы.и гружу шапку не знаю куда еще затолкать
В соответствующий контроллер.
У тебя есть автозагрузчик, так что в роутере логичнее писать if (class_exists()).
> $title = 'error';
> $body = "view/error404.phtml";
> exit;
Это ничего не выведет.
> header('location: http://localhost:8081/login');
Тут зря ты прописал домен и порт, как перенести код на другой домен?
https://github.com/dsgaljkeguhodgiosetuhsegjposguh/studlist/blob/master/controllers/reg.php
> 'email' => trim(htmlspecialchars($_POST['email'],ENT_QUOTES)),
> 'password' => trim(htmlspecialchars($_POST['password'],ENT_QUOTES)),
> 'name' => trim(htmlspecialchars($_POST['name'],ENT_QUOTES)),
тут можно применить цикл вместо копипасты.
Контроллеры profile и reg наверно можно объединить?
> То есть мне надо сделать во всех функциях/методах проверку и если ошибка кидать исключение. и что бы грузился уже не контролер а страница ошибки.
Да. Исключение - это способ для функции сообщить о непреодолимой, неожиданной ошибке. А тот, кто ее вызвал, может, если захочет, его обработать, но это не обязательно.
> то есть исключения что бы при ошибки, приложение не работало дальше.
Да. Какой смысл продолжать выполнять код, если что-то не удалось сделать?
https://github.com/dsgaljkeguhodgiosetuhsegjposguh/studlist/blob/master/дамп для создания бд
Этот файл лучше назвать dump.sql или students.sql. Из него стоит убрать название БД (tables), чтобы он не был привязан к конкретной базе.
При оформлении SQL кода стоит придерживаться этого руководства по стилю: http://www.sqlstyle.guide/ru/
В дальнейшем тебе стоит также подумать о создании отдельной публичной папки, а сейчас у тебя по сути все файлы вывалены в общий доступ.
В репозиторий стоит добавить README с кратким описанием проекта и инструкцией по установке. Образцы (можно даже более кратко сделать):
- https://github.com/Al-faqun/Students/blob/master/README.md
- https://github.com/moroz95/StudentList/blob/master/README.md
- https://github.com/TheSidSpears/Students/blob/master/README.md
- https://github.com/foobar1643/student-list/blob/master/README.md
(если нажать Raw то можно увидеть исходный текст с разметкой)
- мнение про то, как писать: http://qaru.site/questions/19638/how-to-write-a-good-readme
(я тут вообще попробовал сделать поиск и немного удивился от наличия нескольких десятков решений задачи).
https://github.com/dsgaljkeguhodgiosetuhsegjposguh/studlist/blob/master/src/CheckForm/CheckForm.php
> preg_match('/[a-zA-Z1-90]{6,32}/iu',
нет привязки к краям строки (^$), также, для пароля стоит разрешить использовать разные символы.
> [а-яА-Яa]{2,32}
Буква ё в Юникоде идет отдельно от алфавита (не входит в а-я) и ее надо указать отдельно.
> class CheckForm
> const REG_FORM_SEX_MAN = "Мужской";
Эту константу уместнее поместить в студента, а не в проверяльщик формы. Также, в БД лучше сделать для ENUM значения латинницей, так как они просто обозначают пол, но обычно не используются для вывода.
Сообщения об ошибках, конечно, лучше делать более понятные.
> (!preg_match('/[1990-9]{4}/iu'
Неправильная регулярка. [1990-9] значит "одна любая цифра" и равносильно [0-9]. [1990] значит "одна любая из цифр 0, 1 или 9".
Методы checkRegForm() и checkProfileInfo() содержат много одинакового кода. Копипаста кода - это зло. Потому что изучать такой код в 2 раза дольше, править в 2 раза дольше.
https://github.com/dsgaljkeguhodgiosetuhsegjposguh/studlist/blob/master/src/Student/Student.php
Функции setStudent и updateStudentInfo можно объединить в одну, которая принимает массив и обновляет присутствующие в нем поля.
Папку лучше назвать не Student, а Entity или Model.
https://github.com/dsgaljkeguhodgiosetuhsegjposguh/studlist/blob/master/src/DbConnect/DbConnect.php
Этот класс не очень-то и нужен, тебе ведь никто не запрещает просто создать PDO через new.
Ну и сам способ использования класса очень странный:
> $dbConnect = new DbConnect;
> $db = $dbConnect->connect;
Тебе не кажется, что это было бы проще записать так:
$db = connectToDb();
$db = DbConnector::connect();
$db = $dbConnector->connect();
$db = new PDO(...);
То есть, возвращать результат через return а не через записть в свойство?
> }catch (PDOException $e) {
> throw new Exception("Database connection error");
не очень понятен смысл catch. Зачем менять тип исключения с конкретного на более общее?
https://github.com/dsgaljkeguhodgiosetuhsegjposguh/studlist/blob/master/src/UsersTableGateway/UsersTableGateway.php
Тут стоит попробовать применить Dependency Injection: https://github.com/codedokode/pasta/blob/master/arch/di.md
> public function checkEmail($email)
Лучше назвать getEmailUsageCount(), а еще лучше сделать функцию isEmailUsed/isEmailUnique.
То же относится к checkLogin.
> public function addToken($login, $token)
лучше updateToken, или setTokenForLogin.
https://github.com/dsgaljkeguhodgiosetuhsegjposguh/studlist/blob/master/src/Table/Table.php
Это странный класс. Почему он с маленькой буквы? почему назывется table? Это ведь параметры отображения таблицы. Логичнее назвать TableViewParameters или TableParameters, или или TableFilter или ViewFilter. И убрать оттуда работу с БД, работу с GET. Взамен можно добавить ключевое слово.
> $this->countStudents = $this->db->getStudentsCount()['COUNT(*)'];
Это странный код, что мешает из функции getStudentsCount возвращать сразу число? Почему такой странный тип результата функции?
Также, ты не должен для каждого класса создавать по папке. Некоторые можно класть просто в корень, если их мало.
> public function SearchStudents($search, table $table)
Здесь проблема в том, что ты возвращаешь "неполноценные" объекты Student, у которых не заполнена часть полей. Это усложняет код, так как в нем где-то гуляют полностью заполненные объекты, а где-то нет и различить их невозможно. Получив такой объект, ты не знаешь - у студента пустое название группы или оно просто не загружено. Если ты хочешь вернуть только 4 поля, надо использовать массив или отдельный объект. Но лучше бы вернуть полноценных студентов.
https://github.com/dsgaljkeguhodgiosetuhsegjposguh/studlist/blob/master/controllers/Router/Router.php
лучше анализировать только path из URL, без query string, тогда проверка может быть очень простая, в стиле if ($path == '/list').
> $title = 'Таблица';
> $body = 'view/table.phtml';
> require_once "controllers/table.php";
> require_once 'view/headers.phtml';
Вообще, это наверно задача контроллера - определять название страницы и какой используется шаблон. А не роутера.
Вместо exit лучше бы поставить return.
> Меняю имя страницы.и гружу шапку не знаю куда еще затолкать
В соответствующий контроллер.
У тебя есть автозагрузчик, так что в роутере логичнее писать if (class_exists()).
> $title = 'error';
> $body = "view/error404.phtml";
> exit;
Это ничего не выведет.
> header('location: http://localhost:8081/login');
Тут зря ты прописал домен и порт, как перенести код на другой домен?
https://github.com/dsgaljkeguhodgiosetuhsegjposguh/studlist/blob/master/controllers/reg.php
> 'email' => trim(htmlspecialchars($_POST['email'],ENT_QUOTES)),
> 'password' => trim(htmlspecialchars($_POST['password'],ENT_QUOTES)),
> 'name' => trim(htmlspecialchars($_POST['name'],ENT_QUOTES)),
тут можно применить цикл вместо копипасты.
Контроллеры profile и reg наверно можно объединить?
json_encode возвращает null при некорреткных входных данных, это описано в мануале. Нужно проверять и выводить ошибку в таком случае.
>>1104397
Институтов, где тебя реально будут чему-то учить, очень мало, в основном известные ВУЗы в крупных городах. Плюс, есть программы сотрудничества с вузами у Yandex/mail.ru:
https://it.mail.ru/promo/full-time-learning/
https://it.mail.ru/promo/online-learning/
https://academy.yandex.ru/
ИТМО вроде хороший ВУЗ: http://www.ifmo.ru/ru/ - но и то он не только про IT. Вообще, если ты хочешь просто быть средним программистом, тебе ВУЗ не нужен (по идее это в техникуме должны изучать, но не знаю, изучают ли). ВУЗ по идее учит каким-то более сложным вещам, связанным с серьезной математикой, наукой, и тд. Уж точно там не должны учить, как двигать менюшки на сайте.
Но если ты не ищешь простых путей, и хочешь делать что-то сложное, чем сайты (пусть даже и хорошие) то может быть и есть смысл попробовать поступить в какой-нибудь ВУЗ получше. Если такая возможность есть, наверно не стоит от нее отказываться.
Посмотри для начала рейтитнги ВУЗов вроде таких (первое, что нашел):
https://students.superjob.ru/reiting-vuzov/it/
Или посмотри, кто выигрывает олимпиады ACM:
http://finals.snarknews.info/
https://icpc.baylor.edu/worldfinals/results
https://ru.wikipedia.org/wiki/Международная_студенческая_олимпиада_по_программированию#Победители
Потом посмотри сайты этих вузов, что там изучают, какие у них есть достижения. Потом сходи на день открытых дверей.
Ну и конечно, обучение в таком ВУЗе предполагает большую нагрузку. Чтобы доказать, что ты сможешь с ней справиться, ты должен получить высокий балл на вступительных экзаменах (сколько именно, написано на сайте).
Есть статьи на хабре вроде таких: https://habrahabr.ru/post/179891/
>>1104309
Подумаем как-нибудь потом об исправлении бага.
>>1104281
> запрещает скачивание .exe, .msi и так далее.
Наверняка есть сторонние программы-скачивальщики, лишенные этих ограничеий?
json_encode возвращает null при некорреткных входных данных, это описано в мануале. Нужно проверять и выводить ошибку в таком случае.
>>1104397
Институтов, где тебя реально будут чему-то учить, очень мало, в основном известные ВУЗы в крупных городах. Плюс, есть программы сотрудничества с вузами у Yandex/mail.ru:
https://it.mail.ru/promo/full-time-learning/
https://it.mail.ru/promo/online-learning/
https://academy.yandex.ru/
ИТМО вроде хороший ВУЗ: http://www.ifmo.ru/ru/ - но и то он не только про IT. Вообще, если ты хочешь просто быть средним программистом, тебе ВУЗ не нужен (по идее это в техникуме должны изучать, но не знаю, изучают ли). ВУЗ по идее учит каким-то более сложным вещам, связанным с серьезной математикой, наукой, и тд. Уж точно там не должны учить, как двигать менюшки на сайте.
Но если ты не ищешь простых путей, и хочешь делать что-то сложное, чем сайты (пусть даже и хорошие) то может быть и есть смысл попробовать поступить в какой-нибудь ВУЗ получше. Если такая возможность есть, наверно не стоит от нее отказываться.
Посмотри для начала рейтитнги ВУЗов вроде таких (первое, что нашел):
https://students.superjob.ru/reiting-vuzov/it/
Или посмотри, кто выигрывает олимпиады ACM:
http://finals.snarknews.info/
https://icpc.baylor.edu/worldfinals/results
https://ru.wikipedia.org/wiki/Международная_студенческая_олимпиада_по_программированию#Победители
Потом посмотри сайты этих вузов, что там изучают, какие у них есть достижения. Потом сходи на день открытых дверей.
Ну и конечно, обучение в таком ВУЗе предполагает большую нагрузку. Чтобы доказать, что ты сможешь с ней справиться, ты должен получить высокий балл на вступительных экзаменах (сколько именно, написано на сайте).
Есть статьи на хабре вроде таких: https://habrahabr.ru/post/179891/
>>1104309
Подумаем как-нибудь потом об исправлении бага.
>>1104281
> запрещает скачивание .exe, .msi и так далее.
Наверняка есть сторонние программы-скачивальщики, лишенные этих ограничеий?
Проверь, плиз
# Имя сервера которое обслуживает этот VirtualHost
ServerName example.com
# Корневая папка сервера
DocumentRoot /var/www/example.com/public
# ....
у меня сервер начинает падать, когда прописываю
<VirtualHost :80>
что делать?
Разве не <VirtualHost *:80> нужно писать? Попробуй
>>Почему дата - это свойство отеля? Что-то я не понимаю, где тут логика. дата заезда - это свойство заявки на размещение.
Это дата на сегодня.
>>Насчет свойства logs - не логичнее ли историю заселения в номер хранить в самом номере? А то у тебя есть там только expireDate, который не отражает историю заселения. Ну и он не позволяет учесть ситуацию, что номер может быть забронирован в будушем с числа X по число Y.
В logs хранится дата заселения, дата выписывания, сам объект номера и еще персона. Как мне показалось эта исчерпывающая информация. Правда вероятно подсчет прибыли будет запутанный. Но я же учусь проектировать.
>>- Бронь (то, что связывает 1 Группу и 1..N Номеров - или 1 Группу и 1 Номер - тут есть разные варианты)
По сути это у меня класс logs.
>> private $money;
Тоже не очень понятно назначение свойства
Сюда хотел по итогу дня складывать выручку.
>> private function getTotalRooms($freeNumbers)
Не очень понятно, зачем эта функция вообще и что она делает.
Возвращает колличество свободных комнат, не номеров, а конкретно комнат, для того чтобы понимать можно ли заселить группу.
В любом случае спасибо большое за ревью. Буду переделывать. Сам понимаю что, что-то перезамудрил, когда начал реализовывать методы. Я так понимаю, что когда сложно делать реализацию эта в первую очередь проблема проектирования.
https://ideone.com/tPp46M
Вот такой отрывок, мне нужно из условия с isset(_$GET) получить информацию, обработать и получить ответ в виде post, и в условии с isset($_POST) для обработки результатов мне нужна переменная из get, как ее оттуда достать? Подскажите пожалуйста, с сессией не получается. Спасибо заранее.
Все работает, это я дурак, сорян за беспокойство.
Ты разбираешься как работают POST и GET запросы?
Какая-то у тебя конструкция адовая.
Я бы реализовал так. Приходит GET запрос, формируется страница с тестом исходя из $_GET["testid"]. На странице с тестом есть форма в которой прописан method POST и например указан action скрипт_обработки_POST_запроса.php . На этой же странице c сформированным тестом можно в скрытое поле складывать $_GET["testid"]. Потом обрабатываешь POST в скрипт_обработки_POST_запроса.php и выдаешь результат.
Относительно хранения временных данных, можно использовать COOKIE или LocalStorage если ты можешь в JavaScript.
Более-менее разбираюсь, но я же еще учусь.
То что я налепил выше - работает, просто я сессии вписал, а страницу не обновил (точнее жал при обновлении повторить отправку данных), то есть из гета в $_SESSION ничего не было передано.
Что криво и на костылях - я не сомневаюсь, даже на своем уровне я мог бы сделать лучше, недавно шаблонизацию покурил немножко и родил свой первый шаблонизатор (чуть не помер).
Тут просили в рамках одной страницы сделать отображение тестов и обработку.
> The Google codebase includes approximately one billion files and has a history of approximately 35 million commits spanning Google's entire 18-year existence. The repository contains 86TB of data, including approximately two billion lines of code in nine million unique source files.
> In 2014, approximately 15 million lines of code were changedb in approximately 250,000 files in the Google repository on a weekly basis. The Linux kernel is a prominent example of a large open source software repository containing approximately 15 million lines of code in 40,000 files.
Ну и раз речь зашла про большие репозитории, то можно еще почитать про перенос репозитория кода Windows на Git:
https://habrahabr.ru/company/everydaytools/blog/329878/ (рус)
https://blogs.msdn.microsoft.com/bharry/2017/05/24/the-largest-git-repo-on-the-planet/ (англ)
> кодовая база Windows состоит из 3.5 миллионов файлов; когда заливаешь ее на Git, получается репозиторий размером где-то в 300 гигабайт.
>Программа обнаруживает только слова, где в русское слово вставлена латинница, а хорошо бы еще обнаруживать и исправлять случаи, когда в латинское слово вставлена кириллица.
Хорошо, попробую сделать и это.
https://ideone.com/JTdyXo - посмотри ещё задачу с исправлением ошибок.
У тебя там в коде функция, для изменения регистра первой буквы предложения написана одной строчкой, но я так и не понял как это сделать, поэтому вставил код который загуглил. Есть uсfirst() ещё, но он не работает с многобайтной кодировкой.
Все что гуглю выдает либо старье, либо верстка/пхп и прочие вещи.
Интересует какой-то полный развернутый курс по всей этой кухне: настройка линупса как сервера, работа через терминал (ssh), настройка нгинксов и прочих апачей и чтобы все на русском было
ясен хер, тебе выпадают курсы по верстке. "вебмастеринг" - это ублюдское понятие из начала 2000-х, которое и означает верстку.
ты-то спрашиваешь про администрирование сервера. это достаточно специализированная тема, по ней не может быть курса типа "мой первый сайт за час!", т.к. тот, кому нужны такие курсы, заливает сайты на хостинг, где уже все настроено. а ты изволь по отдельности по каждой технологии прочитать мануал лол.
по твоим задачам все просто: линукс, если это дебиан, работает из коробки. установить апач - sudo apt install apache2. настраивать его необязательно, т.к. по http://localhost он будет отвечать сразу же. и у ОПа есть урок по настройке апача.
Нужно изучать линукс, bash, и тд. Установить себе линукс либо в виртуалку, либо на свою машину. Для виртуалки могу посоветовать Debian Testing либо Ubuntu Server (Не desktop).
Придется немного помучиться, чтобы сделать доступ виртуалки к интернету и доступ с хоста по ssh:
- https://www.google.ru/search?q=настройка+доступа+к+ssh+с+хоста+virtualbox&newwindow=1&dcr=0&gbv=1&sei=6q8uWvi2HuGg6AS2i6PQAQ
- https://gist.github.com/codedokode/420c8c12a1edae25f0ec
Без этого придется работать с виртуалкой через ее экран, что не очень удобно.
У меня в Оп посте есть гайд про самые основы использования командной строки, в том числе под линуксом.
То есть гуглить надо "учебник по линукс", и желательно поновее.
Затем, освоив основы линукс, ты можешь погуглить документацию по Апачу и другим программам, раздел Install and configure, он обычно на английском.
sq3 - просто текст запрса
number - число строк.
И, всё же, моя лабораторная предполагает именно вот это вот всё с функциональным стилем, а не PDO. Мне бы конкретно тот код переделать под mysqli или хотя бы найти альтернативу для вывода всех таблиц неизвестной БД
Что значит "предполагает"? В требованиях написано использовать устаревшее расширение mysql? Ставь тогда старую версию PHP.
От того, что ты будешь использовать PDO, твой код не станет ООП. Он будет таким же процедурным.
Если тебе принципиально использовать mysqli, то используй: http://php.net/manual/ru/mysqli.quickstart.php
да, в ходе работы указано именно mysql, но в университете так же стоит новый PHP и, я предполагаю, преподу просто лень было переписывать свой же сборник лаб. Потому он сказал "ну, вы посмотрите и поправьте под mysqli".
>будешь использовать PDO
Да? Когда я открыл руководство мне в ебало полетели всякие мерзкие сишные -> и ::. И я закрыл, не вчитываясь. Значит, там есть функциональная версия? Как и в mysqli?
>Если тебе принципиально использовать mysqli
Я прочитал. Но в качестве альтрнативы функциям типа mysql_tablename там указаны SQL запросы. Которые возвращают странный объект. А раньше функция возвращала массив, с которым, собственно, работал код скинутый выше. Вопрос изначально и заключался в том, как вообще этим пользоваться для поставленной задачи.
>Значит, там есть функциональная версия?
там нет функциональной версии. я подозреваю, ОП имел в виду, что от того, что ты вставишь два класса в свой код, он от этого не станет ООП, т.к. ООП предполагает осмысленную реализацию определенных парадигм.
ты лучше подумай, что ты приобретешь, выполняя ненужные в реальной жизни задания для препода, которому лень обновить под "новый" php (ООП используется в нем как основная методология уже лет 5 как минимум, т.е. с 5.3).
я не особый знаток функционального программирования (это вопрос к тем, кто знает хаскель там), но то, что обычно называют функциональным программированием в php те, кому лень учить ООП - это скорее надо называть простыней из кода.
>что ты приобретешь, выполняя ненужные в реальной жизни задания для препода
Диплом. А так я вообще джаву предпочитаю или питончик, там. Я не против ООП, мне просто надо сдать лабораторную. Очевидно, в том виде, в котором её хочет видеть преподаватель.
Но я не могу, потому, что коды к старой версии не работают, а альтернатива, которую он разрешил использовать, не возвращает массив. Что мне вообще делать с объектом, который возвращает sql запрос?
ну современный пхп не то чтобы глобально отличается от джавы или питона (понятно, что отличия есть).
>Что мне вообще делать с объектом, который возвращает sql запрос?
так без кода сложно говорить. смотря что за объект. по идее у него должны быть методы, которые занимаются формированием массива. вот например в пдо есть метод fetch для объекта PDOStatement https://secure.php.net/manual/en/pdostatement.fetch.php и там можно поставить флаг FETCH_ASSOC, который тебе сформирует массив с ключом и значением.
лучше покажи код, где что-то не возвращает массив, который ты ожидаешь (и укажи версию пхп, где все крутится).
да, кстати
>Диплом
диплом - это хорошая штука, не буду спорить. просто сейчас я задумался, что про образование и диплом у меня вообще ни разу не спрашивали на собеседованиях (даже если в вакансии было написано что он обязателен).
по поводу джавы. если любишь джаву, то в джаве есть jdbc https://en.wikipedia.org/wiki/Java_Database_Connectivity и они с PDO внезапно очень похожи.
Новичок-кун
Новичок - кун
>вообще ни разу не спрашивали
А вдруг меня спросят? Да и вообще, третий курс уже. Бакалавриат-то закончить надо, не долго осталось.
>если любишь джаву, то в джаве есть
Это всё очень здорово, очень. И, наверное, я даже почитаю вскоре. Но лабораторная то по PHP.
Самообразование - это здорово (нет хотя и необходимо) и я, хм, образовываюсь. Но, во-первых, не в сторону PHP (Да не обидит это никого в треде, вам же меньше конкуренции), а во-вторых, конкретно этот вопрос мне нужно решить именно через mysqli, именно в таком виде и всё такое. Как будто тренировка перед безумным заказчиком.
И я попросил помощи, как раз потому, что на PHP.net не нашёл объяснения тому, что за объект и как из него получить массив или, хотя бы, строку. Очень жаль, что как-то не нашлось людей которые смогли бы с этим помочь.
>>1106603
Почему бы не воспользоваться готовыми решениями, типа Denwer худший, наверное, вариант или любой другой сборкой? Вот, например, небольшой их разбор.
https://habrahabr.ru/post/144242/
боюсь, быстрее установить сборку (благо, даже денвер устанавливается в пару кликов и ввода буквы Y), чем дождаться ответа\разобраться с тем, что ты сделал сам.
Впрочем, наверное, если ты разберёшься, ты получишь куда больше знаний, чем просто используя, да.
вот блядь. хз теперь, мб все нахер снести и поставить open server
может и спросят, конечно.
>Очень жаль, что как-то не нашлось людей которые смогли бы с этим помочь
скинь вар дамп объекта, чтобы хотя бы понять, это какой-то внутренний объект пхп или самодельный.
так без кода можно привести объект к массиву либо с помощью реализации у класса этого объекта интерфейса ArrayAccess, либо по-простому миллион вариантов, например вот тут: https://stackoverflow.com/questions/4345554/convert-php-object-to-associative-array
Хотел еще узнать, насколько хорошо надо знать html, css, js, чтобы понять, что готов писать back-end?
Новичок - кун.
если хочешь заниматься только бэкендом, то, в теории, можно вообще не знать. но на практике лучше знать основы, чтобы что-то тестировать (отправлять формы или смотреть xhr-запросы, например).
Вот хорошая статья по установке апача, пыха и прочего https://hackware.ru/?p=21 В итоге это удобнее чем какой-нибудь xampp. Апач всегда запущен, не надо никаких прог запускать для этого. Когда выходит новая версия php, по этой же инструкции и обновляешься хоть сразу же, а не ждёшь пока разработчики xampp сделают поддержку в своём продукте. Да и опыт полезный, на собеседовании плюсик будет
ОП, ты вот пишешь комментарии к задачам в самом треде. А я тут узнал, что можно комментировать код на github-e, если сделать pull-request. Почему бы не воспользоваться данным методом, ведь это, как мне кажется, удобнее?
По такой статье и устанавливал, только по видяшке с юттабчика. Челик не вставил в описание 6. Установка и настройка phpMyAdmin файла. Вот где я проебался( Но я нетерпелив и уже снес нафиг и скачал Open server. Но это был отличный опыт, на собеседование на типичные ошибки отвечу
А сам бэкенд это что? Работа на стороне сервера или создание динамичных сайтов, форм добавления статей итд. На бекенде же много работы, скажем, если я сделаю что-то вроде hdrezka.ru?
новичок-кун
2. Где-то слышал про codeacademy. Стоит пробовать или неоч? Есть опыт с этим сайтом?
preg-replace(' ','',$string);
Что такое фронт- и бекэнд ты сможешь нагуглить. Уметь гуглить - очень полезный навык для программиста ^_^
Как можно это исправить?
У тебя action формы должен быть отличным от той страницы, на которой эта форма располагается. Это прям маст-хев правило такое. Где-то у ОПа в статьях это было описано.
Ты можешь сделать action="register.php", на ней будет происходить обработка и валидация формы и в конце она будет редиректить обратно на index.php, опционально с GET-параметром status.
Не понимаю, как это сделать. Нашёл пока только такой пример:Шарик под баклофеном курсором https://codepen.io/cleric/pen/dIuFj?editors=1111
Но пока не понял, как его адаптировать под мою цель.
Понял. Спасибо большое
ты можешь определить в стилях положения которые тебе нужны и просто менять класс у див используя ЖаваСкрипт.
https://ideone.com/oxgLUi - пиздец я тут с йода-стайлом наговнокодил, подскажите немного как и что исправить.
Cука /[a-zA-Z0-9\.\-_%]+/ срабатывает и на цифирьки, и на букивки, а надо чтобы только на букивки с цифирьками вместе. Где я объебался?
У нас есть как раз такая задача и советы по её решению https://github.com/codedokode/pasta/blob/master/html/html.md#Задание-12
Причём её решение делается без подключения JS.
>Cука /[a-zA-Z0-9\.\-_%]+/ срабатывает и на цифирьки, и на букивки, а надо чтобы только на букивки с цифирьками вместе.
А можно по понятнее? И примеры хорошо бы.
Наверно что-то такое должно получиться, если я правильно понимаю https://regex101.com/r/qfD5Da/1
Анон, ты гений, я с этой хренью сидел сегодня почти весь день и нихрена не получилось. Спасибо!
В одном файле:
setcookie('name', 1, time () + 200, "/");
Дальше идет переадрессация через форму в другой файл
if(isset($_COOKIE['name'])){
echo "it works!";
}
var_dump($_COOKIE);
и в ответ array(0) { }
Есть навбар, в него хочу запихнуть картинки.
Как задать отступ именно на размер навбара? В еденицах не устраивает, т.к. картинки могут быть разных размеров.
в предыдущем вообще под 1000 было, так что все ок
Ребят, подскажите! Почему этот код работает:
$true = isset($_COOKIE['notification']);
// if(isset($_COOKIE['notificaton'])){
if($true){
echo '<div class="notification">' . $_COOKIE['notification'] . '</div>';
setcookie('notification', '', time() - 1);
}
А этот - нет:
// $true = isset($_COOKIE['notification']);
if(isset($_COOKIE['notificaton'])){
// if($true){
echo '<div class="notification">' . $_COOKIE['notification'] . '</div>';
setcookie('notification', '', time() - 1);
}
?
Что самое смешное, if(!isset($_COOKIE['notificaton'])) во втором примере работает! Хотя isset при существующих куках же должен true возвращать?
PHP 7.1.12, Apache/2.4.29
>echo '<div class="notification">' . $_COOKIE['notification'] . '</div>';
>
посмотри таблицу https://secure.php.net/manual/en/types.comparisons.php
isset равен true для в т.ч. значений 0, '', и других.
а при приведении 0 к булеану (что происходит в условии), он становится false и оно не выполняется.
и про приведение типов почитай https://secure.php.net/manual/ru/language.types.type-juggling.php
в твоем случае можно использовать !empty вместо isset
алсо, называть переменную $true - плохая идея, т.к. насилие это над мозгом других анонов. хорошую альтернативу сходу придумать не могу, т.к. такие значения (иссет что-то там) никто в доп. переменные не кладет, но даже $notificationIsSet будет лучше (хотя это тоже полное говно).
Да, там выше написали, это делаектся примерно так.
Кнопка с запоминанием состояния делается из чекбокса. Этот чекбокс можно скрыть средствами CSS и привязать к нему label, который будет реагировать на клики вместо него. В зависимости от состояния чекбокса можно менять вид кнопки, за счет CSS вроде input:checked + .class { ... }.
Аналогично, в зависимости от чекбокса можно как-то менять расположение дива, если элементы идут в таком порядке:
.checkbox1
.checkbox2
.checkbox3
.some-div
То мы можем писать правила вроде .checkbox1:checked ~ .some-div { ... }.
Ну и конечно остается еще вариант использовать яваскрипт.
>>1107090
Я не очень понял, о чем речь, потому придется угадывать, либо тебе надо описать проблему нормально.
Навбар закреплен с помощью position: fixed, имеет неизвестную высоту и надо сделать на body соответствующий ему отступ? Наверно, только JS может помочь. Либо отказ от fixed.
>>1107124
Я же написал, что разберемся хотя бы с частью вопросов и сделаем. Ничего страшного, что мы немного повисим на второй-третьей странице.
>>1107148
Зачем гадать. Попробуй сделать var_dump($true); var_dump($_COOKIE); var_dump(isset(...)); в обоих случаях.
Да, там выше написали, это делаектся примерно так.
Кнопка с запоминанием состояния делается из чекбокса. Этот чекбокс можно скрыть средствами CSS и привязать к нему label, который будет реагировать на клики вместо него. В зависимости от состояния чекбокса можно менять вид кнопки, за счет CSS вроде input:checked + .class { ... }.
Аналогично, в зависимости от чекбокса можно как-то менять расположение дива, если элементы идут в таком порядке:
.checkbox1
.checkbox2
.checkbox3
.some-div
То мы можем писать правила вроде .checkbox1:checked ~ .some-div { ... }.
Ну и конечно остается еще вариант использовать яваскрипт.
>>1107090
Я не очень понял, о чем речь, потому придется угадывать, либо тебе надо описать проблему нормально.
Навбар закреплен с помощью position: fixed, имеет неизвестную высоту и надо сделать на body соответствующий ему отступ? Наверно, только JS может помочь. Либо отказ от fixed.
>>1107124
Я же написал, что разберемся хотя бы с частью вопросов и сделаем. Ничего страшного, что мы немного повисим на второй-третьей странице.
>>1107148
Зачем гадать. Попробуй сделать var_dump($true); var_dump($_COOKIE); var_dump(isset(...)); в обоих случаях.
Стоит открыть средства разработчика (Ctrl + Shift + I), вкладку Network, и перезагрузить страницу. На вкладке посмотреть заголовки ответа Set-Cookie. Потом посмотреть вкладку Resources, где показываются куки, и посмотреть параметры куки.
>>1107003
Я бы советовал улучшить код:
- вместо обработчика на каждую зеленую кнопку поставить 1 обработчик на родительский элемент через $(...).on(...).
- чтобы не прописывать в CSS отступ сверху в пикселях, что неудобно, можно либо измерять эту отступ яваскрптом, либо обернуть кнопки в обертку и перемещать элемент внутрь этой обертки, чтобы его расположение справа от кнопки получалось само собой
>>1107072
Изучай DOM, затем jQuery и получится. В ОП посте есть задачки в помощь, ну а мануал по jQuery легко гуглится.
>>1106957
Незачем код разбиения текста на предложения копипастить 2 раза. Копипаста - зло, раздувает объем кода, его становится должше читать.
Функцию makeFirstletterUppercase лучше сделать так, чтобы она работала только для одного слова или предложения, и вызывать ее изнутри цикла для каждого предлложения.
> foreach ($splitText as $splits) {
Лучше $sentences as $sentence.
> $clearText = preg_replace("/[,;]/u", "", $splits);
Здесь незачем создавать новую переменную.
> $replace = preg_replace("/\s([.]{1})\s/u", "$1 ", $port);
Вместо того, чтобы костылями убирать пробел перед точкой, лучше эту точку не класть отдельным элементов в массив, а приклеить в конец предложения.
> array_push($yodaText, $result);
$yodaText[] = $result;
Стоит открыть средства разработчика (Ctrl + Shift + I), вкладку Network, и перезагрузить страницу. На вкладке посмотреть заголовки ответа Set-Cookie. Потом посмотреть вкладку Resources, где показываются куки, и посмотреть параметры куки.
>>1107003
Я бы советовал улучшить код:
- вместо обработчика на каждую зеленую кнопку поставить 1 обработчик на родительский элемент через $(...).on(...).
- чтобы не прописывать в CSS отступ сверху в пикселях, что неудобно, можно либо измерять эту отступ яваскрптом, либо обернуть кнопки в обертку и перемещать элемент внутрь этой обертки, чтобы его расположение справа от кнопки получалось само собой
>>1107072
Изучай DOM, затем jQuery и получится. В ОП посте есть задачки в помощь, ну а мануал по jQuery легко гуглится.
>>1106957
Незачем код разбиения текста на предложения копипастить 2 раза. Копипаста - зло, раздувает объем кода, его становится должше читать.
Функцию makeFirstletterUppercase лучше сделать так, чтобы она работала только для одного слова или предложения, и вызывать ее изнутри цикла для каждого предлложения.
> foreach ($splitText as $splits) {
Лучше $sentences as $sentence.
> $clearText = preg_replace("/[,;]/u", "", $splits);
Здесь незачем создавать новую переменную.
> $replace = preg_replace("/\s([.]{1})\s/u", "$1 ", $port);
Вместо того, чтобы костылями убирать пробел перед точкой, лучше эту точку не класть отдельным элементов в массив, а приклеить в конец предложения.
> array_push($yodaText, $result);
$yodaText[] = $result;
Ты все перепутал и даешь неправильный совет. Вот урок по формам https://github.com/codedokode/pasta/blob/master/forms.md
Подумай сам, как в твоем варианте при ошибке вывести форму с введенными ранее значениями?
>>1106894
> у меня страница регистраци index.php ссылается на саму себя при отправке форм
Так и должно быть.
> Все бы хорошо, но когда я обновляю страницу у меня информация повторно и повторно в базу заносится.
Нужно делать редирект после успешного заполнения формы, читай урок https://github.com/codedokode/pasta/blob/master/forms.md
>>1106761
Ну так попробуйи посмотри, это же вроде бесплатно.
> как убрать пробелы во второй и третьей строчке?
лучше всего их не добавлять туда с самого начала. Например, ты можешь сделать проверку, если текущее "слово" равно "\n", то не выводить пробел.
> for ($i = 0;$i < 4;$i++) {
Тут надо использовать foreach вместо ручного подсчета и указания числа элементов в массиве.
>>1106696
Фронт/бек - это "передняя" и "задняя" часть системы из 2 частей. Бэкенд в данном случае - серверный код, фронтенд - код, работающий в браузере.
Ты все перепутал и даешь неправильный совет. Вот урок по формам https://github.com/codedokode/pasta/blob/master/forms.md
Подумай сам, как в твоем варианте при ошибке вывести форму с введенными ранее значениями?
>>1106894
> у меня страница регистраци index.php ссылается на саму себя при отправке форм
Так и должно быть.
> Все бы хорошо, но когда я обновляю страницу у меня информация повторно и повторно в базу заносится.
Нужно делать редирект после успешного заполнения формы, читай урок https://github.com/codedokode/pasta/blob/master/forms.md
>>1106761
Ну так попробуйи посмотри, это же вроде бесплатно.
> как убрать пробелы во второй и третьей строчке?
лучше всего их не добавлять туда с самого начала. Например, ты можешь сделать проверку, если текущее "слово" равно "\n", то не выводить пробел.
> for ($i = 0;$i < 4;$i++) {
Тут надо использовать foreach вместо ручного подсчета и указания числа элементов в массиве.
>>1106696
Фронт/бек - это "передняя" и "задняя" часть системы из 2 частей. Бэкенд в данном случае - серверный код, фронтенд - код, работающий в браузере.
Да нифига не удобно. Кто будет делать pull request и куда? pull request ведь делается в существующий репозиторий снаружи.
Мне бы помогла конечно штука, которая позволяет тыкать в код и добавлять комментарии, а потом экспортировать это в текст поста. Я смотрел системы код-ревью, но они все заточены на то, что результаты отображаются у них на сайте.
>>1106644
Зря ты удалил. Надо разобраться, в чем проблема, а не убегать от нее.
>>1106607
> вам же меньше конкуренции
Ты пока не очень похож на конкурента
> на PHP.net не нашёл объяснения тому, что за объект и как из него получить массив или, хотя бы, строку
Чтобы использовать mysqli, строго желательно освоить основы ООП. Если ты хочешь писать на Java, C#, Руби, JS - знание ООП все равно понадобится.
В ОП посте есть учебник, там есть глава про ООП. Или можно взять любой другой учебник по любому языку.
Далее, имея понимание ООП, мы открываем мануал и легко находим ответ.
mysqli::query возвращает объект mysqli_result, который представляет собой ответ сервера на SQL запрос (результат запроса). Это написано тут: http://php.net/manual/ru/mysqli.query.php
Открываем мануал по mysqli_result: http://php.net/manual/ru/class.mysqli-result.php
Видим там кучу методов для извлечения данных из результата. Читаем по ним мануал и выбираем подходящий нам.
>>1106603
> на 80 выдавал ошибку.
Он занят какой-нибудь программой вроде скайпа, надо в настройках это отключить. Посмотреть кто именно занял порт, можно набрав команду netstat -abn в привилегированной консоли с правами админа. Если что, гайд по командной строке в ОП посте.
> Непонятно почему при установке и ведение логов mysql, они сохраняются в папке data в в папке mysql,а не в той, что мне надо.
А где ты прописал папку? В my.ini? А сервер MySQL перезапустил?
> И при заходе в phpmyAdmin появляется прикрил, а не сама админка.
Очевидно, там надо создать конфиг, который ты не создал.
Есть раздел в мануале: https://docs.phpmyadmin.net/en/latest/setup.html#quick-install
Там написано:
> Now you must configure your installation. ...
> Using Setup script
> Next, open your browser and visit the location where you installed phpMyAdmin, with the /setup suffix. The changes are not saved to the server, you need to use the Download button to save them to your computer and then upload to the server.
Надо выполнить то, что тут написано, то есть зайти в /setup и настроить.
Да нифига не удобно. Кто будет делать pull request и куда? pull request ведь делается в существующий репозиторий снаружи.
Мне бы помогла конечно штука, которая позволяет тыкать в код и добавлять комментарии, а потом экспортировать это в текст поста. Я смотрел системы код-ревью, но они все заточены на то, что результаты отображаются у них на сайте.
>>1106644
Зря ты удалил. Надо разобраться, в чем проблема, а не убегать от нее.
>>1106607
> вам же меньше конкуренции
Ты пока не очень похож на конкурента
> на PHP.net не нашёл объяснения тому, что за объект и как из него получить массив или, хотя бы, строку
Чтобы использовать mysqli, строго желательно освоить основы ООП. Если ты хочешь писать на Java, C#, Руби, JS - знание ООП все равно понадобится.
В ОП посте есть учебник, там есть глава про ООП. Или можно взять любой другой учебник по любому языку.
Далее, имея понимание ООП, мы открываем мануал и легко находим ответ.
mysqli::query возвращает объект mysqli_result, который представляет собой ответ сервера на SQL запрос (результат запроса). Это написано тут: http://php.net/manual/ru/mysqli.query.php
Открываем мануал по mysqli_result: http://php.net/manual/ru/class.mysqli-result.php
Видим там кучу методов для извлечения данных из результата. Читаем по ним мануал и выбираем подходящий нам.
>>1106603
> на 80 выдавал ошибку.
Он занят какой-нибудь программой вроде скайпа, надо в настройках это отключить. Посмотреть кто именно занял порт, можно набрав команду netstat -abn в привилегированной консоли с правами админа. Если что, гайд по командной строке в ОП посте.
> Непонятно почему при установке и ведение логов mysql, они сохраняются в папке data в в папке mysql,а не в той, что мне надо.
А где ты прописал папку? В my.ini? А сервер MySQL перезапустил?
> И при заходе в phpmyAdmin появляется прикрил, а не сама админка.
Очевидно, там надо создать конфиг, который ты не создал.
Есть раздел в мануале: https://docs.phpmyadmin.net/en/latest/setup.html#quick-install
Там написано:
> Now you must configure your installation. ...
> Using Setup script
> Next, open your browser and visit the location where you installed phpMyAdmin, with the /setup suffix. The changes are not saved to the server, you need to use the Download button to save them to your computer and then upload to the server.
Надо выполнить то, что тут написано, то есть зайти в /setup и настроить.
> Есть uсfirst() ещё, но он не работает с многобайтной кодировкой.
Да, не работает.
> функция, для изменения регистра первой буквы предложения
Отрезаешь первую букву с помощью mb_substr, переводишь в верхний регистр с помощью mb_strtoupper, приклеиваешь остаток строки.
> [,:]{1}
{1} тут не нужен. И \s* тоже.
> (?<=[.!?](?![.!?]))
Здесь условия незачем вкладывать друг в друга, и можно просто написать (?<=...)(?!...)
>>1106211
>>>Почему дата - это свойство отеля? Что-то я не понимаю, где тут логика. дата заезда - это свойство заявки на размещение.
> Это дата на сегодня.
Сегодняшняя дата это не свойство Гостиницы, как не крути. Свойства Гостиницы - это, например, список Номеров в ней.
>> private $money;
> Сюда хотел по итогу дня складывать выручку.
Это не очень хорошая идея, так как это свойство вычисляется из других и при добавлении каждой брони тебе надо обновлять его, чтобы в нем всегда было актуальное значение. Более того, бронь ведь может быть добавлена на будущее.
Это проще вычислять, а не хранить.
>> В logs хранится дата заселения, дата выписывания, сам объект номера и еще персона. Как мне показалось эта исчерпывающая информация. Правда вероятно подсчет прибыли будет запутанный. Но я же учусь проектировать.
С твоим подходом Номер не может ответить на вопрос, кто в нем когда проживал. Я предлагаю рассмотреть вариант, когда Номер знает, кто в нем жил/планирует жить и может предоставлять информацию о том, что он свободен или занят.
> Возвращает колличество свободных комнат, не номеров, а конкретно комнат, для того чтобы понимать можно ли заселить группу.
А, мы просто не так друг друга поняли. Обычно в англ. языке Номер называется "Room" или "Suit". Вот примеры предложений:
http://context.reverso.net/перевод/русский-английский/Трехместный+номер,
https://www.linguee.ru/русский-английский/перевод/трехместный.html
Вот видишь, как важно выбирать правильные названия полей и переменных.
> Есть uсfirst() ещё, но он не работает с многобайтной кодировкой.
Да, не работает.
> функция, для изменения регистра первой буквы предложения
Отрезаешь первую букву с помощью mb_substr, переводишь в верхний регистр с помощью mb_strtoupper, приклеиваешь остаток строки.
> [,:]{1}
{1} тут не нужен. И \s* тоже.
> (?<=[.!?](?![.!?]))
Здесь условия незачем вкладывать друг в друга, и можно просто написать (?<=...)(?!...)
>>1106211
>>>Почему дата - это свойство отеля? Что-то я не понимаю, где тут логика. дата заезда - это свойство заявки на размещение.
> Это дата на сегодня.
Сегодняшняя дата это не свойство Гостиницы, как не крути. Свойства Гостиницы - это, например, список Номеров в ней.
>> private $money;
> Сюда хотел по итогу дня складывать выручку.
Это не очень хорошая идея, так как это свойство вычисляется из других и при добавлении каждой брони тебе надо обновлять его, чтобы в нем всегда было актуальное значение. Более того, бронь ведь может быть добавлена на будущее.
Это проще вычислять, а не хранить.
>> В logs хранится дата заселения, дата выписывания, сам объект номера и еще персона. Как мне показалось эта исчерпывающая информация. Правда вероятно подсчет прибыли будет запутанный. Но я же учусь проектировать.
С твоим подходом Номер не может ответить на вопрос, кто в нем когда проживал. Я предлагаю рассмотреть вариант, когда Номер знает, кто в нем жил/планирует жить и может предоставлять информацию о том, что он свободен или занят.
> Возвращает колличество свободных комнат, не номеров, а конкретно комнат, для того чтобы понимать можно ли заселить группу.
А, мы просто не так друг друга поняли. Обычно в англ. языке Номер называется "Room" или "Suit". Вот примеры предложений:
http://context.reverso.net/перевод/русский-английский/Трехместный+номер,
https://www.linguee.ru/русский-английский/перевод/трехместный.html
Вот видишь, как важно выбирать правильные названия полей и переменных.
Вот еще про то, в чем разница между room и suit, мне стало любопытно и я погуглил: https://www.yellowpages.ca/tips/what-is-the-difference-between-a-hotel-room-and-suite/
>Наверно, только JS может помочь. Либо отказ от fixed
М-м-м. Ясно. Буду думать.
И подскажи пожалуйста еще момент, почему ссылка меняет текст и получает подчеркивание? Там же стоит text-decoration: none;
Потому что надо еще поставить то же самое для :hover. Иначе встроенное правило браузера
a:hover { ... }
Имеет более высокий приоритет.
https://webref.ru/course/css-basics/priority (псевдокласс вроде :hover имеет тот же вес, что и обычный класс)
https://habrahabr.ru/post/137588/
Спасибо.
есть вопрос, что ты думаешь по поводу этих >1099454 идей? чувак кукухой поехал или он прав?
> Мне бы помогла конечно штука, которая позволяет тыкать в код и добавлять комментарии, а потом экспортировать это в текст поста. Я смотрел системы код-ревью, но они все заточены на то, что результаты отображаются у них на сайте.
А ведь можно оказывается без всяких pull-request'ов создавать issue и в нём описывать проблему: https://github.com/TheSidSpears/test_hub/issues/2
Это ж круто, анон делает pull в мастер, просит проверить код, ты создаешь пачку issue, пишешь в тред "проверяй", анон их решает и закрывает, делает новый pull в мастер и так по кругу
Вообще, надо посмотреть, почему бы и нет.
С пулл-реквестами - они ведь вроде только из одного репозитория в другой создаются.
Ну и issue имеют те недостатки, что они все будут отдельно разбросаны и не будут видны в треде и в архиве тредов.
Плюс, я быстро печатаю, у меня даже Sublime от такой скорости набора подвисать начинает со временем, а браузер уж точно тормозить будет, я думаю. Хотя это надо еще проверить, может и не будет.
Не нашел ни ServerName example.com ни <VirtualHost *:80>, но вроде сделал и работает
Что я делаю не так? Или так? Спасибо.
Примерно так, как в розетке главное меню реализовано.
Вопрос: могу ли я в качестве аргумента использовать mysql запрос? Или как по другому загрузить в объект информацю нужную ?
'break' not in the 'loop' or 'switch' context
Вопрос решен.
Проблема в том, что если в эти десять символов до или после попадается ошибка, то preg_match_all её не находит. Как это исправить?
>А что делать, если например, произошла ошибка в БД, то тоже на 404 редирект нужен?
Должна быть ошибка 500
>И как лучше сделать страницу с ошибкой?
Ловим ошибку/исключение
https://secure.php.net/manual/ru/function.set-error-handler.php
https://secure.php.net/manual/ru/function.set-exception-handler.php
Для пользователя выводим страницу что что-то сломалось, со статусом 500
Подробности ошибки сохраняем в лог
https://secure.php.net/manual/ru/function.error-log.php
https://secure.php.net/manual/ru/book.errorfunc.php
>Если я через апач вот так сделаю: RewriteEngine On ErrorDocument 404 /404.html, то это ок?
Я не знаю
>>1107313
Обычно, конструктор используется для заполнения полей класса и для внедрения зависимостей
Прим.
class User
{
private $id;
private $login;
private $password;
//заполнение полей
public function __construct($id, $login, $password)
{
$this->id = $id;
$this->login = $login;
$this->password = $password;
}
}
class Database
{
public function addUser(User $user)
{
$query = "INSERT INTO users ...";
...
}
...
}
class Controller
{
private $database;
//внедрение зависимостей
public function __construct(Database $database)
{
$this->database = $database;
}
public function run()
{
$user = new User(...);
$this->database->addUser($user);
}
}
>могу ли я в качестве аргумента использовать mysql запрос?
В доктрине есть метод принимающий sql-запрос в качестве аргумента. Такой паттерн, вроде, называется Query Builder, но я не уверен насчет этого.
>Или как по другому загрузить в объект информацю нужную ?
Через конструктор и/или аргументы методов.
Но не стоит передавать в них сам запрос, а только информацию нужную для него.
>function addUser($login, $password)
> {
> $pdo = ...;
> $query = $pdo->prepare("INSERT INTO users (id, login, password) VALUES (NULL, :login, :password)");
> $query->execute(array(
> 'login' => $login,
> 'password' => $password
> ));
> }
>>1107313
Обычно, конструктор используется для заполнения полей класса и для внедрения зависимостей
Прим.
class User
{
private $id;
private $login;
private $password;
//заполнение полей
public function __construct($id, $login, $password)
{
$this->id = $id;
$this->login = $login;
$this->password = $password;
}
}
class Database
{
public function addUser(User $user)
{
$query = "INSERT INTO users ...";
...
}
...
}
class Controller
{
private $database;
//внедрение зависимостей
public function __construct(Database $database)
{
$this->database = $database;
}
public function run()
{
$user = new User(...);
$this->database->addUser($user);
}
}
>могу ли я в качестве аргумента использовать mysql запрос?
В доктрине есть метод принимающий sql-запрос в качестве аргумента. Такой паттерн, вроде, называется Query Builder, но я не уверен насчет этого.
>Или как по другому загрузить в объект информацю нужную ?
Через конструктор и/или аргументы методов.
Но не стоит передавать в них сам запрос, а только информацию нужную для него.
>function addUser($login, $password)
> {
> $pdo = ...;
> $query = $pdo->prepare("INSERT INTO users (id, login, password) VALUES (NULL, :login, :password)");
> $query->execute(array(
> 'login' => $login,
> 'password' => $password
> ));
> }
Покажи код
Он выдает не номер символа, а номер байта. Ну например, в utf-8 кириллица занимает 2 байта и может быть несовпадение из-за этого. Преобразовать номера байта в номер символа можно хитрыми манипуляциями с substr/mb_strlen.
Query Builder это когда строят запрос по кусочкам, обычно из-за наличия if или циклов (если запрос всегда одинаковый, то проще его сразу и написать):
$qb = new QueryBuilder('some_table');
$qb->where('x = ?', $x);
if ($y) {
$qb->andWhere('y = ?', $y);
}
$qb->orderBy('zzz');
$sql = $qb->getSql();
По поводу работы c базой данных с использованием ООП- обязательно для начала прочти теорию по этой теме: https://github.com/codedokode/pasta/blob/master/db/patterns-oop.md
Специально сделал обзор и все разжевал.
/([а-яёa-z])([a-z]+)([а-яёa-z])/ui
ЧЯДНТ?
Сделал, запилив дополнительный регэксп без первой скобки перед реплейсментом. Чувствую, что уебанство, но до универсального регэкспа не догадался.
https://pastebin.com/P2xhDuMc
Создаю такой вот массив https://pastebin.com/EbKnNubE
но получаю https://pastebin.com/wbrES8pD
Как добавить еще одни скобки вначале?
У всех сначала не было опыта. Больше пиши и читай чужой код. И не грусти, а то станешь как я.
>private $query;
>private $sql;
>
>$this->sql = 'SELECT first_name,last_name,group_num,exam_sum FROM students ORDER BY id DESC LIMIT '. $this->rows .' OFFSET '. $this->offset;
>$this->query = $this->db->getPdo()->prepare($this->sql);
Свойства здесь не нужны, лучше использовать простые переменные, а в свойствах хранить только PDO как зависимость.
>private $db;
>public function __construct(...) {
>$this->db = new Database();
Вот примерно так, только сам класс StudentGataway наследовать от твоего Database, и само PDO передавать в конструктор, и сохранять в свойства.
>public function __construct($p) {
>$this->offset = $p * $this->rows - $this->rows; //сверхформула для высчитывания оффсета, чтобы переходить по страницам вроде page=1, page=2 etc
>}
Так не правильно делать. Лучше offset передавать в аргумент использующей его функции, а высчитывать его в каком-нибудь классе хелпере. В задаче со студентами должен быть пагинатор и лучше поместить высчитывающую функцию туда.
>public function SelectStudent(){
>
>$this->sql = 'SELECT first_name,last_name,group_num,exam_sum FROM students ORDER BY id DESC LIMIT '. $this->rows .' OFFSET '. $this->offset;
Нужны пробелы после запятых
У тебя здесь можно провести SQL-инъекцию. Почему не передал здесь данные через плейсхолдеры?
>public function getTotalRows()
Лучше сделать такую функцию в пагинаторе и передавать в неё количество, а на её прежнем месте сделать функцию getCount().
>private $query;
>private $sql;
>
>$this->sql = 'SELECT first_name,last_name,group_num,exam_sum FROM students ORDER BY id DESC LIMIT '. $this->rows .' OFFSET '. $this->offset;
>$this->query = $this->db->getPdo()->prepare($this->sql);
Свойства здесь не нужны, лучше использовать простые переменные, а в свойствах хранить только PDO как зависимость.
>private $db;
>public function __construct(...) {
>$this->db = new Database();
Вот примерно так, только сам класс StudentGataway наследовать от твоего Database, и само PDO передавать в конструктор, и сохранять в свойства.
>public function __construct($p) {
>$this->offset = $p * $this->rows - $this->rows; //сверхформула для высчитывания оффсета, чтобы переходить по страницам вроде page=1, page=2 etc
>}
Так не правильно делать. Лучше offset передавать в аргумент использующей его функции, а высчитывать его в каком-нибудь классе хелпере. В задаче со студентами должен быть пагинатор и лучше поместить высчитывающую функцию туда.
>public function SelectStudent(){
>
>$this->sql = 'SELECT first_name,last_name,group_num,exam_sum FROM students ORDER BY id DESC LIMIT '. $this->rows .' OFFSET '. $this->offset;
Нужны пробелы после запятых
У тебя здесь можно провести SQL-инъекцию. Почему не передал здесь данные через плейсхолдеры?
>public function getTotalRows()
Лучше сделать такую функцию в пагинаторе и передавать в неё количество, а на её прежнем месте сделать функцию getCount().
Спасибо за табличку, в моем случае $_COOKIE['notification'] или строка, или NULL (я куки очищаю полностью же, как только получил сообщение). Поэтому как isset, так и !empty должны давать одинаковый результат.
Нуок, сделал так:
if(!empty($_COOKIE['notification'])) {
echo '<div class="notification">' . $_COOKIE['notification'] . '</div>';
setcookie('notification', '', time() - 1);
}
Все равно не работает, хотя var_dump показывает bool(true). Опять же, оборачиваю в переменную либо использую обратное значение (empty без !) - все работает!
Насчет имени переменной - сорян, если изнасиловал кому-то мозг, понимаю, что так нельзя называть, но у меня дико припекало от того, что фактически if(true) не выполняется.
>а при приведении 0 к булеану (что происходит в условии), он становится false и оно не выполняется.
Ничего не понял, как там может появиться 0, если куки пусты?
>>1107197
>Зачем гадать. Попробуй сделать var_dump($true); var_dump($_COOKIE); var_dump(isset(...)); в обоих случаях.
Да в том-то и дело, что в обоих случаях они все либо true (и в массиве 1 строка), либо false (и тогда массив соответственно пустой).
А теперь - внимание!!! Разгадка. Внимательно посмотрите на эти две строчки, и скажите, чем они отличаются:
if(isset($_COOKIE['notificaton']))
if(isset($_COOKIE['notification']))
Больше часа на это убил, еще и анону мозг вынес, г-ди, какой же я тупой)))))
Кстати, как избежать в дальнейшем подобного мозгоебства? Более короткие имена использовать? Может какие-то редакторы/плагины под это дело есть? Сам юзаю саблайм, потихоньку перекатываюсь на VS Code.
Я специально занимался слепой 10-и пальцевой печатью, у меня на play.typeracer.com частенько скорость набора переваливает за 120 слов в минуту, печатаю в браузере - ничего не глючит. Может вам следует обновить железо?
>>1107274
Не вариант, в твоём репозитории никто ответы ОПа читать не будет. А в треде удобно то, что объяснения могут увидеть много человек, спросить что не понятно.
>>1107292
10-ю пальцами без практики не научишься. Качай любой тренажёр и тренируйся. Ну и учти, что при написании кода тебе это особо не понадобится, если пишешь не в блокноте, а в нормальной IDE. А вот при переписке с кем-то - очень помогает.
bump
Понимаю, что надо использовать mouseover, но не понимаю как его прилепить на всплывающий див.
>как избежать в дальнейшем подобного мозгоебства?
от каких-то ошибок защитят IDE (единственный нормальный - шторм, в качестве агрумента можно почитать, какой функционал я использую на постоянной основе >>1101711). например, я бы не допустил твоей ошибки, т.к. у меня в шторме стоит словарик английских слов и он подчеркнул бы неправильно написанный ключ массива.
еще надо ставить error_reporting E_ALL, чтобы при исполнении генерировался notice о том, что такого ключа у массива нет.
также во всяких условиях я пишу примерно так
if (123 === $value), т.е. значение слева и строгое сравнение. потому что если писать как обычно, можно проебаться, написав if ($value = 123) и оно выдаст true и IDE от такого не защитит.
а в целом полностью никак не защититься. и со временем перестанешь удивляться, что так происходит, придет смирение.
я счалал прогу stamina (но думаю любая подойдет) и недели за две переучился и по-русски, и по-английски. главное когда учишься, стараться печатать медленно и без ошибок.
>Ничего не понял, как там может появиться 0, если куки пусты?
>
я про твои куки ничего не знаю пусты они там или нет. я просто имел в виду что
$var1 = 0;
$var2 = '';
isset($var1); // true
isset($var2); // true
if ($var1 || $var2) {
// не выполнится
}
$values = значения по умолчанию (пустые);
$errors = пустой массив;
Если (форма отправлена) {
Копируем переданные значения полей в $values;
Проверяем значения в $values и записываем найденные ошибки в $errors;
Если (ошибок нет) {
Делаем требуемое действие (например вставляем запись в БД);
Редиректим куда-нибудь;
Завершаем скрипт;
}
}
Выводим форму($values, $errors);
Какой код нужно написать в Выводим форму? Завершаем скрипт?
бы динамически отрисовывались все устройства и их подключения. Как это лучше сделать? Мне на ум приходит только вариант с библиотекой GD. То есть тупо рисовать картинку в коде. Может есть получше варианты?
Кажись сам разобрался, GraphViz думаю подойдет.
> в твоём репозитории никто ответы ОПа читать не будет
ну серьёзно, кому еще нужны ответы ОПа к не своей задаче? Их никто не читает, кроме того, кому они адресованы
>Их никто не читает, кроме того, кому они адресованы
не стоит говорить за всех, особенно на анонимной борде. я читаю и еще анон, который писал про это изначально тоже, соответственно нас минимум двое.
по-моему, если хочешь научиться, логично читать подробные комментарии к чужим задачам. странно, что ты так не делаешь.
Вот для времени "когда" используется DateTime. (когда заканчивается урок? - в 12:15)
А для времени "сколько" его тоже можно использовать? (сколько длиться урок? - 45 минут)
Так же в MySQL в какой тип использовать для второго?
>Незачем код разбиения текста на предложения копипастить 2 раза. Копипаста - зло, раздувает объем кода, его становится должше читать.
> Функцию makeFirstletterUppercase лучше сделать так, чтобы она работала только для одного слова или предложения, и вызывать ее изнутри цикла для каждого предлложения.
https://ideone.com/ga6iPB - исправил свой говнокод с йодастайлом, посмотри, пожалуйста.
1280x720, 0:09
А, нет, извините, до этого не дойдёт. Заработался.
Подскажите почему вот это перестало работать при загрузке на удаленный сервер, на локальном все збс.
Короткие теги <? не включены, используй <?php. Кстати, ты мог бы это проверить, открыв исходный код страницы в браузере и проверив, отображаются ли они там.
Спасибо тебе милчеловек.
Я тоже читаю все ответы опа.
>>1108062
Я как-то компилировал PHP под Windows. Он по моему на Си, а не Си++, если не путаю. Насчет хороших практик - думаю, подойдут любые "хорошие практики" по Си++.
>>1108017
Это называется "интервал времени". Для него есть класс:
http://php.net/manual/en/class.dateinterval.php
А также http://php.net/manual/en/class.dateperiod.php
В стандарте SQL для этого есть специальный тип INTERVAL, судя по https://www.techrepublic.com/article/sql-basics-datetime-and-interval-data-types/ .
Тут описана его реализация в Postgres: https://postgrespro.ru/docs/postgrespro/9.5/datatype-datetime.html
Тут описана его реализация в Oracle: https://www.toadworld.com/platforms/oracle/w/wiki/2041.interval-datatypes
В MySQL судя по https://dev.mysql.com/worklog/task/?id=831 это пока не реализовано.
Вместо этого для интервала (если он небольшой) можно испоьзовать тип TIME, судя по https://dev.mysql.com/doc/refman/5.7/en/time.html
> MySQL retrieves and displays TIME values in 'HH:MM:SS' format (or 'HHH:MM:SS' format for large hours values). TIME values may range from '-838:59:59' to '838:59:59'. The hours part may be so large because the TIME type can be used not only to represent a time of day (which must be less than 24 hours), but also elapsed time or a time interval between two events (which may be much greater than 24 hours, or even negative).
Также, можно хранить интервал просто как число - минут, часов, дней итд.
Как напоминание об интервалах, в MySQL есть такая конструкция:
NOW() + INTERVAL 1 MONTH
https://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_date-add
>>1108062
Я как-то компилировал PHP под Windows. Он по моему на Си, а не Си++, если не путаю. Насчет хороших практик - думаю, подойдут любые "хорошие практики" по Си++.
>>1108017
Это называется "интервал времени". Для него есть класс:
http://php.net/manual/en/class.dateinterval.php
А также http://php.net/manual/en/class.dateperiod.php
В стандарте SQL для этого есть специальный тип INTERVAL, судя по https://www.techrepublic.com/article/sql-basics-datetime-and-interval-data-types/ .
Тут описана его реализация в Postgres: https://postgrespro.ru/docs/postgrespro/9.5/datatype-datetime.html
Тут описана его реализация в Oracle: https://www.toadworld.com/platforms/oracle/w/wiki/2041.interval-datatypes
В MySQL судя по https://dev.mysql.com/worklog/task/?id=831 это пока не реализовано.
Вместо этого для интервала (если он небольшой) можно испоьзовать тип TIME, судя по https://dev.mysql.com/doc/refman/5.7/en/time.html
> MySQL retrieves and displays TIME values in 'HH:MM:SS' format (or 'HHH:MM:SS' format for large hours values). TIME values may range from '-838:59:59' to '838:59:59'. The hours part may be so large because the TIME type can be used not only to represent a time of day (which must be less than 24 hours), but also elapsed time or a time interval between two events (which may be much greater than 24 hours, or even negative).
Также, можно хранить интервал просто как число - минут, часов, дней итд.
Как напоминание об интервалах, в MySQL есть такая конструкция:
NOW() + INTERVAL 1 MONTH
https://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_date-add
> Какой код нужно написать в Выводим форму?
Тот, который выводит страницу с формой. Если ты используешь шаблон, то тот, который вызывает этот шаблон. Шаблоны описаны тут https://github.com/codedokode/pasta/blob/master/php/templates.md
> Завершаем скрипт?
return или exit в зависимости от того, как реализован у тебя контроллер.
Идея алгоритма в том, что вывод формы и обработку отправленных данных делает один и тот же контроллер или скрипт. И потому при ошибке обработки данных мы просто выводим форму еще раз, но с введенными в нее значениями.
>>1108054
Код с ошибками.
Замечания:
- неправильно, что ты пытаешься подключить файл без проверки. Во-первых, автозагрузчиков может быть несколько и например библиотека может использовать свой загрузчик из своей папки. Твой же выдаст ошибку в этом случае.
- во-вторых, твой автозагрузчик выдаст ошибку на код вроде if (class_exists('InvalidClassName')) { ... }
- DOCUMENT_ROOT использовать тоже неправильно. Он имеет смысл только внутри веб-сервера (а не при запуске из командной строки например), да и не всегда корректно указывает куда-то (представь например случай php-fpm + nginx).
Алсо, в PHP есть встроенная функция-автозагрузчик, ищущая файл в include_path: http://php.net/manual/ru/function.spl-autoload.php
>>1108035
> foreach ($sentence as $sentences) {
Наоборот должно быть, множественное число идет в начале. $sentences as $sentence. "Из набора предложений взять по очереди каждое предложение".
> $firstUp = mb_strtoupper(mb_substr($text, 0, 1)) . mb_substr($text, 1, null);
> return $firstUp;
Можно сразу писать return mb_strtoupper...
А так, решено верно.
> Какой код нужно написать в Выводим форму?
Тот, который выводит страницу с формой. Если ты используешь шаблон, то тот, который вызывает этот шаблон. Шаблоны описаны тут https://github.com/codedokode/pasta/blob/master/php/templates.md
> Завершаем скрипт?
return или exit в зависимости от того, как реализован у тебя контроллер.
Идея алгоритма в том, что вывод формы и обработку отправленных данных делает один и тот же контроллер или скрипт. И потому при ошибке обработки данных мы просто выводим форму еще раз, но с введенными в нее значениями.
>>1108054
Код с ошибками.
Замечания:
- неправильно, что ты пытаешься подключить файл без проверки. Во-первых, автозагрузчиков может быть несколько и например библиотека может использовать свой загрузчик из своей папки. Твой же выдаст ошибку в этом случае.
- во-вторых, твой автозагрузчик выдаст ошибку на код вроде if (class_exists('InvalidClassName')) { ... }
- DOCUMENT_ROOT использовать тоже неправильно. Он имеет смысл только внутри веб-сервера (а не при запуске из командной строки например), да и не всегда корректно указывает куда-то (представь например случай php-fpm + nginx).
Алсо, в PHP есть встроенная функция-автозагрузчик, ищущая файл в include_path: http://php.net/manual/ru/function.spl-autoload.php
>>1108035
> foreach ($sentence as $sentences) {
Наоборот должно быть, множественное число идет в начале. $sentences as $sentence. "Из набора предложений взять по очереди каждое предложение".
> $firstUp = mb_strtoupper(mb_substr($text, 0, 1)) . mb_substr($text, 1, null);
> return $firstUp;
Можно сразу писать return mb_strtoupper...
А так, решено верно.
Это кстати хорошо, что ты освоил возможности IDE. Кстати, тут нет желающих написать инструменты для рефакторинга без IDE (чтобы их можно было вызывать из командной строки)? Ну например, утилиту, которая заменяет имя класса с учетом неймспейсов или которая чистит список неймспейсов от неиспользуемых значений.
Еще из полезных возможностей - быстрый переход при вводе части имени файла или класса. Очень полезно, когда большой проект.
Насчет защиты (тут бы не помогло): я стараюсь писать вместо isset($array['field']) или empty просто array_key_exists('field', $array), так как isset/empty промолчит если я опечатаюсь в названии $array. Не люблю такие функции.
Тут бы помогла константа: $_COOKIE[NOITFICATION_COOKIE]. Она же помогла бы сделать нечитаемое название куки вроде nf (Гугл такие названия любит, смотрите любой сервис гугла).
>>1107302
1) Поместить див внутрь ссылки в HTML коде.
2) Использовать JS
3) Также, можно использовать интересный трюк с псевдоэлементом:
<a title="xxx" href="">ссылка</a>
a:before {
content: attr(title);
display: block;
position: absolute;
}
Попробуй-ка так сделать.
>>1107669
У меня само собой со временем получилось. Не 10-пальцевая печать, но довольно быстро. И я заметил, что получается печатать не глядя на клавиатуру, интуитивно понимаю, где какая клавиша, точнее не понимаю, а мышечная память появляется и пальцы сами куда надо нажимают.
Раскладку переключаю с помощью левого/правого Ctrl, без этого постоянно ошибки получаются.
Это кстати хорошо, что ты освоил возможности IDE. Кстати, тут нет желающих написать инструменты для рефакторинга без IDE (чтобы их можно было вызывать из командной строки)? Ну например, утилиту, которая заменяет имя класса с учетом неймспейсов или которая чистит список неймспейсов от неиспользуемых значений.
Еще из полезных возможностей - быстрый переход при вводе части имени файла или класса. Очень полезно, когда большой проект.
Насчет защиты (тут бы не помогло): я стараюсь писать вместо isset($array['field']) или empty просто array_key_exists('field', $array), так как isset/empty промолчит если я опечатаюсь в названии $array. Не люблю такие функции.
Тут бы помогла константа: $_COOKIE[NOITFICATION_COOKIE]. Она же помогла бы сделать нечитаемое название куки вроде nf (Гугл такие названия любит, смотрите любой сервис гугла).
>>1107302
1) Поместить див внутрь ссылки в HTML коде.
2) Использовать JS
3) Также, можно использовать интересный трюк с псевдоэлементом:
<a title="xxx" href="">ссылка</a>
a:before {
content: attr(title);
display: block;
position: absolute;
}
Попробуй-ка так сделать.
>>1107669
У меня само собой со временем получилось. Не 10-пальцевая печать, но довольно быстро. И я заметил, что получается печатать не глядя на клавиатуру, интуитивно понимаю, где какая клавиша, точнее не понимаю, а мышечная память появляется и пальцы сами куда надо нажимают.
Раскладку переключаю с помощью левого/правого Ctrl, без этого постоянно ошибки получаются.
Имена функций/методов пишут с маленькой буквы.
Имена файлов должны быть в едином стиле:
> /Student.php';
> .'/db_connection.php';
В плане ООП, у меня ощущение, что ты не понимаешь, зачем нужны поля и просто натыкал их наугад. Что представляет собой объект StudentGateway? Какие свойства должны быть у этого объекта?
> private $query;
$query - это свойство объекта StudentGateway? Для какой цели оно хранится? Там не нужно поле, а достаточно простой переменной.
> private $sql;
> private $offset;
То же замечание
> public function __construct($p) {
То есть у тебя один объект StudentGateway может получать данные только с одной страницы? зачем так, лучше номер страницы передавать как аргумент.
Также, я бы советовал убрать работу со страницами из SG, это по идее не его задача. Удобнее и гибче сделать получение данных через offset/limit, а не по номеру страницы.
> $this->db = new Database();
Тут советую почитать урок пр DI https://github.com/codedokode/pasta/blob/master/arch/di.md
> LIMIT '. $this->rows .
Нужно подставлять данные через плейсхолдеры
> while ($row = $this->query->fetch(PDO::FETCH_ASSOC)) {
> $listOfStudents[] = $row;
Это можно сделать одним действием, посмотри мануал по PDOStatement.
> $listOfStudents
Можно просто $students.
> $this->sql = 'SELECT COUNT(id) FROM students';
> $this->query = $this->db->getPdo()->prepare($this->sql);
Если в запросе нет подставляемых параметров, то prepare не требуется, можно сразу выполнять запрос.
> $pages = intval($pages['COUNT(id)']);
> $pages = $pages / $this->rows;
Мне кажется, что функция с названием getTotalRows должна возвращать число строк в таблице.
Имена функций/методов пишут с маленькой буквы.
Имена файлов должны быть в едином стиле:
> /Student.php';
> .'/db_connection.php';
В плане ООП, у меня ощущение, что ты не понимаешь, зачем нужны поля и просто натыкал их наугад. Что представляет собой объект StudentGateway? Какие свойства должны быть у этого объекта?
> private $query;
$query - это свойство объекта StudentGateway? Для какой цели оно хранится? Там не нужно поле, а достаточно простой переменной.
> private $sql;
> private $offset;
То же замечание
> public function __construct($p) {
То есть у тебя один объект StudentGateway может получать данные только с одной страницы? зачем так, лучше номер страницы передавать как аргумент.
Также, я бы советовал убрать работу со страницами из SG, это по идее не его задача. Удобнее и гибче сделать получение данных через offset/limit, а не по номеру страницы.
> $this->db = new Database();
Тут советую почитать урок пр DI https://github.com/codedokode/pasta/blob/master/arch/di.md
> LIMIT '. $this->rows .
Нужно подставлять данные через плейсхолдеры
> while ($row = $this->query->fetch(PDO::FETCH_ASSOC)) {
> $listOfStudents[] = $row;
Это можно сделать одним действием, посмотри мануал по PDOStatement.
> $listOfStudents
Можно просто $students.
> $this->sql = 'SELECT COUNT(id) FROM students';
> $this->query = $this->db->getPdo()->prepare($this->sql);
Если в запросе нет подставляемых параметров, то prepare не требуется, можно сразу выполнять запрос.
> $pages = intval($pages['COUNT(id)']);
> $pages = $pages / $this->rows;
Мне кажется, что функция с названием getTotalRows должна возвращать число строк в таблице.
> Вот примерно так, только сам класс StudentGataway наследовать от твоего Database,
Наследование - это отношение A is B (A is an improved version of B), и не уверен, что оно тут годится. Наследовать можно скорее от класса вроде AbstractGateway.
>>1107483
Добавить еще один уровень вложенности массива
'occupancies' => [
[...],
[...]
]
>>1107470
Нужно написать:
только кириллица - латиница - любые буквы
>>1107290
Немного описано тут https://github.com/codedokode/pasta/blob/master/php/exceptions.md#Страница-ошибки-в-веб-приложениях
>>1107359
Да, preg_match не проходит один кусок строки дважды. Исправить это сложно:
- либо получать позицию найденного фрагмента в тексте средствами флага PREG_OFFSET_CAPTURE в preg_match_all и с ее помощью брать подстроку. PREG_OFFSET_CAPTURE возвращает позицию не в символах, а в байтах, потому придется делать преобразование с помощью mb_strlen/substr.
- либо получать позицию найденного фрагмента строки с помощью mb_strpos (не работает, если одинаковых фрагментов там несколько)
Также, можно вместо одного регекспа сделать несколько и искать каждый по отдельности.
>>1107290
Нельзя при 404 ошибке делать редирект. Так как он значит "контент есть, но по другому адресу". Надо сразу выдавать страницу ошибки.
> А что делать, если например, произошла ошибка в БД, то тоже на 404 редирект нужен?
Нужно выдавать код 5xx, почитай список кодов состояния: https://ru.wikipedia.org/wiki/Список_кодов_состояния_HTTP
> Вот примерно так, только сам класс StudentGataway наследовать от твоего Database,
Наследование - это отношение A is B (A is an improved version of B), и не уверен, что оно тут годится. Наследовать можно скорее от класса вроде AbstractGateway.
>>1107483
Добавить еще один уровень вложенности массива
'occupancies' => [
[...],
[...]
]
>>1107470
Нужно написать:
только кириллица - латиница - любые буквы
>>1107290
Немного описано тут https://github.com/codedokode/pasta/blob/master/php/exceptions.md#Страница-ошибки-в-веб-приложениях
>>1107359
Да, preg_match не проходит один кусок строки дважды. Исправить это сложно:
- либо получать позицию найденного фрагмента в тексте средствами флага PREG_OFFSET_CAPTURE в preg_match_all и с ее помощью брать подстроку. PREG_OFFSET_CAPTURE возвращает позицию не в символах, а в байтах, потому придется делать преобразование с помощью mb_strlen/substr.
- либо получать позицию найденного фрагмента строки с помощью mb_strpos (не работает, если одинаковых фрагментов там несколько)
Также, можно вместо одного регекспа сделать несколько и искать каждый по отдельности.
>>1107290
Нельзя при 404 ошибке делать редирект. Так как он значит "контент есть, но по другому адресу". Надо сразу выдавать страницу ошибки.
> А что делать, если например, произошла ошибка в БД, то тоже на 404 редирект нужен?
Нужно выдавать код 5xx, почитай список кодов состояния: https://ru.wikipedia.org/wiki/Список_кодов_состояния_HTTP
У тебя наверно не используются виртуальные хосты, а только один хост в сервере прописан. Тогда можно так и оставить.
>>1107265
>>1107266
Такой интересный вопрос, и никто в треде не комментирует? Что же вы так.
> 1. заканчивать названия объектов на -er - это анти ооп http://www.yegor256.com/2015/03/09/objects-end-with-er.html
По моему опыту, да, часто объекты делятся на "сущности", у которых есть свойства, и "сервисы", у которых нет свойств и которые есть только в 1 экземпляре. Он предлагает ликвидировать "сервисы" и их код перенести в "сущности". Но это не всегда удобно:
- если сервис использовал DI, то теперь мы должны передавать зависимости при создании сущности, хотя они, может быть, ей редко когда нужны и выглядят "лишними". То есть в объект User мы должны передавать PDO, и еще какие-то зависимости.
- если сервис создает сущности (StudentGateway->findStudentById(..)), то как этот код перенести в Student?
- мы должны смешивать функционал в одном классе и менять паттерны в угоды этой идее. Например, в соответствии с его идеями, мы должны отказаться от Data Mapper и заменить его на Active Record, которая имеет недостатки (много функционала собрано в одном классе).
- на практике, с одной сущностью часто можно делать очень много вещей. Возьмем Пост в блоге: опубликовать, прокомментировать, лайкнуть, проверить на правильность, сохранить в БД, загрузить из БД, поделиться ссылкой на Пост по почте. Ну или возьмите Товар в интернет-магазине. Или Пользователя в соцсети. Там просто тонна функционала и класс станет огромным, и будет напоминать God object.
Если подумать над решением указанных проблем, "сервисы" как раз помогают их решить. Вот также статья про Service Layer: http://design-pattern.ru/patterns/service-layer.html
Возможно, что это не "чистый ООП". А это где-то описано, каким должен быть "чистый ООП"? Я не знаю.
А какие вы видите еще варианты решения? Попробуйте взять реалистичный код (посложнее чем сортировка яблок) и избавиться там от сервисов.
По второму вопросу.
> Isn't it already clear that a single-argument constructor of class CSV expects the name of a file with comma-separated values? I would rename it to file
fileName как раз лучше, так как file у меня ассоциируется с объектом вроде SplFileObject.
> 3. пустые строки - это тоже code smell, т.к. они означают, что метод не соблюдает принцип единой обязанности.
Мне все же больше нравится вариант с пустыми строками. Не надо преумножать сущности (методы) без необходимости, если метод не слишком большой, то хватит и перевода строки. Это мое субъективное мнение.
> и если он прав, то не слишком ли это высокие материи, чтобы задумываться о них на джун-уровне?
Почитать такую статью и попробовать составить свое мнение было бы полезно.
У тебя наверно не используются виртуальные хосты, а только один хост в сервере прописан. Тогда можно так и оставить.
>>1107265
>>1107266
Такой интересный вопрос, и никто в треде не комментирует? Что же вы так.
> 1. заканчивать названия объектов на -er - это анти ооп http://www.yegor256.com/2015/03/09/objects-end-with-er.html
По моему опыту, да, часто объекты делятся на "сущности", у которых есть свойства, и "сервисы", у которых нет свойств и которые есть только в 1 экземпляре. Он предлагает ликвидировать "сервисы" и их код перенести в "сущности". Но это не всегда удобно:
- если сервис использовал DI, то теперь мы должны передавать зависимости при создании сущности, хотя они, может быть, ей редко когда нужны и выглядят "лишними". То есть в объект User мы должны передавать PDO, и еще какие-то зависимости.
- если сервис создает сущности (StudentGateway->findStudentById(..)), то как этот код перенести в Student?
- мы должны смешивать функционал в одном классе и менять паттерны в угоды этой идее. Например, в соответствии с его идеями, мы должны отказаться от Data Mapper и заменить его на Active Record, которая имеет недостатки (много функционала собрано в одном классе).
- на практике, с одной сущностью часто можно делать очень много вещей. Возьмем Пост в блоге: опубликовать, прокомментировать, лайкнуть, проверить на правильность, сохранить в БД, загрузить из БД, поделиться ссылкой на Пост по почте. Ну или возьмите Товар в интернет-магазине. Или Пользователя в соцсети. Там просто тонна функционала и класс станет огромным, и будет напоминать God object.
Если подумать над решением указанных проблем, "сервисы" как раз помогают их решить. Вот также статья про Service Layer: http://design-pattern.ru/patterns/service-layer.html
Возможно, что это не "чистый ООП". А это где-то описано, каким должен быть "чистый ООП"? Я не знаю.
А какие вы видите еще варианты решения? Попробуйте взять реалистичный код (посложнее чем сортировка яблок) и избавиться там от сервисов.
По второму вопросу.
> Isn't it already clear that a single-argument constructor of class CSV expects the name of a file with comma-separated values? I would rename it to file
fileName как раз лучше, так как file у меня ассоциируется с объектом вроде SplFileObject.
> 3. пустые строки - это тоже code smell, т.к. они означают, что метод не соблюдает принцип единой обязанности.
Мне все же больше нравится вариант с пустыми строками. Не надо преумножать сущности (методы) без необходимости, если метод не слишком большой, то хватит и перевода строки. Это мое субъективное мнение.
> и если он прав, то не слишком ли это высокие материи, чтобы задумываться о них на джун-уровне?
Почитать такую статью и попробовать составить свое мнение было бы полезно.
Попробуй сравнить достоинства/недостатки того или иного варианта, а не заучивать догмы "всегда надо делать X". Обычно все паттерны, подходы на чем-то основаны и появились из-за необходимости решить какую-то проблему. Те же Helper тоже появились не на пустом месте.
По коду, ты перестарался, логичнее наверно $e = new Email('[ ^xANUSmeQ;^PUNCTUMcopi"m'); if ($e->isValid()) ... Как бонус, мы получаем специальный тип для email и можем тайп-хинтить его:
public function setEmail(Email $email);
Для URL, например, точно где-то есть класс, который умеет его разбирать на куски.
>>1106900
Да, считается, что у PHP хорошая документация.
Не обращай внимания, это я попробовал написать код используя только объекты и вилку (ну без нее блядь никак же), ориентируясь на то что там этот тип пишет "ООП это объекты и ничего более".
Так что пока не создадут такой язык, это так, баловство и графомания с киданием говном.
<html>
<head>
<?php include 'autoload.php'; ?>
</head>
<body>
...
</body>
</html>
Ничего не выводит, если расширение .html, работает корректно если .php
Здесь якобы работает https://github.com/codedokode/pasta/blob/master/php/templates.md
В процессе поиска наткнулся на
https://habrahabr.ru/post/139154/
где черти в комментах опустили автора небалуй.
ОП, молю, объясни кто прав, кто виноват!
$proxy = 'http://127.0.0.1:9150/';
curl_setopt($ch, CURLOPT_PROXY, $proxy);
curl_setopt($ch, CURLOPT_PROXYTYPE, 7);
)
и некоторые сайты действительно работают, однако нужный мне - нет. У него на входе стоит каптча и чувствую, что дело в ней.
Возвращает следующие хэдеры:
HTTP/1.1 302 Moved Temporarily Server: nginx Date: Sat, 16 Dec 2017 19:34:23 GMT Content-Type: application/octet-stream Transfer-Encoding: chunked Connection: close Set-Cookie: pregate=1513452863.64191784b0be11457be059be4ad2bcff.3fa8d862745b15a3ff47c669f88a3869 Location: /
При установке curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1) просто входит в бесконечный луп и отваливается на максимальном времени исполнения скрипта.
спасибо.
я составил свое мнение по поводу автора (чуть пробежавшись по некоторым другим постам) и оно такое: он смотрит на ООП как на неизбежное зло, которое порождает тонны кода, который сложен для понимания и поддержки:
>I thought it was obvious that the vast majority of modern software written in modern OO languages is unmaintainable and simply a mess.
http://www.yegor256.com/2016/08/15/what-is-wrong-object-oriented-programming.html
вот достаточно посмотреть на названия статей по ООП http://www.yegor256.com/tag/oop.html
он считает злом ORM, activeRecord, геттеры и сеттеры, try-catch и много чего еще.
ну или не как на неизбежное зло, а как на что-то несовершенное, место которого однажды займет что-то более простое и удобное. может и займет, а он может, указывая на недостатки ООП, приблизит этот день.
а по поводу плодить сущности без необходимости у него есть статья про то, что много маленьких классов - это как большой словарный запас, т.е. норм. вот она http://www.yegor256.com/2017/02/28/too-many-classes.html
Ты вообще неправильно понял.
>> I thought it was obvious that the vast majority of modern software written in modern OO languages is unmaintainable and simply a mess.
Он говорит о том, что большинство написанного софта на современных ООП языках - неподдерживаямая груда кода, где тут "ООП как на неизбежное зло"? Автор как раз за ООП, только у него своё понимание.
О том, что геттеры/сеттеры это не ООП и нарушают принцип Tell Dont Ask рассказывал даже один из авторов доктрины: https://youtu.be/WW2qPKukoZY?t=8m49s
try-catch тоже нужно избегать. Проблема в том, что большинство PHP-разработчиков не понимают исключения. Исключения нужно выбрасывать в исключительных ситуациях, которые не должны происходить. И ловиться для того, чтобы как-то оповещать разработчика о том, что что-то пошло не так. Я же постоянно в коде натыкаюсь на ситуции, когда исключения используют для валидации пользовательского ввода, что неверно, так как неверный ввод мы как правило ожидаем от пользователя.
Есть таблица, создаваемая по результату SQL-запроса. В каждой строке в ней добавлено текстовое поле для sumbit для записи текст в SQL через скрипт вроде
$var="\"".$_GET['submit1']."\""
$sql="INSERT into form1 (col1) VALUES (var)";
Как можно сделать, чтобы передавать в скрипт не только данные из поля submit1, но и данные из одной из ячеек в строке, в которой делается submit, и ещё текущее время ?
Можно, наверное, для каждой строки делать своё имя submit+row['id'] (будет submit1, sumbit2) и т.д., а потом из обрабатывающего скрипта/функции, зная, какая это строка, делать ещё один запрос и брать нужное значение и добавлять его к данным из формы, но может как-то попроще можно ?
Мне кажется, ты читал невнимательно и все перепутал. Если ты открываешь URL вроде http://localhost/test.html то веб-сервер по расширению видит, что это статический файл и отдает его как есть.
Если ты открываешь URL http://localhost/test.php то сервер с помощью PHP выполняет код из файла.
Это описано тут например https://github.com/codedokode/pasta/blob/master/soft/web-server.md#Встроенный-в-php-сервер
Это лишь настройки по умолчанию и разумеется, это можно перенастроить как-то по другому.
Когда ты в PHP коде пишешь require то расширение вообще не имеет значения.
Статья с хабра вообще отношения не имеет к делу. Что касается вставки значений в JS код, то у меня тоже есть урок по теме https://github.com/codedokode/pasta/blob/master/js/pass-values.md
Я тебе настоятельно рекомендую разобраться, как работает веб-сервер, как браузер и веб-сервер взаимодействуют. Не понимая этого, ты нормально дальше двигаться не сможешь. В идеале, хорошо бы было, если бы ты попробовал вручную отправить HTTP запрос, как описано в моем уроке. Это не так и сложно.
Он там приводит много цитат от всяких замечательных людей, и все эти цитаты не предлагают никакой альтернативы. ООП появился как способ организации сложных программ, и да, в том числе программ с GUI, так как с помощью ООП очень хорошо моделируются окошечки с кнопками, различные схемы (например, электрические схемы) или текст со сложным форматированием. Ну и не только они, конечно. Товары, категории и бренды в интернет-магазине так же прекрасно моделируются с помощью ООП.
Могу кстати сказать, что в старых версиях ИЕ для хранения HTML была использована не-ООП модель, и из-за этого DOM у них работал медленно и плохо (хотя, может быть и более экономно с точки зрения использования памяти, их модель была заточена на сайты, которые особо не модифицируют DOM, и плохо работала с современными интерактивными SPA приложениями): https://blogs.windows.com/msedgedev/2017/04/19/modernizing-dom-tree-microsoft-edge/
Бывают случаи, когда ООП не нужен - например, если вы пишете программу для обработки данных от какой-нибудь научной установки, там одна математика и структуры сложнее массивов в общем-то не требуются. И бывают случаи, когда люди начинают городить переусложненную архитектуру, как тут: https://habrahabr.ru/post/153225/ (та самая статья про хлеб).
Там есть цитата Линуса про то, что ему не нравится Си++, и отчасти поэтому в ядре линукса используется только Си. Но, например, в МакОСи фреймворк для написания драйверов объектно-ориентированный: https://developer.apple.com/library/content/documentation/DeviceDrivers/Conceptual/IOKitFundamentals/Introduction/Introduction.html - а недостатки Си++ исправлены тем, что там из него убрана часть особо опасных фич.
И действительно, для драйверов ООП хорошо подходит: допустим, у нас есть драйвер USB-флешки. Когда мы втыкаем эту флешку, система создает экземпляр драйвера (на деле чуть сложнее конечно). Втыкаем вторую - создает второй экземпляр. Вынимаем - уничтожает. Аналогии с ООП очевидны. Устройства обычно подключены к шинам (PCI, USB и тд), и эта иерархия тоже хорошо моделируется с помощью ООП. Также, при написании драйвера часто берется какой-то общий шаблон (например, шаблон драйвера звуковой карты) за основу и дополняется кодом работы уже с конкретным устройством. Это иногда можно удачно реализовать с помощью наследования.
Да и вообще, основной язык разработки под Mac/iOS долгое время был Objective-C - ООП-расширение языка Си.
Они пишут, что код на ООП сложный. Ну так он и без ООП был бы огромный и сложный. А ООП пытается снизить эту сложность за счет разделения кода на классы, определения интерфейса взаимодействия между ними, сокрытия деталей (инкапсуляции).
Лучше всего выгода от использования ООП оценивается, если написать 2 версии программы - с ООП и без (в версии без ООП разрешается даже использовать классы без методов, как "глупые" структуры для хранения данных). Скорее всего, с ООП (если вы его знаете) у вас получится написать код быстрее. Потому он так распространен.
Если кому-то хочется попробовать свои силы, в треде есть задачи про Гостиницу ( >>1100283 ) и Продюсерское Агенство (запощу отдельным постом ниже). И обратите внимание, это еще примеры простых задач, которые решаются за 30 минут. ООП тем и хорош, что он масштабируется на гораздо более сложные системы, которые пишутся человеко-годами. Потому он и используется.
Тут надо учесть, что я не особо силен в теории ООП. Я хорошо знаю только тот вид (?) ООП, который используется в приложениях на языках вроде Java/C++/скриптовых языков (то есть PHP/Python/Ruby). Я не изучал Simula и Smalltalk, в которых была реализована первоначальная версия ООП ( https://en.wikipedia.org/wiki/Object-oriented_programming#History ).
Что касается критики ООП - было бы хорошо не ограничиться короткими цитатами, а рассмотреть конкретные случаи, где ООП плохо работает, по мнению авторов. Давайте посмотрим на них вместе.
Наверно, один из примеров, где можно увидеть недостатки - это ORM. Объекты не очень хорошо ложатся на SQL-таблицы, ORM часто получаются сложные, с разными костылями вроде "ленивой загрузки" (чтобы не вытягивать всю БД в память) и искуственных языков вроде DQL, но тут уж извините, попробуйте написать лучше. В итоге ORM все же экономит время на написание кода работы с БД. У этого автора же, кстати, про ORM тоже статья есть: http://www.yegor256.com/2014/12/01/orm-offensive-anti-pattern.html (если хотите, и ее можем обсудить).
Также, если посмотрите, статья начинается со слов:
> Recently, I was trying to convince a few of my readers that a better understanding of an object in OOP would help us solve many problems in existing pseudo-object-oriented languages.
То есть автор и не отрицает необходимость ООП, ему просто чем-то не нравится его реализация в языках программирования. И если посмотреть другую его статью ( http://www.yegor256.com/2016/07/14/who-is-object.html ), то тут он топит за инкапсуляцию (хотя это слово в ней ни разу не использовано).
> Java is the most distressing thing to happen to computing since MS-DOS.
А вот тут обидно. На ней весь юзерспейс (не-ядро) Андроида собран и он прекрасно работает.
> он считает злом ORM, activeRecord, геттеры и сеттеры, try-catch и много чего еще.
Критика - это полезно. Вам, аноны, она может помочь лучше разобраться в ООП, потому я советую почитать эти статьи и составить свое мнение. Но, конечно, хотелось бы видеть не только критику, но и альтернативное решение.
Я всегда готов поучастовать в обсуждении и высказать свое мнение.
Он там приводит много цитат от всяких замечательных людей, и все эти цитаты не предлагают никакой альтернативы. ООП появился как способ организации сложных программ, и да, в том числе программ с GUI, так как с помощью ООП очень хорошо моделируются окошечки с кнопками, различные схемы (например, электрические схемы) или текст со сложным форматированием. Ну и не только они, конечно. Товары, категории и бренды в интернет-магазине так же прекрасно моделируются с помощью ООП.
Могу кстати сказать, что в старых версиях ИЕ для хранения HTML была использована не-ООП модель, и из-за этого DOM у них работал медленно и плохо (хотя, может быть и более экономно с точки зрения использования памяти, их модель была заточена на сайты, которые особо не модифицируют DOM, и плохо работала с современными интерактивными SPA приложениями): https://blogs.windows.com/msedgedev/2017/04/19/modernizing-dom-tree-microsoft-edge/
Бывают случаи, когда ООП не нужен - например, если вы пишете программу для обработки данных от какой-нибудь научной установки, там одна математика и структуры сложнее массивов в общем-то не требуются. И бывают случаи, когда люди начинают городить переусложненную архитектуру, как тут: https://habrahabr.ru/post/153225/ (та самая статья про хлеб).
Там есть цитата Линуса про то, что ему не нравится Си++, и отчасти поэтому в ядре линукса используется только Си. Но, например, в МакОСи фреймворк для написания драйверов объектно-ориентированный: https://developer.apple.com/library/content/documentation/DeviceDrivers/Conceptual/IOKitFundamentals/Introduction/Introduction.html - а недостатки Си++ исправлены тем, что там из него убрана часть особо опасных фич.
И действительно, для драйверов ООП хорошо подходит: допустим, у нас есть драйвер USB-флешки. Когда мы втыкаем эту флешку, система создает экземпляр драйвера (на деле чуть сложнее конечно). Втыкаем вторую - создает второй экземпляр. Вынимаем - уничтожает. Аналогии с ООП очевидны. Устройства обычно подключены к шинам (PCI, USB и тд), и эта иерархия тоже хорошо моделируется с помощью ООП. Также, при написании драйвера часто берется какой-то общий шаблон (например, шаблон драйвера звуковой карты) за основу и дополняется кодом работы уже с конкретным устройством. Это иногда можно удачно реализовать с помощью наследования.
Да и вообще, основной язык разработки под Mac/iOS долгое время был Objective-C - ООП-расширение языка Си.
Они пишут, что код на ООП сложный. Ну так он и без ООП был бы огромный и сложный. А ООП пытается снизить эту сложность за счет разделения кода на классы, определения интерфейса взаимодействия между ними, сокрытия деталей (инкапсуляции).
Лучше всего выгода от использования ООП оценивается, если написать 2 версии программы - с ООП и без (в версии без ООП разрешается даже использовать классы без методов, как "глупые" структуры для хранения данных). Скорее всего, с ООП (если вы его знаете) у вас получится написать код быстрее. Потому он так распространен.
Если кому-то хочется попробовать свои силы, в треде есть задачи про Гостиницу ( >>1100283 ) и Продюсерское Агенство (запощу отдельным постом ниже). И обратите внимание, это еще примеры простых задач, которые решаются за 30 минут. ООП тем и хорош, что он масштабируется на гораздо более сложные системы, которые пишутся человеко-годами. Потому он и используется.
Тут надо учесть, что я не особо силен в теории ООП. Я хорошо знаю только тот вид (?) ООП, который используется в приложениях на языках вроде Java/C++/скриптовых языков (то есть PHP/Python/Ruby). Я не изучал Simula и Smalltalk, в которых была реализована первоначальная версия ООП ( https://en.wikipedia.org/wiki/Object-oriented_programming#History ).
Что касается критики ООП - было бы хорошо не ограничиться короткими цитатами, а рассмотреть конкретные случаи, где ООП плохо работает, по мнению авторов. Давайте посмотрим на них вместе.
Наверно, один из примеров, где можно увидеть недостатки - это ORM. Объекты не очень хорошо ложатся на SQL-таблицы, ORM часто получаются сложные, с разными костылями вроде "ленивой загрузки" (чтобы не вытягивать всю БД в память) и искуственных языков вроде DQL, но тут уж извините, попробуйте написать лучше. В итоге ORM все же экономит время на написание кода работы с БД. У этого автора же, кстати, про ORM тоже статья есть: http://www.yegor256.com/2014/12/01/orm-offensive-anti-pattern.html (если хотите, и ее можем обсудить).
Также, если посмотрите, статья начинается со слов:
> Recently, I was trying to convince a few of my readers that a better understanding of an object in OOP would help us solve many problems in existing pseudo-object-oriented languages.
То есть автор и не отрицает необходимость ООП, ему просто чем-то не нравится его реализация в языках программирования. И если посмотреть другую его статью ( http://www.yegor256.com/2016/07/14/who-is-object.html ), то тут он топит за инкапсуляцию (хотя это слово в ней ни разу не использовано).
> Java is the most distressing thing to happen to computing since MS-DOS.
А вот тут обидно. На ней весь юзерспейс (не-ядро) Андроида собран и он прекрасно работает.
> он считает злом ORM, activeRecord, геттеры и сеттеры, try-catch и много чего еще.
Критика - это полезно. Вам, аноны, она может помочь лучше разобраться в ООП, потому я советую почитать эти статьи и составить свое мнение. Но, конечно, хотелось бы видеть не только критику, но и альтернативное решение.
Я всегда готов поучастовать в обсуждении и высказать свое мнение.
> О том, что геттеры/сеттеры это не ООП и нарушают принцип Tell Dont Ask
Какая предлагается альтернатива?
Вот он приводит пример плохого класса class User { private $passwordHash; } и видимо намекает, что модель должна быть "умной":
class User {
public function setPassword($password);
public function validate();
}
Но если у нас хешированием паролей занимается отдельный сервис, как его сюда внедрить? Если для валидации необходим доступ к БД? Доктрина не позволяет конструкторы с аргументами (можно решить фабрикой) и остается только вариант вроде
public function setPassword($hashService, $password);
public function validate($userRepository);
так? Не очень тянет на красивое АПИ если честно (в видео он по сути так и делает, используя анонимные функции, но здесь есть недостаток, что их иногда нужно несколько). Остается разве что отказаться от DI вообще. Ну и я высказывался по поводу умных моделей выше: >>1108431
По моему субъективному мнению, так мне нравится больше:
$authService->changePassword($user, $newPass);
Заметьте, в моем варианте легко реализуются уведомления о смене пароля, а также более сложные схемы, с высылкой письма со ссылкой, на которую надо кликнуть для смены, с 2F авторизацией. А что в варианте из видео? Вы утонете в коллбеках. Вообще, коллбеки там это как костыль - объект пользователя не умеет хешировать пароли, потому давайте с помощью коллбека дадим ему эту возможность.
Мне нравится подход, когда у нас есть сервисы, и они образуют внутреннее АПИ приложения. А "глупые" модели используются как аргументы для методов этого API. Да, тут получается меньше инкапсуляци, так как любой может читать/писать данные в модели. Предложите альтернативу. В некоторых языках это решается, например, в Си++, есть "friend classes", которые могут залезать в приватные поля другого класса.
Что касается инкапсуляции в случае с паролем, то ее поддерживаю. Ради безопасности, можно немного изменить схему и запретить выдачу хеша пароля наружу.
> Я же постоянно в коде натыкаюсь на ситуции, когда исключения используют для валидации пользовательского ввода
Здесь легко привести пример, когда это не работает: когда тебе надо сообщить об ошибках в нескольких полях. С другой стороны, исключения представляют ошибку и хочется их использовать. Вообще, валидация интерсная вещь. Вот представьте, что вам для валидации передали объект пользователя, и в нем не указан IP-адрес, с которого произведена регистрация. Что с этим делать? вы же не можете в форме написать пользователю "не указан IP адрес", потому что там нет такого поля.
Я для себя придумал такой компромиссный вариант:
- для ошибок, которые пользователь может исправить, возвращаем объект исключения через return
- для ошибок, которые пользователь исправить не может, выбрасываем его. То есть рассматриваем передачу объекта с отсутствующими данными как исключительную ситуацию.
Чувствую, впрочем, что решение не идеальное.
> О том, что геттеры/сеттеры это не ООП и нарушают принцип Tell Dont Ask
Какая предлагается альтернатива?
Вот он приводит пример плохого класса class User { private $passwordHash; } и видимо намекает, что модель должна быть "умной":
class User {
public function setPassword($password);
public function validate();
}
Но если у нас хешированием паролей занимается отдельный сервис, как его сюда внедрить? Если для валидации необходим доступ к БД? Доктрина не позволяет конструкторы с аргументами (можно решить фабрикой) и остается только вариант вроде
public function setPassword($hashService, $password);
public function validate($userRepository);
так? Не очень тянет на красивое АПИ если честно (в видео он по сути так и делает, используя анонимные функции, но здесь есть недостаток, что их иногда нужно несколько). Остается разве что отказаться от DI вообще. Ну и я высказывался по поводу умных моделей выше: >>1108431
По моему субъективному мнению, так мне нравится больше:
$authService->changePassword($user, $newPass);
Заметьте, в моем варианте легко реализуются уведомления о смене пароля, а также более сложные схемы, с высылкой письма со ссылкой, на которую надо кликнуть для смены, с 2F авторизацией. А что в варианте из видео? Вы утонете в коллбеках. Вообще, коллбеки там это как костыль - объект пользователя не умеет хешировать пароли, потому давайте с помощью коллбека дадим ему эту возможность.
Мне нравится подход, когда у нас есть сервисы, и они образуют внутреннее АПИ приложения. А "глупые" модели используются как аргументы для методов этого API. Да, тут получается меньше инкапсуляци, так как любой может читать/писать данные в модели. Предложите альтернативу. В некоторых языках это решается, например, в Си++, есть "friend classes", которые могут залезать в приватные поля другого класса.
Что касается инкапсуляции в случае с паролем, то ее поддерживаю. Ради безопасности, можно немного изменить схему и запретить выдачу хеша пароля наружу.
> Я же постоянно в коде натыкаюсь на ситуции, когда исключения используют для валидации пользовательского ввода
Здесь легко привести пример, когда это не работает: когда тебе надо сообщить об ошибках в нескольких полях. С другой стороны, исключения представляют ошибку и хочется их использовать. Вообще, валидация интерсная вещь. Вот представьте, что вам для валидации передали объект пользователя, и в нем не указан IP-адрес, с которого произведена регистрация. Что с этим делать? вы же не можете в форме написать пользователю "не указан IP адрес", потому что там нет такого поля.
Я для себя придумал такой компромиссный вариант:
- для ошибок, которые пользователь может исправить, возвращаем объект исключения через return
- для ошибок, которые пользователь исправить не может, выбрасываем его. То есть рассматриваем передачу объекта с отсутствующими данными как исключительную ситуацию.
Чувствую, впрочем, что решение не идеальное.
Задача про Гостиницу
Есть Гостиница, в ней есть Номера. Для каждого Номера известен его номер, количество Гостей, которое в него влезет, а также цена за сутки. В Гостиницу приезжают Гости. Нужно сделать объектную модель Гостиницы с такими возможностями (методами):
- получить список свободных номеров на определенную дату
- получить список свободных номеров, которые будут свободны в определенный диапазон дат (от A до B)
- дан список Гостей и диапазон дат, в которые они хотели бы заселиться. Необходимо подобрать им самый дешевый (а среди номеров с одинаковой ценой - самый маленький) Номер, который их вместит и который свободен в это время.
- то же самое, но при отстутствии одного подходящего номера для Гостей разрешается заселить их в несколько номеров, опять же, начиная с самых дешевых. Например, приехало 3 Гостя, но все 3-местные номера заняты и мы выделяем 2 2-местных, или 3 1-местных или 1-местный + 2-местный.
- зарегистрировать проживание данных Гостей в данных Номерах на данный период
- получить историю заселения Номера (кто в нем когда жил)
- получить историю заселения Гостя (в каких номерах он жил)
- получить статистику доходов Гостиницы за данный диапазон дат (в день A отдель заработал X тугриков, в день B - Y тугриков и так далее)
Задача про Продюсерское Агенство
Есть ПродюсерскоеАгенство, и оно периодически сотрудничает с разными Персонами для участия в рекламных, музыкальных, кинематографических и других Проектах. Агенству нужно хранить информацию о Персонах, с которыми оно контактировало или планирует контактировать. Тебе поручено создание соответствующей базы данных.
Персоны - это люди, у которых есть какие-то творческие способности. У каждой Персоны есть такие свойства:
- имя
- контактный номер телефона
Кроме того, у них могут быть навыки: Персона может быть Актером, Моделью, Музыкантом, Менеджером.
У Актера в дополнение к обычным свойствам есть свойство: список Фильмов, в которых он снимался
У Музыканта есть свойства: список Групп, в которых он участвует, и список инструментов, на которых он умеет играть
У Модели есть свойства: рост, цвет глаз и цвет волос
У Менеджера (Агент или менеджер по работе с талантами) есть свойство: название Агенства, которое он представляет.
У Актера, Музыканта или Модели может быть свой Менеджер, и эта информация должна быть указана в их профиле (нельзя заключить договор без обсуждения с ним).
Нужно представить информацию о Персонах в виде объектной модели (набора классов), которая бы позволила наиболее удобно представить информацию о них. Соответственно "база Персон" - это просто массив таких объектов. Тебе нужно спроектировать эти классы. Методы тут писать не нужно, хватит только полей.
Задача про Гостиницу
Есть Гостиница, в ней есть Номера. Для каждого Номера известен его номер, количество Гостей, которое в него влезет, а также цена за сутки. В Гостиницу приезжают Гости. Нужно сделать объектную модель Гостиницы с такими возможностями (методами):
- получить список свободных номеров на определенную дату
- получить список свободных номеров, которые будут свободны в определенный диапазон дат (от A до B)
- дан список Гостей и диапазон дат, в которые они хотели бы заселиться. Необходимо подобрать им самый дешевый (а среди номеров с одинаковой ценой - самый маленький) Номер, который их вместит и который свободен в это время.
- то же самое, но при отстутствии одного подходящего номера для Гостей разрешается заселить их в несколько номеров, опять же, начиная с самых дешевых. Например, приехало 3 Гостя, но все 3-местные номера заняты и мы выделяем 2 2-местных, или 3 1-местных или 1-местный + 2-местный.
- зарегистрировать проживание данных Гостей в данных Номерах на данный период
- получить историю заселения Номера (кто в нем когда жил)
- получить историю заселения Гостя (в каких номерах он жил)
- получить статистику доходов Гостиницы за данный диапазон дат (в день A отдель заработал X тугриков, в день B - Y тугриков и так далее)
Задача про Продюсерское Агенство
Есть ПродюсерскоеАгенство, и оно периодически сотрудничает с разными Персонами для участия в рекламных, музыкальных, кинематографических и других Проектах. Агенству нужно хранить информацию о Персонах, с которыми оно контактировало или планирует контактировать. Тебе поручено создание соответствующей базы данных.
Персоны - это люди, у которых есть какие-то творческие способности. У каждой Персоны есть такие свойства:
- имя
- контактный номер телефона
Кроме того, у них могут быть навыки: Персона может быть Актером, Моделью, Музыкантом, Менеджером.
У Актера в дополнение к обычным свойствам есть свойство: список Фильмов, в которых он снимался
У Музыканта есть свойства: список Групп, в которых он участвует, и список инструментов, на которых он умеет играть
У Модели есть свойства: рост, цвет глаз и цвет волос
У Менеджера (Агент или менеджер по работе с талантами) есть свойство: название Агенства, которое он представляет.
У Актера, Музыканта или Модели может быть свой Менеджер, и эта информация должна быть указана в их профиле (нельзя заключить договор без обсуждения с ним).
Нужно представить информацию о Персонах в виде объектной модели (набора классов), которая бы позволила наиболее удобно представить информацию о них. Соответственно "база Персон" - это просто массив таких объектов. Тебе нужно спроектировать эти классы. Методы тут писать не нужно, хватит только полей.
У тебя в коде уязвимость - SQL инъекция: https://github.com/codedokode/pasta/blob/master/security/sql-injection.md
Что касается твоего вопроса, дополнительные данные в форме можно передать через скрытый input, проще всего передать только id сущности, а текущее время можно получить и на сервере.
Начну с того, что сам я в промышленном коде конечно же использую геттеры/сеттеры, просто потому что у нас так делают все и у меня не те уровень компетенции и положение в команде, чтобы учить кого-то таким спорным вещам. Более того, я считаю что советовать другие подходы нужно только в том случае, если сам на них не одну собаку съел, иначе к моему мнению просто пропадёт доверие.
Ещё я хочу сказать, что в простых приложениях rich domain model не нужна и попросту не оправдывает себя, можно нагенерить код и сопровождать его будет не очень больно. Для более сложных случаев используются репозитории (по сути TDG). Можно делать прям поверх QueryBuilder'а Yii/Laravel, как-то так: https://ideone.com/aYG6ft
И в тех проектах, что я видел на Symfony делают ведь так же само - flush пихают в репозитории, что противоречит persistence ignorance и сводит на нет UnitOfWork доктрины. Однако такой подход решает задачи, только непонятно зачем там доктрина. Кстати, в 3-й доктрине хотят добавить что-то вроде TDG - можно будет сохранить определённую сущность в обход UnitOfWork, не используя flush (не могу нагуглить issue на гитхабе).
Теперь касательно примера с классом User. Нет, там не будет методов setPassword и validate, проверять данные нужно там, где для этого хватает информации (это может быть валидатор, а может быть и AuthService). Проверяются на валидность объекты-пустышки без логики:
- https://stovepipe.systems/post/avoiding-entities-in-forms
- https://stovepipe.systems/post/rethinking-form-development
Rich Domain Model - это не о том, как всё пихать в сущность, это о том, как в коде максимально правдиво отражать требования бизнеса. В сущность не должны добавляться уведомления о смене пароля, нам же нужно SRP соблюдать. Для таких целей есть Domain Events:
- http://enterprisecraftsmanship.com/2017/10/03/domain-events-simple-and-reliable-solution/
- http://udidahan.com/2008/02/29/how-to-create-fully-encapsulated-domain-models/
Мне кажется, что такой подход требует определённых соглашений для распределения файлов по модулям, нужен быстрый способ, позволяющий например найти "всех слушателей события UserRegistered". В системе на ивентах сложно разбираться, для этого думаю нужно не складывать все слушатели в одни папку, а делить систему на модули. Но я пока только изучаю всё это, нужно найти время и написать что-нибудь со сложной логикой (TestHub я не считаю сложным, его просто долго делать, там всё линейно).
Начну с того, что сам я в промышленном коде конечно же использую геттеры/сеттеры, просто потому что у нас так делают все и у меня не те уровень компетенции и положение в команде, чтобы учить кого-то таким спорным вещам. Более того, я считаю что советовать другие подходы нужно только в том случае, если сам на них не одну собаку съел, иначе к моему мнению просто пропадёт доверие.
Ещё я хочу сказать, что в простых приложениях rich domain model не нужна и попросту не оправдывает себя, можно нагенерить код и сопровождать его будет не очень больно. Для более сложных случаев используются репозитории (по сути TDG). Можно делать прям поверх QueryBuilder'а Yii/Laravel, как-то так: https://ideone.com/aYG6ft
И в тех проектах, что я видел на Symfony делают ведь так же само - flush пихают в репозитории, что противоречит persistence ignorance и сводит на нет UnitOfWork доктрины. Однако такой подход решает задачи, только непонятно зачем там доктрина. Кстати, в 3-й доктрине хотят добавить что-то вроде TDG - можно будет сохранить определённую сущность в обход UnitOfWork, не используя flush (не могу нагуглить issue на гитхабе).
Теперь касательно примера с классом User. Нет, там не будет методов setPassword и validate, проверять данные нужно там, где для этого хватает информации (это может быть валидатор, а может быть и AuthService). Проверяются на валидность объекты-пустышки без логики:
- https://stovepipe.systems/post/avoiding-entities-in-forms
- https://stovepipe.systems/post/rethinking-form-development
Rich Domain Model - это не о том, как всё пихать в сущность, это о том, как в коде максимально правдиво отражать требования бизнеса. В сущность не должны добавляться уведомления о смене пароля, нам же нужно SRP соблюдать. Для таких целей есть Domain Events:
- http://enterprisecraftsmanship.com/2017/10/03/domain-events-simple-and-reliable-solution/
- http://udidahan.com/2008/02/29/how-to-create-fully-encapsulated-domain-models/
Мне кажется, что такой подход требует определённых соглашений для распределения файлов по модулям, нужен быстрый способ, позволяющий например найти "всех слушателей события UserRegistered". В системе на ивентах сложно разбираться, для этого думаю нужно не складывать все слушатели в одни папку, а делить систему на модули. Но я пока только изучаю всё это, нужно найти время и написать что-нибудь со сложной логикой (TestHub я не считаю сложным, его просто долго делать, там всё линейно).
Там сейчас треды 1-96 за исключением 14-22. С этими тредами проблема в том, что у них ID пересекаются с ID уже ранне добавленных постов из тредов до 14-го. Мне непонятно, как на старом 2ch.hk вообще такое было возможно.
Я противник событий в серверном коде, так как это добавляет неочевидность в порядок выполнения кода. В Симфони события можно определять в куче мест (services.yml, класс Бандла, где-то в бутстрапе) и хрен найдешь так просто, что происходит в том или ином случае. Лучше все же явно вызвать нужные методы.
Я допускаю использование событий для дополнительных проверок, условно, при сохранении пользователя по postPersist проверять, что какие-то служебные поля заполнены, или что файл аватарки существует.
Также могу принять события, если это какая-то CMS и без них не расширить ее функционал.
Ок.
Там был то ли вайп, то ли потеряли БД и соответственно последние сообщения были потеряны и номера вернулись на несколько дней назад. Если у тебя id с двача используются как primary key то видимо это не очень удачное решение. Можно сделать искуственные id или использовать пару (id треда, id поста).
Сейчас на главной картинки вверху не видны.
Насчет цепочек, там выше писали, что ОП посты мешают, может можно игнорировать ссылки из них? То есть из Оп поста дальше продолжение не идет, и даже сам Оп пост можно не включать.
И тут http://phpclub.tech/pr/chain/1098085/ явно смешались разные цепочки, это наверно из-за моих постов, где я отвечаю на несколько вопросов...
> Если у тебя id с двача используются как primary key то видимо это не очень удачное решение.
Это удобно тем, что если человек пытается зайти в тред, который уже удалён, он может использовать тот же URL для получения треда в архиве.
> Сейчас на главной картинки вверху не видны.
Исправлено.
> явно смешались разные цепочки,
Там же весь граф включается (все достижимые узлы)
> что ОП посты мешают
Да, их наверное нужно исключать.
>>1108766
Уточни пожалуйста где конкретно.
Ну можно разделить id, которые используются в URL и выводятся, и первичный ключ в БД. Я согласен, что так-то удобнее использовать существующие id, где возможно.
По поводу картинок - у них стали названия в виде md5 хеша, а на этой борде они выводятся текстом, например, cat-cafe-osaka.jpg
И еще один совет хотел дать, не знаю, как у вас с этим, но советую автоматизировать все операции вроде деплоя или настройки сервера. Очень помогает, когда приходится менять сервера например. Многие используют ансибл, мне он не нравится, я использую bash скрипты. Ну например, у меня есть скрипт, который разворачивает и настраивает OpenVPN на любом ubuntu сервере за пару минут (с генерацией ключей, конфигов и прочего).
Понял. Для всех тредов, которые парсятся с 2ch-api присутствуют client provided file names: http://phpclub.tech/pr/res/1097438.html
Треды младше парсятся с архивача и там я просто не предусмотрел функции парсинга оригинальных имён, можно добавить. С парсингом было много проблем и не все решены, это всё нужно выписывать куда-то и исправлять постепенно.
> Ну можно разделить id, которые используются в URL и выводятся, и первичный ключ в БД.
Хорошо, нужно сделать.
> советую автоматизировать все операции вроде деплоя
Пока git pull, @foobar писал что поднимет Jenkins, чтобы был автопрогон тестов при пуше в мастер и деплой.
про ООП да, базара нет.
а вот
>try-catch тоже нужно избегать. Проблема в том, что большинство PHP-разработчиков не понимают исключения. Исключения нужно выбрасывать в исключительных ситуациях, которые не должны происходить
что значит "не должны происходить"? это тонкие материи, т.к. они выходят за рамки программирования. многие мудрые люди ответили бы, что если они не должны происходить, но происходят, то это ты неправильно оценил ситуацию. я так понимаю, под этими ситуациями ты имел в виду ошибки в работе программы (недоступна БД, например), но если убрать твою формулировку про "не должны происходить", то вместе с ней уйдет принципиальная разница между этой ошибкой и неверными данными от пользователя. исключения позволяют решить оба этих вопроса.
для примера возьмем валидацию. неправильные данные от пользователя предполагают завершение работы программы на этом месте и вывод сообщения об ошибке пользователю. я для этого использую исключения, т.к. они посредством разных классов исключений и разных блоков try-catch позволяют решать, в каком месте перехватывать и кому показывать сообщения об ошибках - только разработчику, разработчику и пользователю или только пользователю в красивом шаблоне.
также могу сказать, что так делаю не только я, но и, например, разработчики symfony и еще много кто, т.е. да, так делают большинство разработчиков php.
вопросы:
1. чем в данном случае плоха реализация через исключения? ты возможно скажешь, что она семантически плоха, мол видя исключения разработчик должен сразу предполагать исключительно критичные ситуации, но если дело только в этом, то это немного религиозный вопрос. или есть еще причины?
2. как бы в случае валидации сделал именно ты?
3. если ты знаком с другими ООП-языками, то как например такие вещи принято реализовывать в джаве? или они тоже неправильно понимают исключения?
>Здесь легко привести пример, когда это не работает: когда тебе надо сообщить об ошибках в нескольких полях.
да, это во всей ситуации с исключениями для валидации достаточно кривой момент. вот тут https://habrahabr.ru/post/279501/ есть способ решения, что думаешь о таком?
Добавил issue для сбора ошибок в парсере: https://github.com/someApprentice/phpClub/issues/30
Если у вас открытый код на гитхабе, можно бесплатно подключить для тестов (не деплоя) Travis CI. Вот у меня подключено: https://github.com/codedokode/task-checker/blob/master/.travis.yml
Он запускает phpunit, и вот как это выглядит: https://travis-ci.org/codedokode/task-checker/jobs/264686025
При этом в ридми можно поставить зеленый значок, плюс гитхаб будет у каждого коммита и пулл-реквеста показывать статус прохождения тестов:
https://github.com/codedokode/task-checker/commits/master
Для тестов под Windows (если вдруг понадобится) есть appveyour. Им например можно делать сборку сишных проектов под винду и автоматически загружать экзешник в releases.
Имена файлов могут быть в архивах, сохраненных с двача, у меня есть и новые треды тоже, могу скинуть.
Проще просто сделать объект "коллекция ошибок". Хотя с ходу недостатки предлагаемого в статье решения не могу назвать.
>>1108784
Ошибки валидации это не исключения (по моему мнению), так как они ожидаемы. Мы ожидаем, что пользователь может ввести что угодно и программа должна при этом работать корректно.
Исключения - это например, когда не удается соединиться с БД или прочесть файл, который обязан существовать. Или передано отрицательное число в функцию, принимающую только положительные.
В статье на Хабре имхо проще было вернуть ошибку через return чем городить try/catch.
> чем в данном случае плоха реализация через исключения?
Тем, что это замаскированный return
> как бы в случае валидации сделал именно ты?
$errors = validate($data);
> если ты знаком с другими ООП-языками
Это не зависит от языка.
>Тем, что это замаскированный return
на мой взгляд, это уж скорее замаскированный die.
>$errors = validate($data);
можешь привести какие-то примеры из публичного кода? я просто сколько всего не смотрел, такого не видел.
....
function query($pdo){
//get name and other infromation about studen as variables
$FN = $_POST['FirstName'];
$LN = $_POST['LastName'];
$SOP = $_POST['points'];
$query =$pdo->query("INSERT INTO students VALUES('$FN','$LN')");
$names = [$FN,$LN,$SOP];
return $names;
}
foreach($_POST as $key=>$var){
if(!isset($var) ){
$error = true;
}
} if(!($error)){
//get the array containing info about a student
$name = query($pdo);
$string = implode($name);
setcookie("student",$string, time() +15);
$_POST = array();
header("Location:/list.php");
}
....
function query($pdo){
//get name and other infromation about studen as variables
$FN = $_POST['FirstName'];
$LN = $_POST['LastName'];
$SOP = $_POST['points'];
$query =$pdo->query("INSERT INTO students VALUES('$FN','$LN')");
$names = [$FN,$LN,$SOP];
return $names;
}
foreach($_POST as $key=>$var){
if(!isset($var) ){
$error = true;
}
} if(!($error)){
//get the array containing info about a student
$name = query($pdo);
$string = implode($name);
setcookie("student",$string, time() +15);
$_POST = array();
header("Location:/list.php");
}
У тебя там в коде SQL инъекция: https://github.com/codedokode/pasta/blob/master/security/sql-injection.md
По коду, попробуй вывести значения переменных с помощью var_dump (в том числе значение $_POST), а также натыкать echo, чтобы понять, выполняется ли цикл и if.
Спасибо. У меня в шаблонн есть скрытые формы для радио кнопок, так как $_POST не добавлял ключа с пустым значением для них, если не выбрать радио значение. Может быть из-за этого?
Ты же пишешь, что у тебя проблема появляется, даже если ты не отправил форму. Значит, что у тебя в форме, не имеет значения, а проблема где-то в коде. Потому я и предлагаю натыкать echo и var_dump, чтобы увидеть, что в переменных и в каком порядке выполняется код.
У меня была такая идея игнорировать ОП-пост, но помимо них могут быть другие посты с несколькими ответами. Заставить кого-то отвечать разными постами было бы не справедливо.
Вообще икогда не понимал нахрена нужен твиг и это вот всё. Как по мне, какое-то пятое колесо.
зависит от масштаба проекта и количества сотрудников. шаблоны на твиге может править какой-нибудь верстальщик, который не знает, что происходит на уровне фреймворка и php вообще.
может кто-то назовет другие плюсы шаблонизаторов, потому что я принципиальных плюсов (кроме того, что на мой взгляд это изящное решение) больше не знаю.
Ответ написан на главной твига https://twig.symfony.com/
Алсо, урок про шаблонизаторы вообще: https://github.com/codedokode/pasta/blob/master/php/templates.md
вот код с примера документации к api
https://pastebin.com/pfvyy8pr
можете отправить post запрос на $url_for_post с параметрами $params
и показать что пришло в ответ?
просто у меня даж апача не стоит да и настолько хуево знаком с пыхом что минут 20 убил на то, чтоб добавить ключ 'sign' в $params а проверить я ли проебался с переноса примера с php на питон или у них документация к api протухла нужно.
вот как я это вижу на питоне
алсо схуяли у вас хэштейбл объявляется как array? наркоманы...
https://pastebin.com/jEv7C9xD
>а $url_for_post с параметрами $params
>и показать что пришло в ответ?
31 $curl=curl_init();
32 curl_setopt($curl,CURLOPT_RETURNTRANSFER, true);
34 curl_setopt($curl,CURLOPT_URL, $url_for_post);
35 curl_setopt($curl,CURLOPT_CUSTOMREQUEST, 'POST');
36 curl_setopt($curl,CURLOPT_POSTFIELDS, json_encode($params));
37 curl_setopt($curl,CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
38 curl_setopt($curl,CURLOPT_HEADER, false);
39 curl_setopt($curl,CURLOPT_SSL_VERIFYPEER, 0);
40 curl_setopt($curl,CURLOPT_SSL_VERIFYHOST, 0);
41 $out=curl_exec($curl);
42 $code=curl_getinfo($curl, CURLINFO_HTTP_CODE);
43
44 var_dump($out);
45 var_dump($code);
говнокод, понимаю, но тем не менее
$ php tmp.php
string(21) "<p>Page not found</p>"
int(404)
аналогично если не делать json_encode для $params, возвращается
$ php tmp.php
string(216) "<html><body><h1>500 Internal Server Error</h1>If you are the administrator of this website, then please read this web application's log file and/or the web server's log file to find out what went wrong.</body></html>"
int(500)
так что там какое-то наебалово, бро.
>а $url_for_post с параметрами $params
>и показать что пришло в ответ?
31 $curl=curl_init();
32 curl_setopt($curl,CURLOPT_RETURNTRANSFER, true);
34 curl_setopt($curl,CURLOPT_URL, $url_for_post);
35 curl_setopt($curl,CURLOPT_CUSTOMREQUEST, 'POST');
36 curl_setopt($curl,CURLOPT_POSTFIELDS, json_encode($params));
37 curl_setopt($curl,CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
38 curl_setopt($curl,CURLOPT_HEADER, false);
39 curl_setopt($curl,CURLOPT_SSL_VERIFYPEER, 0);
40 curl_setopt($curl,CURLOPT_SSL_VERIFYHOST, 0);
41 $out=curl_exec($curl);
42 $code=curl_getinfo($curl, CURLINFO_HTTP_CODE);
43
44 var_dump($out);
45 var_dump($code);
говнокод, понимаю, но тем не менее
$ php tmp.php
string(21) "<p>Page not found</p>"
int(404)
аналогично если не делать json_encode для $params, возвращается
$ php tmp.php
string(216) "<html><body><h1>500 Internal Server Error</h1>If you are the administrator of this website, then please read this web application's log file and/or the web server's log file to find out what went wrong.</body></html>"
int(500)
так что там какое-то наебалово, бро.
спасибо анончик, пойду до саппорта доебусь
Смотрел, testhub делаю на нём. Вот появились уроки для самых маленьких
https://knpuniversity.com/screencast/symfony4-upgrade/sf34-deprecations?utm_content=buffer7e518&utm_medium=social&utm_source=twitter.com&utm_campaign=buffer
Щас читать буду, а то в некоторых моментах туплю
о, спасибо. жалко, еще не все дописаны, но сохранил в закладки.
пытаюсь разобраться с аутенфикацией Silex + AJAX.
На сервере использую способ аутенф. "form_login" в настройках фаирвола. Из клиентского прилоежения отправляю AJAX запрос с данными _password и _username. Но сервер не аутенфицирует (после отправки формы сервер редиректит на страницу, которая указана в свойстве 'login_path').
Проверял со статичной формой - аутенфикация работает (сервер редиректит на запрашиваемую страницу).
В пикриле инфа о запросах AJAX и обычной формы, я вижу что в AJAX запросе нет отправки Cookie, очевидно это и есть причина?
Как метод аутенфикации использовать в настройках Silex? Пилить свой? Я думал, что должно быть так: есть адрес api, по которму на сервер можно отправить username/password и получить обратно токен. По остальным адресам api, сервер использует токен-аутенфикацию, и клиент отправляет все запросы с токеном, который он получил раннее. А как это делается в реальной жизни?
Код AJAX запроса:
https://github.com/enotocode/birthday_reminder/blob/23ec142c4dcaf8f881a1b3b4cc67fb5307478e17/src/client/services/apiCall.js#L72
Настройки аутенфикации сервера:
https://github.com/enotocode/birthday_reminder/blob/23ec142c4dcaf8f881a1b3b4cc67fb5307478e17/src/server/public/index.php#L54
с отправкой Cookie разобрался, добавив свойство credentials: include в метод fetch.
Но в целом, вопрос как выглядит схема аутенфикации для spa приложения с silex бэк-эндом, остается открытым.
DI - это для передачи зависимостей в объект. Так что да, если у тебя там есть зависимости, то логичнее всего передавать их в конструктор, это не задача класса искать объекты-зависимости самому.
Но если объект - это не зависимость, а какая-то сущность, используемая классом, то ее можно и создавать в конструкторе. Ну например, класс линии может создавать объект "стартовая точка" сам:
class PolyLine
{
private $points = [];
public function __construct($x, $y)
{
$this->points[] = new Point($x, $y);
}
}
Надеюсь, не запутал.
>>1109261
На родном PHP шаблонизаторе писать неудобно, нужно больше знаков набирать и экранирования нет встроенного.
>>1109155
ОП-посты (первый пост в треде) можно смело игнорировать, так как из них продолжить цепочку нереально. А вот что делать с постами, где ответы на несколько постов - тут, конечно, не очень понятно.
Может, строить цепочку только в одну сторону? Ну то есть:
- берем первый пост
- добавляем ответы на него
- для каждого ответа добавляем ответы на них (но не добавляем посты, на которые ссылаются эти посты)
Ну то есть двигаемся по графу связей только в одну сторону, от поста к ответам на него.
>>1108824
Читай комментарии к задаче, пробуй делать хотя бы частично, спрашивай советов в треде.
DI - это для передачи зависимостей в объект. Так что да, если у тебя там есть зависимости, то логичнее всего передавать их в конструктор, это не задача класса искать объекты-зависимости самому.
Но если объект - это не зависимость, а какая-то сущность, используемая классом, то ее можно и создавать в конструкторе. Ну например, класс линии может создавать объект "стартовая точка" сам:
class PolyLine
{
private $points = [];
public function __construct($x, $y)
{
$this->points[] = new Point($x, $y);
}
}
Надеюсь, не запутал.
>>1109261
На родном PHP шаблонизаторе писать неудобно, нужно больше знаков набирать и экранирования нет встроенного.
>>1109155
ОП-посты (первый пост в треде) можно смело игнорировать, так как из них продолжить цепочку нереально. А вот что делать с постами, где ответы на несколько постов - тут, конечно, не очень понятно.
Может, строить цепочку только в одну сторону? Ну то есть:
- берем первый пост
- добавляем ответы на него
- для каждого ответа добавляем ответы на них (но не добавляем посты, на которые ссылаются эти посты)
Ну то есть двигаемся по графу связей только в одну сторону, от поста к ответам на него.
>>1108824
Читай комментарии к задаче, пробуй делать хотя бы частично, спрашивай советов в треде.
Та строчка, которую я написал, $errors = validate($data); это первое, что приходит в голову и я даже не понимаю, зачем нужно искать какие-то примеры кода.
Пожалуйста, вот пример https://symfony.com/doc/current/validation.html
> $errors = $validator->validate($author);
>>1108712
> Для более сложных случаев используются репозитории (по сути TDG). Можно делать прям поверх QueryBuilder'а Yii/Laravel, как-то так: https://ideone.com/aYG6ft
В Симфони, как я помню, репозиторий не имеет доступа к контейнеру и ограничен только работой с БД.
> И в тех проектах, что я видел на Symfony делают ведь так же само
Ну тут я прокомментировать чьи-то чужие решения никак не могу.
Вообще, с flush не все так просто. Например, не сделав flush, ты не можешь получить id новой вставленной сущности, а он может быть где-то нужен.
> можно будет сохранить определённую сущность в обход UnitOfWork, не используя flush (не могу нагуглить issue на гитхабе).
Это можно было сделать и раньше, передав ее в flush(). Не знаю, правда, сохранит ли это связанные с ней сущности.
> Нет, там не будет методов setPassword
В видео такой метод есть.
> Entities should always be in a valid state
Ну это спорная точка зрения. Я помню, пару тредов назад мы поднимали эту тему (всегда валидных сущностей), и я сейчас придумал вариант, где это хорошо работает - это когда у нас readonly, иммутабельные сущности. Там это действительно будет работать.
А вот с формами, я не уверен, что есть смысл делать всегда валидные сущности и потом решать возникшие из-за этого проблемы. Вариант с DTO, конечно, работает, но усложняет код. Я бы его использовал только там, где форма сильно не похожа на сущность.
Плюс, в этом варианте валидацию себя должна делать сама сущность, и это сложно: что, если для валидации нужен доступ к БД? Это неудобно реализовывать. Плюс, код валидации в сущности может дублировать код валидации где-то еще.
> Для таких целей есть Domain Events:
Мне события на сервере не нравятся, так как затрудняют понимание логики программы. На мой взгляд, то, что в сервисах мы можем просто писать последовательность действий - огромное преимущество в сравнении с системой с событиями.
>>1108532
Видимо, это защита от парсинга.
Та строчка, которую я написал, $errors = validate($data); это первое, что приходит в голову и я даже не понимаю, зачем нужно искать какие-то примеры кода.
Пожалуйста, вот пример https://symfony.com/doc/current/validation.html
> $errors = $validator->validate($author);
>>1108712
> Для более сложных случаев используются репозитории (по сути TDG). Можно делать прям поверх QueryBuilder'а Yii/Laravel, как-то так: https://ideone.com/aYG6ft
В Симфони, как я помню, репозиторий не имеет доступа к контейнеру и ограничен только работой с БД.
> И в тех проектах, что я видел на Symfony делают ведь так же само
Ну тут я прокомментировать чьи-то чужие решения никак не могу.
Вообще, с flush не все так просто. Например, не сделав flush, ты не можешь получить id новой вставленной сущности, а он может быть где-то нужен.
> можно будет сохранить определённую сущность в обход UnitOfWork, не используя flush (не могу нагуглить issue на гитхабе).
Это можно было сделать и раньше, передав ее в flush(). Не знаю, правда, сохранит ли это связанные с ней сущности.
> Нет, там не будет методов setPassword
В видео такой метод есть.
> Entities should always be in a valid state
Ну это спорная точка зрения. Я помню, пару тредов назад мы поднимали эту тему (всегда валидных сущностей), и я сейчас придумал вариант, где это хорошо работает - это когда у нас readonly, иммутабельные сущности. Там это действительно будет работать.
А вот с формами, я не уверен, что есть смысл делать всегда валидные сущности и потом решать возникшие из-за этого проблемы. Вариант с DTO, конечно, работает, но усложняет код. Я бы его использовал только там, где форма сильно не похожа на сущность.
Плюс, в этом варианте валидацию себя должна делать сама сущность, и это сложно: что, если для валидации нужен доступ к БД? Это неудобно реализовывать. Плюс, код валидации в сущности может дублировать код валидации где-то еще.
> Для таких целей есть Domain Events:
Мне события на сервере не нравятся, так как затрудняют понимание логики программы. На мой взгляд, то, что в сервисах мы можем просто писать последовательность действий - огромное преимущество в сравнении с системой с событиями.
>>1108532
Видимо, это защита от парсинга.
Нету README.
Нету тестов.
Зачем в каждой папке лежит пустой gitignore?
https://github.com/TheSidSpears/test_hub/blob/master/templates/base.html.twig#L21
> {% if app.request.attributes.get('_route') != 'main' %}
Вот это мне не нравится, почему view лезет куда-то в Request?
https://github.com/TheSidSpears/test_hub/blob/master/templates/_testlist.html.twig
Почему имя файла начинается с подчеркивания?
https://github.com/TheSidSpears/test_hub/blob/master/templates/_testlist.html.twig#L16
> "{{ path('tests', {'tag': tag.name}) }}"
Вот это мне не нравится. Разве не лучше было бы написать getTestsByTagUrl(tag)? Так мы собираем код генерации URL в одном месте, а не размазываем по шаблонам, получаем тайп-хинты, можем делать дополнительные проверки. Можем как-то централизованно влиять на генерацию URL.
> https://github.com/TheSidSpears/test_hub/blob/master/templates/tests/list.html.twig#L8
> 'attr': {
> 'value': searchValue
Что-то выглядит как костыль. Значение в форму в контроллере прописать нельзя?
https://github.com/TheSidSpears/test_hub/blob/master/templates/tests/list.html.twig#L29
> {{ tests.getTotalItemCount }} tests total
Нет выбора правильной формы слова в зависимости от числа.
По переменным окружения - не стоит ли добавить им уникальный префикс вроде TH_..., чтобы они были гарантированно уникальными?
https://github.com/TheSidSpears/test_hub/blob/master/config/packages/twig.yaml#L4
Почему strict_variables включены только в режиме debug? Это может быть субъективное мнение, но я считаю, что это неправильно и даже issue по этому поводу создал: https://github.com/twigphp/Twig/issues/2537
То же самое касается strict_requirements в роутере.
И мне конечно не нравится это море конфигов... труднее разбираться, по моему, стало.
Роуты в аннотациях, на мой взгляд, неудачное и неудобное решение. Ты не можешь легко осмотреть их список, легко допустить перекрытие одного роута другим.
Это мое субъективное мнение, но я не люблю репозитории Доктрины и считаю, что лучше писать свои сервисы, у них возможностей больше, например, есть доступ к контейнеру.
https://github.com/TheSidSpears/test_hub/blob/master/src/Controller/TestsController.php#L23
> // only handles data on POST
> $form->handleRequest($request);
Форма поиска должна работать через GET
https://github.com/TheSidSpears/test_hub/blob/master/src/Controller/TestsController.php#L29
> elseif (!$searchString = $request->query->get('tag')) {
Неудачная идея, по моему, делать присваивание внутри if.
https://github.com/TheSidSpears/test_hub/blob/master/src/Migrations/Version20171208191454.php#L18
Тут charset utf8 стоит, а не utf8mb4
https://github.com/TheSidSpears/test_hub/blob/master/src/Migrations/Version20171208231923.php#L19
Тут избыточные индексы у таблицы test_tag
https://github.com/TheSidSpears/test_hub/blob/master/src/Repository/TestRepository.php#L19
Для не меняющегося запроса, наверно короче будет написать его на DQL.
Нету README.
Нету тестов.
Зачем в каждой папке лежит пустой gitignore?
https://github.com/TheSidSpears/test_hub/blob/master/templates/base.html.twig#L21
> {% if app.request.attributes.get('_route') != 'main' %}
Вот это мне не нравится, почему view лезет куда-то в Request?
https://github.com/TheSidSpears/test_hub/blob/master/templates/_testlist.html.twig
Почему имя файла начинается с подчеркивания?
https://github.com/TheSidSpears/test_hub/blob/master/templates/_testlist.html.twig#L16
> "{{ path('tests', {'tag': tag.name}) }}"
Вот это мне не нравится. Разве не лучше было бы написать getTestsByTagUrl(tag)? Так мы собираем код генерации URL в одном месте, а не размазываем по шаблонам, получаем тайп-хинты, можем делать дополнительные проверки. Можем как-то централизованно влиять на генерацию URL.
> https://github.com/TheSidSpears/test_hub/blob/master/templates/tests/list.html.twig#L8
> 'attr': {
> 'value': searchValue
Что-то выглядит как костыль. Значение в форму в контроллере прописать нельзя?
https://github.com/TheSidSpears/test_hub/blob/master/templates/tests/list.html.twig#L29
> {{ tests.getTotalItemCount }} tests total
Нет выбора правильной формы слова в зависимости от числа.
По переменным окружения - не стоит ли добавить им уникальный префикс вроде TH_..., чтобы они были гарантированно уникальными?
https://github.com/TheSidSpears/test_hub/blob/master/config/packages/twig.yaml#L4
Почему strict_variables включены только в режиме debug? Это может быть субъективное мнение, но я считаю, что это неправильно и даже issue по этому поводу создал: https://github.com/twigphp/Twig/issues/2537
То же самое касается strict_requirements в роутере.
И мне конечно не нравится это море конфигов... труднее разбираться, по моему, стало.
Роуты в аннотациях, на мой взгляд, неудачное и неудобное решение. Ты не можешь легко осмотреть их список, легко допустить перекрытие одного роута другим.
Это мое субъективное мнение, но я не люблю репозитории Доктрины и считаю, что лучше писать свои сервисы, у них возможностей больше, например, есть доступ к контейнеру.
https://github.com/TheSidSpears/test_hub/blob/master/src/Controller/TestsController.php#L23
> // only handles data on POST
> $form->handleRequest($request);
Форма поиска должна работать через GET
https://github.com/TheSidSpears/test_hub/blob/master/src/Controller/TestsController.php#L29
> elseif (!$searchString = $request->query->get('tag')) {
Неудачная идея, по моему, делать присваивание внутри if.
https://github.com/TheSidSpears/test_hub/blob/master/src/Migrations/Version20171208191454.php#L18
Тут charset utf8 стоит, а не utf8mb4
https://github.com/TheSidSpears/test_hub/blob/master/src/Migrations/Version20171208231923.php#L19
Тут избыточные индексы у таблицы test_tag
https://github.com/TheSidSpears/test_hub/blob/master/src/Repository/TestRepository.php#L19
Для не меняющегося запроса, наверно короче будет написать его на DQL.
С аякс-запросом куки отправляются точно так же, как и с обычным. Я вижу так же наличие заголовка Authorisation (HTTP авторизация) в обычной форме. Ты случайно не HTTP-авторизацию включил? Она скорее всего не будет работать при отправке аякс-запроса (ну или тебе надо как-то вручную там формировать заголовок Authorisation).
Если что, в мануале также есть совет:
> When a security configuration does not behave as expected, enable logging (with the Monolog extension for instance) as the Security Component logs a lot of interesting information about what it does and why.
> Как метод аутенфикации использовать в настройках Silex? Пилить свой? Я думал, что должно быть так: есть адрес api, по которму на сервер можно отправить username/password и получить обратно токен. По остальным адресам api, сервер использует токен-аутенфикацию, и клиент отправляет все запросы с токеном, который он получил раннее. А как это делается в реальной жизни?
Если речь о веб-приложении, то там проще всего использовать куки, то есть та же схема, что для не-SPA приложений. Плюс в том, что она работает прозрачно и единственное, что требует, это определять состояние разлогиненности и показывать форму входа. Также, для куки можно ставить интересные флаги вроде http_only.
Если речь о публичном API, то имхо, проще тут посылать данные авторизации с каждым запросом (следуя правилу stateless из REST).
На практике, в API обычно используют для безопасности не пароли, а токены, у которых часто может еще быть ограниченный набор полномочий (если украсть токен, то полноценного доступа к аккаунту не получаешь, плюс можно эти токены легко отзывать, когда, например, разработчик увольняется). Токены пользователь получает вручную и они не устаревают.
То, что ты предложил, выглядит как усложнение, нам надо следить за этими токенами, продлевать их итд. При этом по сути это то же самое, что токен в куках.
> В Симфони, как я помню, репозиторий не имеет доступа к контейнеру и ограничен только работой с БД.
Вот список различных способов регистрировать репозитории: https://www.tomasvotruba.cz/blog/2017/10/16/how-to-use-repository-with-doctrine-as-service-in-symfony/
В SF4 влепили какой-то костыль и теперь можно использовать репозитории как сервисы: https://symfony.com/doc/current/doctrine.html#querying-for-objects-the-repository
> Это можно было сделать и раньше, передав ее в flush().
Это удалят в Doctrine 3 из-за багов: https://github.com/doctrine/doctrine2/issues/6118
Касательно всего остального - мне нужно написать нормальное приложение с таким подходом и тогда я отпишу о результатах.
Вы видите копию треда, сохраненную 21 декабря 2017 года.
Скачать тред: только с превью, с превью и прикрепленными файлами.
Второй вариант может долго скачиваться. Файлы будут только в живых или недавно утонувших тредах. Подробнее
Если вам полезен архив М.Двача, пожертвуйте на оплату сервера.