Это копия, сохраненная 24 ноября 2018 года.
Скачать тред: только с превью, с превью и прикрепленными файлами.
Второй вариант может долго скачиваться. Файлы будут только в живых или недавно утонувших тредах. Подробнее
Если вам полезен архив М.Двача, пожертвуйте на оплату сервера.
Тут мы изучаем язык PHP (а также JS/CSS/HTML/SQL), решаем задачки, печем печенье и даже делаем простые сайты! Зачем? Кто-то хочет изменить мир, кто-то заработать на лапшу быстрого приготовления, кому-то просто нечего делать.
Да, в нашем треде отвечают почти на все вопросы, только бампайте каждые 5 дней. И не разводите флуд, если вам скучно, сходите погуляйте, например. Может вас побьет какой-нибудь хороший человек и вы перестанете флудить в нашем треде.
Это тред для начинающих. Не написал за свою жизнь ни одной программы и имеешь тройку по математике? Ты наш человек.
Предыдущий тред был тут: >>1232710 (OP) (OP) . Остальные треды есть в архиве: https://phpclub.tech/ (там есть поиск, так что можно легко найти обсуждение какой-то задачи или ответы на свой старый пост) или ищутся в гугле по словам "клуб изучающих php" и в архиваче.
Мейлач лежит, модератор зверствует? Есть запасной тред на доброчане: /s/res/23225.xhtml#i46467
Форматируй свой код, если хочешь, чтобы его читали (как, написано во втором посте).
Правила: ведем себя воспитанно, помогаем новичкам, читаем учебники, решаем задачки, постим ссылки на решения, ОП их проверяет и дает советы и замечания. ОП заходит редко, где-то раз в 2-3 дня, у него мало времени, не жди его, решай задачки дальше. ОП отвечает на все вопросы по его задачкам и учебнику, а вот насчет каких-то других вещей - только если останется время. Но в треде немало анонимных экспертов разного уровня, так что вряд ли вопрос останется без ответа.
С чего начать
У нас есть свои уроки по основам PHP, они собраны и выложены по адресу http://codedokode.github.io/phpbook (вас отредиректит на другой домен, не читайте, не сохраняйте, не запоминайте его, он временный). Это учебник для изучающих с нуля, то есть если ты вообще ничего не знаешь, то можно начать с него. Он простой и понятный. Там есть задачи, их нужно решать (чтобы стать программистом, надо писать код — иначе никак). Пости ссылки на решения в тред, мы их проверим, напишем замечания и дадим советы по улучшению. С другой стороны, если этот учебник тебе не нравится, можно читать любой другой. Или официальный мануал. Или все сразу.
Устанавливать пока что ничего не требуется, разве что редактор кода вроде 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
Решения задач лучше показать мне, особенно на ООП,так как сам ты вряд ли увидишь все ошибки. Пости свой код на гитхаб и вкидывай ссылку в тред по мере решения. Я прокомментирую и укажу на ошибки.
Параллельно стоит подучивать английский, на первых порах можно без него, но по мере развития придется все чаще сталкиваться с англоязычными статьями, так что лучше не откладывать. Читать можно news.ycombinator.com - это что-то вроде их хабра. Также можно начинать смотреть фильмы и видео на английском.
Также, у нас есть задачи которые позволят тебе изучить или подтянуть до нормального уровня знания 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
- Новости IT на англ. https://news.ycombinator.com/
- какой-то древний, устаревший, но большой и на русском справочник по веб-разработке, посоветованный аноном: https://starcat.dp.ua/doc/wdh/
Оформляй код аккуратно!!! — например пропусти через 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
> I am $age years old
Чому переменную не обрамляете фигурными скобками? Раньше это было чуть ли не стандартом: ${var} или {$var} в строке.
Пишу переменные в фигурных скобках в тексте. Учился по какой то олдовой книге, с тех пор так и пишу.
Держи вкурсе
ideone не работает с mb функциями. Если тебе принципиально решение на идеоне, сделай проверку тождества через регексп с флагом игноркейсом.
>- дан список слов в массиве, например: $words = ['кошка', 'кит', 'собака']. Список слов может быть любым, не только как в примере.
>- надо сгруппировать эти слова по первой букве и вывести (в первой строчке все слова на одну букву, во второй на другую, итд). Сортировать по алфавиту не требуется, выводить можно в любом порядке. Например, для слов выше программа должна вывести:
>К: кошка, кит
>С: собака
Код: jdoodle.com/a/G3e
Тащемта для всего алфавита нужен один if, 32 else if и else если в массиве первая буква не кириллический символ, а что-то другое.
>> Откуда такая любовь к laravel?
> Компонент-бейзед
Это на словах, а по факту ты получаешь сильно связанные компоненты, которые в отрыве от фреймворка работать не будут. Компоненты Symfony гораздо более независимые и реюзабельные. Например Symfony Validator требует только общий пакет для интерфейсов (symfony/contracts) и опциональные полифиллы для PHP расширений mbstring и ctype (если в 2018-м у тебя по какой-то причине нет возможности установить их в PHP): https://github.com/symfony/validator/blob/master/composer.json
А вот валидатор Laravel: https://github.com/laravel/framework/blob/5.6/src/Illuminate/Validation/composer.json
Он требует наличия DI-контейнера Laravel (!), пакет переводов Laravel, непонятно зачем слой для работы с HTTP запросами/ответами (symfony/http-foundation), illuminate/support (ненужный мусорник: http://mattallan.org/posts/dont-use-illuminate-support/)
> современные паттерны
Monkey-patch, магические и статические методы повсюду + трейты это паттерны фанбоев, бросающихся на цветные фантики: https://blog.ircmaxell.com/2011/07/are-traits-new-eval.html
Всё это делает исходники фреймворка месивом из переплетающихся трейтов и магических методов, где IDE без костылей не может статически понимать код: https://github.com/barryvdh/laravel-ide-helper
Я даже боюсь статические анализаторы кода вроде Psalm и Phan подрубать к Laravel, они ведь обезумеют от увиденного.
> адекватный порог вхождения
Адекватный для кого, для совсем нулячих в PHP? Потом они из-за отсутствия фундаметальных знаний лезут на форумы / в чаты с тупыми вопросами, которые относятся не к фреймворку, а как базовым знаниям PHP и БД.
Я не тот анон, но спасибо что ответил.
Как в задаче про банкомат проверить, достаточно ли купюр для выдачи?
Сделал граммар нази и опечаточники. Итак.
1) Граммар нази. Тут у меня есть ощущение, что я как-то не аутентично использую функции для работы с регулярками + там же надо делать исправление больших букв и я его добавил отдельным правилом т.е. не оче умно. Но т.к. я уже долго в этом вожусь - оставил как есть.
Задача: https://ideone.com/OW5uJV
2) Опечаточники. Тут ты, ОП, в спойлере у задачки оставил примеры текстов - которые добавляют дополнительные условия, т.е. в слове может быть несколько опечаток, или англ.символы могут идти подряд, что заставляет переписывать регулярки и код. Кароче пока тоже оставил как есть.
Задача: https://ideone.com/KmRlPx
P.S. В общем мне нужен пример решения, хочется двигаться дальше. ОП'чик скинь мне на мыло
Скинул, тебе за щеку.
ОП-треда, который проверяет задачки, потерялся.
Просто загугли задачки и посмотри как у других.
Warning: mysqli_connect(): PHP was built without openssl extension, can't send password encrypted in C:\Apache24\htdocs\lab4.php on line 2
"Лиличка" - https://3v4l.org/9nNiF
Приступил к следующей задачке, и обосрался еще раз.
Как вывести столбцы рядом друг с другом, а не все в один большой столбец?
а хуль у них на официальном сайте такое гамно лежит без поддержки openssl?
https://windows.php.net/download/ скачивал VC15 x64 Thread Safe 7.2.10
да я и не умею собирать
Я ебу чому они без опенссл выкладывают сборки? Я на прыщах всегда сам собирал рнр с нужными мне модулями. Вот читай как выйти из твоего положения http://php.net/manual/ru/openssl.installation.php
Привет, анон. Сдавал задание на галеру одну и мне сказали что хуйня, можешь глянуть краем глаза что не так? Они не отвечают
А как надо?
скобки не нужны ровно до тех пор пока не понадобится вплотную написать текст к значению переменной и подобное
printf следует использовать для _форматированного_ вывода только когда нужен _форматированный_ вывод, как бы нелогично не звучало
Твои слова расходятся с написанным в шапке.
Чем форматированная строка хуже echo? Как по мне, проще самому управлять выводом. Особенно, когда используешь строгую типизацию. Приучает к дисциплине и ещё больше походит на божественный Си.
>строгую типизацию
Сынок, потише в этом треде с умными словами, особенно когда не знаешь значений
У твоей "божественной" Си слабая типизация как и у ПХП
В смысле?
int i = 2; это разве не строгая типизация?! Или когда в аргументах функции пишешь что-то навроде float d = 5.
Она не хуже - она другая. Безопасность типов она между тем не обеспечивает.
Подумой, как говорится.
https://pastebin.com/9EUE9heZ
declare(strict_type=1)
string $username = “Pinnacle”;
printf(“Hello %s!”, $username);
Разве это не максимально безопасный код? Типа в ручную управляешь типом данных, чуть что интерпритатор сразу дропает выполнение кода с ошибкой.
Да, Reference Manual скомпиленный в CHM с комментариями.
>int i = 2; это разве не строгая типизация?
Нет. Это статическая.
Просвещайся.
https://habr.com/post/161205/
Речь идет об mysql, если что.
Да, так бесит эта MySQL, был баг, что одним запросом формы, создавалось 2 записи в таблице, 10 раз перепроверил метод который создаёт запись в таблице, ничего не нашел.
Потом психанул написал запрос на этой же странице, и все стало нормально создавать. Или когда уже уставший пишешь запрос и где-то проебал запятую в SQL запросе, то это пиздец, потом в куче текста эту запятую хуй найдёшь.
Да, в этом проблема была. Начинал ставить одинарные кавычки, оказалось, что надо `.
Мне надо вывести определённое количество новостей на странице, я вывожу их таким способом
while($row = $result->fetch_array(MYSQLI_ASSOC)
....код
}
Но как ограничить вывод допустим 3 штуками на страницу?
В чем дело, почему программа возвращает ложное значение?
10 же больше чем 6.
>echo "У анона выпало ($anonDice1) и ($anonDice1)\nУ компьютера ($compDice1) и ($compDice2)\n";
Блин так и знал что в галза долблюсь. Я даже не заметил что всегда даблы выпадают.
Блин, точно. Забыл за LIMIT спасибо.
Ничего страшного, годик попревозмогаешь и вкатишься в Питере за 7к в месяц и обеды соленым немытым хуем лошка, вкатившегося годом ранее тебя и носящим лычку миддла.
Через пару лет мб дослужишься до компенсации проезда на маршрутке. А там глядишь и в дойче банк позовут. И все у тебя будет хорошо. Нет, конечно, ты умрешь бомжом в Гатчине на кухне съемной однокомнатной халабуды от передоза героином
Какой ты токсичный, анон. Плохо быть тобою, плохо.
>Uncaught TypeError: Return value of StudentMapper::searchEmail() must be an instance of boolean, boolean returned
Почему тут все обмазываются дойче банком? Зарплата на пикриле нищенская по немецким меркам.
В Германии столько дворники получают.
Потому что кое кто живет слухами. Работники дойч банков экономят каждую копейку. У меня каждый месяц получается откладывать всего 100-200 евро. Отдел програмистов в банке не намного лучше живет, зарплата всего 300- 400 евро больше.
В PHP5 нельзя в тайп-хинтах использовать примитивные типы вроде int, он их понимает как имена классов. Советую обновиться до PHP7.
Пиздец
Выше говорят, что это статическая типизация. Правда я так особо и не вкурил в чём радикальное отличие статической/слабой типизации от сильной/строгой. Что-то пишут овердохуя про ООП, но я ниасилил. Может в ООП это и есть слабая типизация, а на уровне объявления переменных не является таковой.
В любом кроме двух ДС.
Допустим я хочу чтобы бот оправил сообщение в конфу.
$send = fopen("https://api.telegram.org/bot{$token}/sendMessage?chat_id={$chat_id}
&parse_mode=html&text={$txt}","r");
Выдает ошибку. Хелпаните ньюфагу.
>>1269732
Но блин там же много файлов, и не хочется весь этот позор на гит выкладывать
По гуглу и официальным документациям. Что интересно - в то и ныряю. К сожалению, за ручку как ОП никто не водит.
Урывками оооочень давно, иногда забивается на по полгода. Это интересное хобби. Жаль разделить не с кем.
Каким образом?
фвй
Кстати, любопытная ссылка: правила выбора формы слова в зависимости от числа (1 человек, 2 человека, 5 человек) в разных языках: http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html
Анон с TDG, интересная штука, попоробую посмотреть позже.
https://pastebin.com/bZ8iHwsK
Горжусь тем, что впендюрил рекурсию (никогда не понимал, что это за херь вообще, а после того, как нафармил 4кю на кодеварсах более-менее вкурил, и поди ж ты, уже в задачках использую как щеголь!)
Не горжусь уебищными тернарниками для решения вопросов пола. Надо было на стадии, когда с числами работал внутри рексурсии, как автор советовал, решать, т.к. потом после обработки массива с числительными у меня уже не числа, а строки, пришлось матчить регекспом.
>Плюс, ты делаешь ошибку, $i[0] возвращает первый байт строки, а не первый символ, и многие символы в utf-8 занимают больше одного байта, так что ты можешь получить огрызок вместо символа. Лучше использовать mb_substr().
Да, я пропалил этот момент на примере с кавычкой, почему и сделал каличный подгон ^"?\w вместо просто ^\w, более тщательно можно было бы ^(\W+)?\w чтобы не только кавычки учесть.
А как через сабстр? Все равно же нужно знать порядковый номер, а он у первой буквы может быть рандомным, если там десяток точек или кавычек предшествует?
>Ну или сделать регулярку, ищущую слова из букв разных алфавитов.
Ты имеешь в виду ограничиться флагом /u или делать полноценные [aá] и т.д.?
https://ideone.com/Grtrs6
В который раз переделал задачу с текстовыми/числовыми вопросами. Проверьте, плз.
У меня возникли глупенькие вопросы.
1. Тайп-хинты на вход и выход, нужно стараться использовать везде где есть функции?
2. Как перехватить с помощью try-catch, ошибку возникшую из-за неправильно переданного типа? Заменить тайп-хинт на проверку внутри функции, которая будет выбрасывать исключение?
3. Решаю сейчас ООП-будильник, потом нужно будет решать Вектор или эти задачки взаимозаменяемые?
Да уш, тяжело смотреть на него после php. Но он достоин любви.
>>69803
>Идея хранить содержимое теста в виде JSON мне не очень нравится, так как не будут работать внешние ключи (например, на выбранный вариант ответа) и не контролируется структура содержимого - а это значит, там быстро начнут накапливаться ошибки
Сами вопросы хранить в отдельной таблице( один(Тест) ко многому) и варианты ответа то же в отдельной таблице(один(Вопрос) ко многому)
Так что ли?
>1. Тайп-хинты на вход и выход, нужно стараться использовать везде где есть функции?
Да.
>2. Как перехватить с помощью try-catch, ошибку возникшую из-за неправильно переданного типа? Заменить тайп-хинт на проверку внутри функции, которая будет выбрасывать исключение?
>проверку внутри функции
Довен, тайпхинты как раз существуют, чтобы эти проверки РУКАМИ не делать?
Сделаешь , ты условие if(!is_bool){ throw new \RuntimeException("Не верный тип");, и чем это будет отличаться от ошибок которые выдает тебе интрепретатор?
Если типы не совпадают, то их нужно как-то приводить к нужному типу перед передачей в функцию.
Еще тайпхинты дают ахуенную подсказку при работе с IDE.
Можешь и в одной, если количество вариантов ответов везде одинаково. Id вопроса, вопрос, правильный ответ, неправильный ответ №1, неправильный ответ №2, неправильный ответ №3. А при выводе ответы перемешивать.
Как блять поисковые связаны с тем что язык жив или нет?
У него блядский вырвиглазный синтаксис, как на нём вообще можно писать скрипты, код невозможно читать.
Ага, всякие очевидные вещи перечитывать и только потому что синтаксис отличается
Безработица.
https://ideone.com/NhFrF5
Ошибка:
>PHP Fatal error: Constant expression contains invalid operations in /home/Gc2l35/prog.php on line 4
Ну мне трудно представить, как это все выглядит.
Нихуя себе
Из-за ркн мой бот не хочет работать, как сделать так, чтобы бот отправлял сообщения через прокси?
Заебался уже копаться в этом говне и активаторах, ни один из которых не работает.
Зачем там активатор? Есть куча левых license server. Да и просто код можно найти и добавить их сервер в хостс чтоб он не проверялся и шторм считал что он лицензионный.
Вот следующие задание буду с чужими СSS делать, а студентов закончу со своими.
тогда не нужно, пусть эти жиды сами им пользуются
90 за 1 год
Да это понятно, проблемы начинаются, когда при повторных нажатиях надо менять тип сортировки.
Можно.
Довольно неплохо!
Внутри какого условия, условия цикла, или имелось в виду что то другое? Если условие if, то оно уже есть.
Тебе нужно другое условие. Если долг + проценты меньше ежемесячного платежа, то выплатить оставшееся, вывести свое ехо и кинуть break;
goto называется.
Ща отдохну и попробую, а то уже 4 часа пытаюсь и голова заболела.
Нужно выводить ссылку с учетом текущего типа сортировки. То есть если выбрана сортировка -name, то надо выводить в заголовке +name вместо -name.
Не проще поставить и настроить netbeans for PHP или Eclipse for PHP? Лицензионно и бесплатно.
Я итак на нетбинсе, но шторм вне конкуренции, он слишком охуененн.
DON'T USE A LICENSE SERVER
add 0.0.0.0 account.jetbrains.com to your host file
and get a key from http://idea.lanyus.com/getkey
DISSCONNECT FROM INTERNET
Run jetbrain product, Paste the key into license section
then activate product
Connect to internet Again
Welcome to 2018.2
https://pastebin.com/EsM3d1e8
> return $op==='+'?$result+$number:($op==='-'?$result-$number:$result*$number);
Здесь лучше использовать блок if/elseif, так как длинное выражение трудно читать.
А так, хорошо, что ты вынес вычисление в функцию. Сделано верно.
>>70146
Тыж программист, подумай, как это аккуратно сделать.
>>69962
Если ты используешь fopen (довольно странный выбор), то почитай про контексты потоков: http://php.net/manual/ru/stream.contexts.php
>>69940
Можно указать значение по умолч. null и в функции сделать проверку:
function t($x = null)
{
if ($x === null) {
$x = ....;
}
...
}
> return $op==='+'?$result+$number:($op==='-'?$result-$number:$result*$number);
Здесь лучше использовать блок if/elseif, так как длинное выражение трудно читать.
А так, хорошо, что ты вынес вычисление в функцию. Сделано верно.
>>70146
Тыж программист, подумай, как это аккуратно сделать.
>>69962
Если ты используешь fopen (довольно странный выбор), то почитай про контексты потоков: http://php.net/manual/ru/stream.contexts.php
>>69940
Можно указать значение по умолч. null и в функции сделать проверку:
function t($x = null)
{
if ($x === null) {
$x = ....;
}
...
}
Хороший повод получше освоить CSS. Формы можно делать так:
<div class="f-row">
<div class="f-label">...</div>
<div class="f-widget">...</div>
</div>
Выровнять f-label/f-widget горизонтально можно с помощью display: inline-block, float, display: table, flexbox, и наверно как-то еще. Не забудь предусмотреть область для показа ошибок.
>>69861
Да, логично сделать таблицу для вопросов и для вариантов ответов (для тех вопросов, где они есть). Вопросы бывают разных типов с разными полями - и есть несколько паттернов наследования таблиц для их реализации.
>>69810
В общем, хорошо. Хотя, мне кажется, лучше бы если за определение числа баллов отвечал бы объект-вопрос. Он ведь знает правильный и почти правильный ответ, число баллов, наверняка может и сам посчитать сколько баллов полагается за ответ. Плюс, можно было бы сделать разные алгоритмы определения числа баллов для разных вопросов. Но твой вариант тоже годится.
> 1. Тайп-хинты на вход и выход, нужно стараться использовать везде где есть функции?
Да, чем больше тайп-хинтов, тем лучше. Они документируют код, он становится понятнее, и позволяют раньше обнаруживать ошибки в программе.
> 2. Как перехватить с помощью try-catch, ошибку возникшую из-за неправильно переданного типа?
Вообще, при неправильном типе поведение зависит от версии PHP. Дело в том, что в PHP, кроме исключений, есть еще "ошибки": notice, warning, fatal error, которые не являются исключениями и не ловятся try/catch (но ловятся при желании специальным обработчиком ошибок). Они по умолчанию пишутся в лог, могут выводиться на экран, и могут завершать или не завершать скрипт (в зависимости от уровня ошибки). Информацию можно поискать тут: http://php.net/manual/ru/book.errorfunc.php
Немного про них написано тут: http://anton.shevchuk.name/php/php-for-beginners-error-handling/
Некоторые фреймворки просто преобразовывают их в исключения, как описано тут: http://php.net/manual/ru/class.errorexception.php
В PHP7 часть фатальных ошибок была заменена на выброс исключения.
Соответственно, поймать такую ошибку сложно, если учесть, что она фатальная и завершает скрипт. Надо ставить обработчик ошибок, а в нем анализировать сообщение об ошибке (либо ловить исключение и анализировать его текст). Проще использовать предложенный тобой вариант (убрать тайп-хинт). Хотя я не представляю, когда нужно их перехватывать.
> 3. Решаю сейчас ООП-будильник, потом нужно будет решать Вектор или эти задачки взаимозаменяемые?
Решай в любом порядке, но лучше решить обе. Вектор посложнее.
Хороший повод получше освоить CSS. Формы можно делать так:
<div class="f-row">
<div class="f-label">...</div>
<div class="f-widget">...</div>
</div>
Выровнять f-label/f-widget горизонтально можно с помощью display: inline-block, float, display: table, flexbox, и наверно как-то еще. Не забудь предусмотреть область для показа ошибок.
>>69861
Да, логично сделать таблицу для вопросов и для вариантов ответов (для тех вопросов, где они есть). Вопросы бывают разных типов с разными полями - и есть несколько паттернов наследования таблиц для их реализации.
>>69810
В общем, хорошо. Хотя, мне кажется, лучше бы если за определение числа баллов отвечал бы объект-вопрос. Он ведь знает правильный и почти правильный ответ, число баллов, наверняка может и сам посчитать сколько баллов полагается за ответ. Плюс, можно было бы сделать разные алгоритмы определения числа баллов для разных вопросов. Но твой вариант тоже годится.
> 1. Тайп-хинты на вход и выход, нужно стараться использовать везде где есть функции?
Да, чем больше тайп-хинтов, тем лучше. Они документируют код, он становится понятнее, и позволяют раньше обнаруживать ошибки в программе.
> 2. Как перехватить с помощью try-catch, ошибку возникшую из-за неправильно переданного типа?
Вообще, при неправильном типе поведение зависит от версии PHP. Дело в том, что в PHP, кроме исключений, есть еще "ошибки": notice, warning, fatal error, которые не являются исключениями и не ловятся try/catch (но ловятся при желании специальным обработчиком ошибок). Они по умолчанию пишутся в лог, могут выводиться на экран, и могут завершать или не завершать скрипт (в зависимости от уровня ошибки). Информацию можно поискать тут: http://php.net/manual/ru/book.errorfunc.php
Немного про них написано тут: http://anton.shevchuk.name/php/php-for-beginners-error-handling/
Некоторые фреймворки просто преобразовывают их в исключения, как описано тут: http://php.net/manual/ru/class.errorexception.php
В PHP7 часть фатальных ошибок была заменена на выброс исключения.
Соответственно, поймать такую ошибку сложно, если учесть, что она фатальная и завершает скрипт. Надо ставить обработчик ошибок, а в нем анализировать сообщение об ошибке (либо ловить исключение и анализировать его текст). Проще использовать предложенный тобой вариант (убрать тайп-хинт). Хотя я не представляю, когда нужно их перехватывать.
> 3. Решаю сейчас ООП-будильник, потом нужно будет решать Вектор или эти задачки взаимозаменяемые?
Решай в любом порядке, но лучше решить обе. Вектор посложнее.
Я имею в виду, искать слова, где есть буквы и латинницы, и кириллицы одновременно. Флаг u нужен в любом случае, он лишь говорит о работе с кодировкой utf-8 и нужен по сути всегда.
>>69808
Я имел в виду вместо $i[0] использовать mb_substr($i, 0, 1) - это корректный код, так как он берет первый символ, а не первый байт. $i[0] это некорректно и описанную тобой проблему (символы в начале строки) никак не решает.
Что касается символов в начале строки - можно разбивать текст так, чтобы предложения всегда начинались с буквы. Или использовать preg_replace_callback с регуляркой, которая ищет именно первую букву предложения, а не первый символ.
>>69806
> define('AMOUNT','(' . $number . ')');
Это плохая идея. Константу можно определить только один раз и при втором вызове функции произойдет ошибка. Также, в PHP7 используется слово const для определения константы. Тем более у тебя это не константа вообще - так как ее значение не постоянно, а зависит от переданного числа. Константы это неизменные значения. А в твоем случае нужна обычная переменная.
В общем:
- константы не создаются в функциях. Это ненормально, что функция меняет какие-то глобальные значения и не позволяет вызвать себя второй раз.
- константы это неизменные значения, а не то что у тебя
> if ($opNumber/100>=0) {
В чем смысл этого условия? Оно равносильно $opNumber >= 0.
> $firstDigit=floor($opNumber/100); $opNumber-=$firstDigit100; $firstDigit=$spelling[$firstDigit100];
Не пиши несколько команд в 1 строку, тяжело читать.
> $firstDigit=$spelling[$firstDigit*100];
Не надо использовать одну переменную для 2 разных типов значений (для числа и для строки) - это лишь усиливает путаницу.
> $x=($firstDigit&&$firstDigit!='ноль'?"$firstDigit ":'') . ($secondDigit&&$secondDigit!='ноль'?"$secondDigit ":'') . ($lastDigit&&$lastDigit!='ноль'?"$lastDigit":'');
Это нечитаемо. Тут надо использовать if/else. Также, не стоит делать сравнение со строкой. Надо было куда-то сохранить первую цифру и проверять именно ее, а не результат преобразования ее в строку. Это костыль, он сломается, если например мы поменяем написание слов или напишем их на другом языке.
> function numberToText($number,$arr=[]) {
Непонятно, зачем передавать сюда $arr. И название выбрано плохое - arr ничего не значит.
Рекурсия по моему только осложняет понимание кода. У тебя и так большая, сложная функция, и ты еще сильнее усложняешь ее. Более того, в ней тут нет никакой необходиомсти и без нее код будет только проще и читабельнее.
И еще одна проблема. Программа тут довольно сложная, и для понятности стоит разбить ее на отдельные части-функции. Так, чтобы мы могли каждую функцию рассматривать отдельно, не глядя на другие. И , например, редактировать одну функцию, не трогая другие. Чтобы каждая функция решала какую-то свою задачу.
Надо учиться разбивать задачу на подзадачи. Делать код максимально простым и понятным.
Ты же не очень к этому стремишься и сделал одну огромную функцию numberToText. Надо разбить ее на составляющие. Не надо писать стену кода.
> $preString=preg_replace('/два тысячи/u','две тысячи',$preString);
Это кривые костыли, затрудняющие понимание кода. Ну представь, человек начнет разбирать твой код, увидит, что он генерирует строку "два тысячи", подумает, что в нем ошибка. И только потом, может, увидит, что в конце эта ошибка костылем испрвляется. Но почему нельзя сделать, чтобы там сразу бралось правильное слово? Зачем усложнять все и запутывать читателя? Так не годится.
> $preString="" . ($arr[2]?
preg_match('/(два|три|четыре)$/u',$arr[2])?"{$arr[2]} миллиона":(preg_match('/(один)$/u',$arr[2])?"{$arr[2]} миллион":"{$arr[2]} миллионов")
Это невозможно читать. Слишком запутанно. Необходимо переписать.
В общем, задачу, увы, надо переделать. Я такое принять не могу, ты должен думать о тех, кто будет читать твой код, чтобы им было проще разобраться в нем.
Если ты не знаешь, как разбить код на части, могу предложить один вариант (другие варианты тоже допустимы):
- делаем функцию выбора формы слова (тысяча, тысяч) в зависимости от числа
- делаем функцию, которая преобразует число от 0 до 999 в строку
- делаем функцию, которая разбивает большое число на части и записывает его, вызывая функции выше
У каждой функции должна быть своя задача, и логичный, простой набор аргументов и возвращаемых значений.
Я имею в виду, искать слова, где есть буквы и латинницы, и кириллицы одновременно. Флаг u нужен в любом случае, он лишь говорит о работе с кодировкой utf-8 и нужен по сути всегда.
>>69808
Я имел в виду вместо $i[0] использовать mb_substr($i, 0, 1) - это корректный код, так как он берет первый символ, а не первый байт. $i[0] это некорректно и описанную тобой проблему (символы в начале строки) никак не решает.
Что касается символов в начале строки - можно разбивать текст так, чтобы предложения всегда начинались с буквы. Или использовать preg_replace_callback с регуляркой, которая ищет именно первую букву предложения, а не первый символ.
>>69806
> define('AMOUNT','(' . $number . ')');
Это плохая идея. Константу можно определить только один раз и при втором вызове функции произойдет ошибка. Также, в PHP7 используется слово const для определения константы. Тем более у тебя это не константа вообще - так как ее значение не постоянно, а зависит от переданного числа. Константы это неизменные значения. А в твоем случае нужна обычная переменная.
В общем:
- константы не создаются в функциях. Это ненормально, что функция меняет какие-то глобальные значения и не позволяет вызвать себя второй раз.
- константы это неизменные значения, а не то что у тебя
> if ($opNumber/100>=0) {
В чем смысл этого условия? Оно равносильно $opNumber >= 0.
> $firstDigit=floor($opNumber/100); $opNumber-=$firstDigit100; $firstDigit=$spelling[$firstDigit100];
Не пиши несколько команд в 1 строку, тяжело читать.
> $firstDigit=$spelling[$firstDigit*100];
Не надо использовать одну переменную для 2 разных типов значений (для числа и для строки) - это лишь усиливает путаницу.
> $x=($firstDigit&&$firstDigit!='ноль'?"$firstDigit ":'') . ($secondDigit&&$secondDigit!='ноль'?"$secondDigit ":'') . ($lastDigit&&$lastDigit!='ноль'?"$lastDigit":'');
Это нечитаемо. Тут надо использовать if/else. Также, не стоит делать сравнение со строкой. Надо было куда-то сохранить первую цифру и проверять именно ее, а не результат преобразования ее в строку. Это костыль, он сломается, если например мы поменяем написание слов или напишем их на другом языке.
> function numberToText($number,$arr=[]) {
Непонятно, зачем передавать сюда $arr. И название выбрано плохое - arr ничего не значит.
Рекурсия по моему только осложняет понимание кода. У тебя и так большая, сложная функция, и ты еще сильнее усложняешь ее. Более того, в ней тут нет никакой необходиомсти и без нее код будет только проще и читабельнее.
И еще одна проблема. Программа тут довольно сложная, и для понятности стоит разбить ее на отдельные части-функции. Так, чтобы мы могли каждую функцию рассматривать отдельно, не глядя на другие. И , например, редактировать одну функцию, не трогая другие. Чтобы каждая функция решала какую-то свою задачу.
Надо учиться разбивать задачу на подзадачи. Делать код максимально простым и понятным.
Ты же не очень к этому стремишься и сделал одну огромную функцию numberToText. Надо разбить ее на составляющие. Не надо писать стену кода.
> $preString=preg_replace('/два тысячи/u','две тысячи',$preString);
Это кривые костыли, затрудняющие понимание кода. Ну представь, человек начнет разбирать твой код, увидит, что он генерирует строку "два тысячи", подумает, что в нем ошибка. И только потом, может, увидит, что в конце эта ошибка костылем испрвляется. Но почему нельзя сделать, чтобы там сразу бралось правильное слово? Зачем усложнять все и запутывать читателя? Так не годится.
> $preString="" . ($arr[2]?
preg_match('/(два|три|четыре)$/u',$arr[2])?"{$arr[2]} миллиона":(preg_match('/(один)$/u',$arr[2])?"{$arr[2]} миллион":"{$arr[2]} миллионов")
Это невозможно читать. Слишком запутанно. Необходимо переписать.
В общем, задачу, увы, надо переделать. Я такое принять не могу, ты должен думать о тех, кто будет читать твой код, чтобы им было проще разобраться в нем.
Если ты не знаешь, как разбить код на части, могу предложить один вариант (другие варианты тоже допустимы):
- делаем функцию выбора формы слова (тысяча, тысяч) в зависимости от числа
- делаем функцию, которая преобразует число от 0 до 999 в строку
- делаем функцию, которая разбивает большое число на части и записывает его, вызывая функции выше
У каждой функции должна быть своя задача, и логичный, простой набор аргументов и возвращаемых значений.
> https://github.com/wheelafterwheel/TDG/blob/master/sqlite3/transaction.ts
Здесь проблемы с читаемостью. Мне кажется, надо было не создавать объект to внутри функции, а сделать отдельным классом. Так как получилась тяжело читаемая функция-монстр.
Асинхронный код и так сам по себе сложен, и ты нагромождением коллбеков и остутпов делаешь его еще сложнее для понимания. Я сейчас сам не очень понимаю, корректен ли он или что-то упущено.
Еще отступы в 2 пробела ухудшают читаемость, может конечно я просто к ним не привык, но они же почти неразличимы.
В строке 47 глубина отступов составляет 7 - по моему, это перебор.
Возможно, стоило сделать промисифицированную обертку над db отдельным классом - так как многочисленные if ... reject только ухудшают читаемость. То есть сделать PromisifiedDb и уже с ним тут работать:
await pdb.beginTransaction();
to = new DbExecutor(pdb);
await sequence(to);
await pdb.commit();
Может быть, даже DbExecutor и не нужен будет, можно будет передавать в sequence этот PromisifiedDb.
Как-то так, наверно, будет гораздо читабельнее. А ты стремишься все описать в одном файле и в одной большой функции.
Также, я не думаю, что надо было в классе делать db.open/close(). Логичнее передавать уже открытый объект db. Как я понимаю, при коммите изменения гарантированно сохраняются и без close(). Заодно мы могли бы поставить тайп-хинт в конструкторе TDG, а не принимать тип any.
Также, я тут вижу потенциальную ошибку из-за асинхронности. Ты ждешь (await) завершения функции sequence и закрываешь транзакцию. Но кто гарантирует, что в этой функции не будут делаться вызовы объекта to после закрытия транзакции? Это вполне возможно из-за асинхронности:
transaction(function (to) {
setTimeout(function () {
to.execute(...);
}, 1000);
await to.execute(...)
});
Можно защититься от этого добавлением флага в to, который показывает доступность объекта, включается после выполнения BEGIN и выключается перед COMMIT.
То, что rollback реджектится не очень логично - наверно, все же логично при успехе отката резолвить его в null или true.
Также, транзакции конечно нужны при записи в БД, но при чтении они выглядят немного избыточными.
> if (
> statement.match(/^\s*SELECT/)
Это плохая идея, есть например SHOW и может еще какие-то команды. Лучше не определять их автоматически.
> async slice(limit: number = 30, offset: number = 0):
Это довольно ограниченный метод, он не поддерживает ни условия, ни порядок сортировки.
Не уверен, что нужны методы create/drop. Обычно таблицы создаются и изменяются через миграции.
> export class Staff extends TDG {
> constructor(
> name: string = 'staff'
Непонятно, зачем нужна возможность задать другое имя.
> (\`password_hash\` = ? OR \`password_hash\` IS NULL)
Это немного странно, а не приведет ли это к авторизации с пустым паролем?
> return (result["0"]["0"] !== undefined)
Надо было сделать методы, возвращающие одну строку и одну колонку.
Я вижу, что у тебя есть тест для Staff, а что насчет тестов для остального кода?
В тесте для ожидания исключения есть вроде бы конструкции expect().to.throw(...), а у тебя, если исключение не произойдет, то ошибки не будет.
Тест не очень хороший. У тебя просто один гигантский сценарий. Но тесты (по моему) должны тестировать фичи:
- вставка: если вставить объект в таблицу с помощью TDG, то его можно в ней найти
- удаление: если удалить объект с помощью TDG, то он больше не находится
- поиск: функция поиска находит объекты по правильным критериям (и не находит по неправильным)
- итд.
То есть ты должен подумать, что умеет делать твой TDG, записать это в виде списка фич, требований, и на каждое написать тест. Причем в идеале отдельный тест пишется для базового класса и отдельный для Staff.
Это дает такие преимущества:
- отдельные тесты получаются меньше и проще, и тестируют ровно 1 фичу
- если что-то сломается, то видно будет, какие фичи сломаны
И мне кажется, сама архитектура mocha к этому подталкивает: там есть describe() для описания тестируемого объекта и it() для описания фич. Ты же используешь it() для описания шагов гигантского теста. А должно быть:
describe('Staff', function () {
it('Can insert employee', ...);
it('Can delete employee', ...);
....
});
Если что, я могу еще что-то подсказать по тестам. Было бы хорошо тогда покрыть тестами весь код.
Также, непонятно, как при создании нового работника получить не занятый табельный номер.
Главная проблема - нечитаемость кода в transaction.ts.
Если хочешь поломать голову, не хочешь ли попробовать сделать ORM на основе DataMapper, вроде Доктрины в PHP? То есть сделать так, чтобы не надо было вручную писать методы вроде register(), а они бы как-то сами умели определять структуру объекта и формировать SQL код:
var repo = Repository.getFor(Employee);
var e1 = repo.findOneBy({'tableNumber': 123});
e1.name = 'New name';
repo.flush(); // сохраняет изменения в БД
Далее, реализовать паттерны Identity Map, Unit Of Work. Далее, связи между сущностями и ленивую загрузку. Задача интересная, хоть и сложная.
> https://github.com/wheelafterwheel/TDG/blob/master/sqlite3/transaction.ts
Здесь проблемы с читаемостью. Мне кажется, надо было не создавать объект to внутри функции, а сделать отдельным классом. Так как получилась тяжело читаемая функция-монстр.
Асинхронный код и так сам по себе сложен, и ты нагромождением коллбеков и остутпов делаешь его еще сложнее для понимания. Я сейчас сам не очень понимаю, корректен ли он или что-то упущено.
Еще отступы в 2 пробела ухудшают читаемость, может конечно я просто к ним не привык, но они же почти неразличимы.
В строке 47 глубина отступов составляет 7 - по моему, это перебор.
Возможно, стоило сделать промисифицированную обертку над db отдельным классом - так как многочисленные if ... reject только ухудшают читаемость. То есть сделать PromisifiedDb и уже с ним тут работать:
await pdb.beginTransaction();
to = new DbExecutor(pdb);
await sequence(to);
await pdb.commit();
Может быть, даже DbExecutor и не нужен будет, можно будет передавать в sequence этот PromisifiedDb.
Как-то так, наверно, будет гораздо читабельнее. А ты стремишься все описать в одном файле и в одной большой функции.
Также, я не думаю, что надо было в классе делать db.open/close(). Логичнее передавать уже открытый объект db. Как я понимаю, при коммите изменения гарантированно сохраняются и без close(). Заодно мы могли бы поставить тайп-хинт в конструкторе TDG, а не принимать тип any.
Также, я тут вижу потенциальную ошибку из-за асинхронности. Ты ждешь (await) завершения функции sequence и закрываешь транзакцию. Но кто гарантирует, что в этой функции не будут делаться вызовы объекта to после закрытия транзакции? Это вполне возможно из-за асинхронности:
transaction(function (to) {
setTimeout(function () {
to.execute(...);
}, 1000);
await to.execute(...)
});
Можно защититься от этого добавлением флага в to, который показывает доступность объекта, включается после выполнения BEGIN и выключается перед COMMIT.
То, что rollback реджектится не очень логично - наверно, все же логично при успехе отката резолвить его в null или true.
Также, транзакции конечно нужны при записи в БД, но при чтении они выглядят немного избыточными.
> if (
> statement.match(/^\s*SELECT/)
Это плохая идея, есть например SHOW и может еще какие-то команды. Лучше не определять их автоматически.
> async slice(limit: number = 30, offset: number = 0):
Это довольно ограниченный метод, он не поддерживает ни условия, ни порядок сортировки.
Не уверен, что нужны методы create/drop. Обычно таблицы создаются и изменяются через миграции.
> export class Staff extends TDG {
> constructor(
> name: string = 'staff'
Непонятно, зачем нужна возможность задать другое имя.
> (\`password_hash\` = ? OR \`password_hash\` IS NULL)
Это немного странно, а не приведет ли это к авторизации с пустым паролем?
> return (result["0"]["0"] !== undefined)
Надо было сделать методы, возвращающие одну строку и одну колонку.
Я вижу, что у тебя есть тест для Staff, а что насчет тестов для остального кода?
В тесте для ожидания исключения есть вроде бы конструкции expect().to.throw(...), а у тебя, если исключение не произойдет, то ошибки не будет.
Тест не очень хороший. У тебя просто один гигантский сценарий. Но тесты (по моему) должны тестировать фичи:
- вставка: если вставить объект в таблицу с помощью TDG, то его можно в ней найти
- удаление: если удалить объект с помощью TDG, то он больше не находится
- поиск: функция поиска находит объекты по правильным критериям (и не находит по неправильным)
- итд.
То есть ты должен подумать, что умеет делать твой TDG, записать это в виде списка фич, требований, и на каждое написать тест. Причем в идеале отдельный тест пишется для базового класса и отдельный для Staff.
Это дает такие преимущества:
- отдельные тесты получаются меньше и проще, и тестируют ровно 1 фичу
- если что-то сломается, то видно будет, какие фичи сломаны
И мне кажется, сама архитектура mocha к этому подталкивает: там есть describe() для описания тестируемого объекта и it() для описания фич. Ты же используешь it() для описания шагов гигантского теста. А должно быть:
describe('Staff', function () {
it('Can insert employee', ...);
it('Can delete employee', ...);
....
});
Если что, я могу еще что-то подсказать по тестам. Было бы хорошо тогда покрыть тестами весь код.
Также, непонятно, как при создании нового работника получить не занятый табельный номер.
Главная проблема - нечитаемость кода в transaction.ts.
Если хочешь поломать голову, не хочешь ли попробовать сделать ORM на основе DataMapper, вроде Доктрины в PHP? То есть сделать так, чтобы не надо было вручную писать методы вроде register(), а они бы как-то сами умели определять структуру объекта и формировать SQL код:
var repo = Repository.getFor(Employee);
var e1 = repo.findOneBy({'tableNumber': 123});
e1.name = 'New name';
repo.flush(); // сохраняет изменения в БД
Далее, реализовать паттерны Identity Map, Unit Of Work. Далее, связи между сущностями и ленивую загрузку. Задача интересная, хоть и сложная.
Статическая типизация - типы переменных известны в момент написания программы (обычно это значит что они явно указаны в коде), например:
int a = 1;
Соответственно, компилятор может проверить корректность типов до выполнения кода.
Динамическая - типы не известны до выполнения программы:
$a = calc();
function calc() {
....
}
Сильная/слабая - при слабой типизации язык может преобразовывать типы (например, в выражении "2" + 2 язык может автоматичеки преобразовать строку "2" в число), при сильной это надо делать явно, иначе будет ошибка.
https://ru.wikipedia.org/wiki/Сильная_и_слабая_типизация
>>69439
Это что-то с твоим кодом. Если что, есть паттерн Post/Redirect/Get для защиты от повторной отправки формы.
>(например, в выражении "2" + 2 язык может автоматичеки преобразовать строку "2" в число)
Нет, это не слабая типизация. Это неявное преобразование типов.
Смотри на Си. ты не можешь там сделать "2" + 2, так чтобы он на лету преобразовал строку "2" в число 2. При этом у Си - слабая типизация.
Ну все правильно он сказал
Ты не можешь "2" + 2 в С сделать, но
void *ptr можешь кастовать хоть во что
или enum с целыми неявно смешивать
именно поэтому слабая
Хотя даже тут ты наврал и меня запутал
>> "2" + 2
для С норм, потому что "2" указатель на константную строку
И сколько у тебя получится?
Читай внимательно
>ты не можешь там сделать "2" + 2, так чтобы он на лету преобразовал строку "2" в число 2
Анон, допомоги понять одну хероту.
Есть сает http://dzzb.ru
Запилил там "окна консоли" в некоторых статьях через css. Примеры:
http://dzzb.ru/blog/MScen
http://dzzb.ru/blog/StartGen
http://dzzb.ru/blog/Punch!
И вот в FurryFox и даже в IE эти "окна" отображаются нормально - с заголовком, который берется из картинки, а хром не воспринимает этот параметр CSS ниразу. Допиливал и "webkit" ко всем параметрам и бочку делал - нихуя. Насоветуй как хром полечить.
Слава слонику, ты тут многие замечания описал, которые мне тоже не нравятся (ура!). Ремарочка, как появился transaction.ts: я замучался с дефолтной реализацией драйвера sqlite3, и решил обыграть все спорные моменты одной функцией (написал и забыл, работает же!). Однако этот франкенштейн не так гибок как хотелось бы (появились ненужные флаги и прочий мусор), ты прав, лучше переписать ее или вообще убрать. (Но повторюсь, от дефолтного апи меня аж трисет, вот оно https://github.com/mapbox/node-sqlite3/wiki/API , если подскажешь, как это превратить в promisified, буду очень благодарен). Вообще у меня идея появилась сейчас абстрагироваться от баз данных вообще ииии да, именно
>сделать так, чтобы не надо было вручную писать методы вроде register(), а они бы как-то сами умели определять структуру объекта и формировать SQL код
На вскидку это довольно сложно, но я попробую, обучение же! (Но в реальном проекте лучше не велосипедить и взять https://github.com/typeorm/typeorm)
По поводу отступов:
>отступы в 4 пробела ухудшают мне читаемость, может конечно я просто к ним не привык, но они же слишком длинные
ну ты понял, алсо https://github.com/basarat/typescript-book/blob/master/docs/styleguide/styleguide.md#spaces
Я думаю, два, четыре пробела или таб не делают программиста.
>глубина отступов составляет 7 - по моему, это перебор
ну да, чет многовато (даже для такой трешовой функции)
Главное:
>Как я понимаю, при коммите изменения гарантированно сохраняются и без close()
из документации вообще не понятно, нужно ли, и когда нужно закрывать подключение (может быть принудительное закрывание помогает избежать утечек памяти или предотвращать коррупцию файла, хз), поэтому я на всякий случай закрываю. Однозначно нужно избавляться от всех any потому что это херня а не тип.
>То, что rollback реджектится не очень логично - наверно, все же логично при успехе отката резолвить его в null или true.
ты имеешь в виду to.rollback() ? это мануальный откат, который мы сами вызовем при определенных условиях в своем коде, указывая причину, которую (та-даа!) можно отловить (потому-что даже мануальный откат это исключительная ситуация). При reject мы выходим из sequence и идем ловить ошибку, а вот при resolve(true) мы как бы уже откатились, но команды далее по коду будут как ниндзи выполняться на уже закрытую транзакцию, как будто все нормально. (Собственно, это проблема архитектуры функции)
>вызовы объекта to после закрытия транзакции? Это вполне возможно из-за асинхронности...
жесть конечно, это надо быть кем, чтобы так стрелять себе в ногу (мы делаем из кучи асинхронных функций одну "синхронную", чтобы потом в коде ее запускать по таймауту (хм...асинхронно?))
Тогда да, флаг тут - очень хорошее решение, спасибо.
Я думал ты будешь пробовать сам запускать, ну да ладно.
Остальные замечания: все постараюсь исправить. Нужны комментарии на вопросы выше.
Слава слонику, ты тут многие замечания описал, которые мне тоже не нравятся (ура!). Ремарочка, как появился transaction.ts: я замучался с дефолтной реализацией драйвера sqlite3, и решил обыграть все спорные моменты одной функцией (написал и забыл, работает же!). Однако этот франкенштейн не так гибок как хотелось бы (появились ненужные флаги и прочий мусор), ты прав, лучше переписать ее или вообще убрать. (Но повторюсь, от дефолтного апи меня аж трисет, вот оно https://github.com/mapbox/node-sqlite3/wiki/API , если подскажешь, как это превратить в promisified, буду очень благодарен). Вообще у меня идея появилась сейчас абстрагироваться от баз данных вообще ииии да, именно
>сделать так, чтобы не надо было вручную писать методы вроде register(), а они бы как-то сами умели определять структуру объекта и формировать SQL код
На вскидку это довольно сложно, но я попробую, обучение же! (Но в реальном проекте лучше не велосипедить и взять https://github.com/typeorm/typeorm)
По поводу отступов:
>отступы в 4 пробела ухудшают мне читаемость, может конечно я просто к ним не привык, но они же слишком длинные
ну ты понял, алсо https://github.com/basarat/typescript-book/blob/master/docs/styleguide/styleguide.md#spaces
Я думаю, два, четыре пробела или таб не делают программиста.
>глубина отступов составляет 7 - по моему, это перебор
ну да, чет многовато (даже для такой трешовой функции)
Главное:
>Как я понимаю, при коммите изменения гарантированно сохраняются и без close()
из документации вообще не понятно, нужно ли, и когда нужно закрывать подключение (может быть принудительное закрывание помогает избежать утечек памяти или предотвращать коррупцию файла, хз), поэтому я на всякий случай закрываю. Однозначно нужно избавляться от всех any потому что это херня а не тип.
>То, что rollback реджектится не очень логично - наверно, все же логично при успехе отката резолвить его в null или true.
ты имеешь в виду to.rollback() ? это мануальный откат, который мы сами вызовем при определенных условиях в своем коде, указывая причину, которую (та-даа!) можно отловить (потому-что даже мануальный откат это исключительная ситуация). При reject мы выходим из sequence и идем ловить ошибку, а вот при resolve(true) мы как бы уже откатились, но команды далее по коду будут как ниндзи выполняться на уже закрытую транзакцию, как будто все нормально. (Собственно, это проблема архитектуры функции)
>вызовы объекта to после закрытия транзакции? Это вполне возможно из-за асинхронности...
жесть конечно, это надо быть кем, чтобы так стрелять себе в ногу (мы делаем из кучи асинхронных функций одну "синхронную", чтобы потом в коде ее запускать по таймауту (хм...асинхронно?))
Тогда да, флаг тут - очень хорошее решение, спасибо.
Я думал ты будешь пробовать сам запускать, ну да ладно.
Остальные замечания: все постараюсь исправить. Нужны комментарии на вопросы выше.
Ебать ты англичанин.
Или для записи в поликлинику
А мне нравится дизайн. Чуть чуть выровнять только. А то сейчас что не сайт - битва космических истребителей от лукасфилм.
https://github.com/deadj/deadj.github.io
deadj.github.io
>>1266710
Самое главное, что бросается в глаза: не подключен шрифт. У тебя указан шрифт Lato, но если его не установлено на компьютере, то текст отобразится другим шрифтом (sans-serif). Для подключения файла шрифта есть специальное CSS-правило @font-face. Я советую внимательно его изучить. Обрати внимание, что существуют разные форматы шрифтов, и разные браузеры поддерживают разные форматы:
- https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face (в конце есть таблица)
- https://css-tricks.com/snippets/css/using-font-face/ (англ)
- https://caniuse.com/#feat=woff
- https://caniuse.com/#feat=woff2
- https://caniuse.com/#feat=ttf
- https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/webfont-optimization?hl=ru (статья на русском)
Сконвертировать шрифты можно конвертором: https://www.fontsquirrel.com/tools/webfont-generator
Обрати внимание, что пока шрифт не загрузится, браузер не показывает текст. Повлиять на это поведение можно новым свойством font-display: https://css-tricks.com/font-display-masses/
Проверить, как шрифты отображаются в разных браузерах, можно напрмер, тут: https://developer.microsoft.com/en-us/microsoft-edge/tools/screenshots/
Раньше на browserstack была возможность бесплатно делать скриншоты, но не знаю, есть ли она сейчас.
Скриншоты можно сделать еще на http://browsershots.org/, но там нет ИЕ и мобильных браузеров.
Ты заметишь, что процесс довольно хлопотный: надо конвертировать шрифты, настроить правила font-face итд. Вообще, этого можно избежать, если подключать готовые шрифты с Google Fonts, который все сделает сам, но я бы советовал один раз сделать все вручную, чтобы разобраться. Ну и при желании ты можешь как-то shell-скриптами автоматизировать это.
Телефон хорошо бы сделать кликабельным, ссылкой с префиксом tel: https://css-tricks.com/the-current-state-of-telephone-links/
Также, было бы хорошо сделать версию для маленьких экранов. У тебя сделана какая-то минимальная адаптивность, но ее явно недостаточно. Сейчас при уменьшении ширины шапка остается гигантской и смотрится нелогично. Вот список размеров экранов разных устройств: http://viewportsizes.com/ - можно выбрать, например такие значения ширины для проверки:
- 320 (или 360), 640, 960
Стоит на маленьких экранах уменьшить текст в шапке, уменьшить отступы и шрифт в списке преимуществ, может быть даже как-то переформатировать его, например, убрав или сдвинув иконки, в подвале уменьшить шрифт и отступы, а кружочки-ссылки расставит пошире, чтобы в них было удобнее попадать пальцем.
Просто выстроить все блоки вертикально - это очень механически, и этого недостаточно для адаптивности.
> body, html {
> box-sizing: border-box;
Непонятно, зачем тут box-sizing, если для html/body ширина или высота все равно не задана.
> .headerBack {
> width: 100%;
> display: inline-block;
Непонятно, зачем тут inline-block
> .logo {
> display: inline-block;
> float: left;
float подразуемвает display: block
В блоке с Consectetur надо настроить line-height в абзацах как на макете.
Вместо тегов b/i сейчас используют strong/em, с немного другим смыслом (они задают не внешний вид текста, а смысловое выделение).
> <div class="serveicesBlock">
> <div class="img"></div>
Можно использовать псевдоэлемент вместо дива .img
> <input type="radio" id="tabLabel2" name="radiobutton"/>
В указании слеша в конце /> в HTML5 нет необходимости. Это из XHTML.
Надо чтобы при выборе категорий (all/graphic/illustration) часть работ скрывалась, а часть оставалась. Присвоить категории можно через data-атрибуты или CSS классы.
> <div></div>
> <div></div>
Непонятно, зачем пустые дивы.
> .serveicesBlock > p {
> font-size: 14px;
Это плохая идея, вешать стили на p, так как текст может быть и в других тегах (например: ul/li, figure). Лучше просто было задать шрифт на servicesBlock.
> .footerLink > a:nth-child(2) {
> background-position: -42px -11px;
Здесь вместо номеров лучше использовать классы (link-fb, link-tw). Так как с номерами неудобно вставлять или убирать элементы: надо менять все номера. Или нельзя просто переставить 2 ссылки местами. Тут лучше явно указать тип ссылки в HTML.
>>1266710
Самое главное, что бросается в глаза: не подключен шрифт. У тебя указан шрифт Lato, но если его не установлено на компьютере, то текст отобразится другим шрифтом (sans-serif). Для подключения файла шрифта есть специальное CSS-правило @font-face. Я советую внимательно его изучить. Обрати внимание, что существуют разные форматы шрифтов, и разные браузеры поддерживают разные форматы:
- https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face (в конце есть таблица)
- https://css-tricks.com/snippets/css/using-font-face/ (англ)
- https://caniuse.com/#feat=woff
- https://caniuse.com/#feat=woff2
- https://caniuse.com/#feat=ttf
- https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/webfont-optimization?hl=ru (статья на русском)
Сконвертировать шрифты можно конвертором: https://www.fontsquirrel.com/tools/webfont-generator
Обрати внимание, что пока шрифт не загрузится, браузер не показывает текст. Повлиять на это поведение можно новым свойством font-display: https://css-tricks.com/font-display-masses/
Проверить, как шрифты отображаются в разных браузерах, можно напрмер, тут: https://developer.microsoft.com/en-us/microsoft-edge/tools/screenshots/
Раньше на browserstack была возможность бесплатно делать скриншоты, но не знаю, есть ли она сейчас.
Скриншоты можно сделать еще на http://browsershots.org/, но там нет ИЕ и мобильных браузеров.
Ты заметишь, что процесс довольно хлопотный: надо конвертировать шрифты, настроить правила font-face итд. Вообще, этого можно избежать, если подключать готовые шрифты с Google Fonts, который все сделает сам, но я бы советовал один раз сделать все вручную, чтобы разобраться. Ну и при желании ты можешь как-то shell-скриптами автоматизировать это.
Телефон хорошо бы сделать кликабельным, ссылкой с префиксом tel: https://css-tricks.com/the-current-state-of-telephone-links/
Также, было бы хорошо сделать версию для маленьких экранов. У тебя сделана какая-то минимальная адаптивность, но ее явно недостаточно. Сейчас при уменьшении ширины шапка остается гигантской и смотрится нелогично. Вот список размеров экранов разных устройств: http://viewportsizes.com/ - можно выбрать, например такие значения ширины для проверки:
- 320 (или 360), 640, 960
Стоит на маленьких экранах уменьшить текст в шапке, уменьшить отступы и шрифт в списке преимуществ, может быть даже как-то переформатировать его, например, убрав или сдвинув иконки, в подвале уменьшить шрифт и отступы, а кружочки-ссылки расставит пошире, чтобы в них было удобнее попадать пальцем.
Просто выстроить все блоки вертикально - это очень механически, и этого недостаточно для адаптивности.
> body, html {
> box-sizing: border-box;
Непонятно, зачем тут box-sizing, если для html/body ширина или высота все равно не задана.
> .headerBack {
> width: 100%;
> display: inline-block;
Непонятно, зачем тут inline-block
> .logo {
> display: inline-block;
> float: left;
float подразуемвает display: block
В блоке с Consectetur надо настроить line-height в абзацах как на макете.
Вместо тегов b/i сейчас используют strong/em, с немного другим смыслом (они задают не внешний вид текста, а смысловое выделение).
> <div class="serveicesBlock">
> <div class="img"></div>
Можно использовать псевдоэлемент вместо дива .img
> <input type="radio" id="tabLabel2" name="radiobutton"/>
В указании слеша в конце /> в HTML5 нет необходимости. Это из XHTML.
Надо чтобы при выборе категорий (all/graphic/illustration) часть работ скрывалась, а часть оставалась. Присвоить категории можно через data-атрибуты или CSS классы.
> <div></div>
> <div></div>
Непонятно, зачем пустые дивы.
> .serveicesBlock > p {
> font-size: 14px;
Это плохая идея, вешать стили на p, так как текст может быть и в других тегах (например: ul/li, figure). Лучше просто было задать шрифт на servicesBlock.
> .footerLink > a:nth-child(2) {
> background-position: -42px -11px;
Здесь вместо номеров лучше использовать классы (link-fb, link-tw). Так как с номерами неудобно вставлять или убирать элементы: надо менять все номера. Или нельзя просто переставить 2 ссылки местами. Тут лучше явно указать тип ссылки в HTML.
- https://phpclub.tech/pr/res/1232710.html
- https://2ch.hk/pr/arch/2018-09-27/res/1232710.html (М)
Если я проверил вашу задачку, а вы не успели увидеть решение - зайдите в архив. Также в нашем архиве можно искать решения и комментарии к задачам.
Как я помню, вопросы с 20 сентября отвечены в старом треде, ответы вопросы с 1 сентября по сегодня - ниже:
>>1270298
Нужно установить интерпретатор PHP, это программа для командной строки: https://github.com/codedokode/pasta/blob/master/soft/php-install.md
Если тебе не нравится командная строка, то можно взять IDE или редактор (Netbeans PHP, Eclipse for PHP, PhpStorm, Sublime Text) и настроить запуск PHP из них. В каждом редакторе это делается по-своему.
>>1270158
У тебя помоему $time на 1 меньше, чем надо. То есть если бы миллион получился после 1 года (например, если начальная сумма равна 999 000), то твоя программа напишет что миллион накопился в 16 лет, а не в 17.
>>1266701
Алсо задачка на поиск емейл в тексте. https://ideone.com/bOB8LV
В именах пользователя и домене могут быть минусы:
Код надо форматровать получше, каждая закрывающая скобка } ставится на отдельной строке.
Но сама идея решения верная.
- https://phpclub.tech/pr/res/1232710.html
- https://2ch.hk/pr/arch/2018-09-27/res/1232710.html (М)
Если я проверил вашу задачку, а вы не успели увидеть решение - зайдите в архив. Также в нашем архиве можно искать решения и комментарии к задачам.
Как я помню, вопросы с 20 сентября отвечены в старом треде, ответы вопросы с 1 сентября по сегодня - ниже:
>>1270298
Нужно установить интерпретатор PHP, это программа для командной строки: https://github.com/codedokode/pasta/blob/master/soft/php-install.md
Если тебе не нравится командная строка, то можно взять IDE или редактор (Netbeans PHP, Eclipse for PHP, PhpStorm, Sublime Text) и настроить запуск PHP из них. В каждом редакторе это делается по-своему.
>>1270158
У тебя помоему $time на 1 меньше, чем надо. То есть если бы миллион получился после 1 года (например, если начальная сумма равна 999 000), то твоя программа напишет что миллион накопился в 16 лет, а не в 17.
>>1266701
Алсо задачка на поиск емейл в тексте. https://ideone.com/bOB8LV
В именах пользователя и домене могут быть минусы:
Код надо форматровать получше, каждая закрывающая скобка } ставится на отдельной строке.
Но сама идея решения верная.
>>1266631
> Мне нужно заменить все значения true, на false.
> А что если просто сериализовать массив в строку, и пройтись регулярко, ну и потом обратно собрать?
Это очень костыльно, и ты взяд ли сможешь сделать это корректно. Формат сериализации не документирован и может в любой момент поменяться. Ну например, может там в строке есть слово true, а ты его заменишь.
Лучше может быть просто в цикле пересоздать массив - это делает код безопаснее.
>>1265236
> Почитал урок про MVC, с моделью и вью все понятно, а вот есть подробные инструкции по написанию контроллеров?
Контроллер анализрует запрос пользователя, берет нужные данные из модели и отображает их с помощью view.
Контроллер может быть написан просто как скрипт, как функция, как класс или метод в классе.
Описание паттерна кратко: http://design-pattern.ru/patterns/page-controller.html
В некоторых фреймворках контроллер - это функция, которая принимает на вход объект Request и возвращает объект Response.
Код в контроллере нельзя повторно использовать (вызвать из другого места кода), потому стоит делать его не слишком большим и не помещать в него то, что можно поместить в модель.
Также, есть паттерн Front Controller - когда все запросы идут в главный контроллер, он делает какие-то подготовительные действия и вызывает уже отвечающий за данный запрос контроллер. Описание кратко: http://design-pattern.ru/patterns/front-controller.html
>>1265663
> Задача на автозамену скобочек в тел. номерах
Не надо экономить строчки. Фигурные скобки ставятся так:
if (условие) {
действия;
}
Варнинги надо исправить:
> PHP Warning: array_push() expects parameter 1 to be array, string given in /home/A2VmLC/prog.php on line 19
> echo "Only these passed negative tests {$mistakes}\n";
Локальная переменная, созданная в функции, не доступна снаружи.
>>1266631
> Мне нужно заменить все значения true, на false.
> А что если просто сериализовать массив в строку, и пройтись регулярко, ну и потом обратно собрать?
Это очень костыльно, и ты взяд ли сможешь сделать это корректно. Формат сериализации не документирован и может в любой момент поменяться. Ну например, может там в строке есть слово true, а ты его заменишь.
Лучше может быть просто в цикле пересоздать массив - это делает код безопаснее.
>>1265236
> Почитал урок про MVC, с моделью и вью все понятно, а вот есть подробные инструкции по написанию контроллеров?
Контроллер анализрует запрос пользователя, берет нужные данные из модели и отображает их с помощью view.
Контроллер может быть написан просто как скрипт, как функция, как класс или метод в классе.
Описание паттерна кратко: http://design-pattern.ru/patterns/page-controller.html
В некоторых фреймворках контроллер - это функция, которая принимает на вход объект Request и возвращает объект Response.
Код в контроллере нельзя повторно использовать (вызвать из другого места кода), потому стоит делать его не слишком большим и не помещать в него то, что можно поместить в модель.
Также, есть паттерн Front Controller - когда все запросы идут в главный контроллер, он делает какие-то подготовительные действия и вызывает уже отвечающий за данный запрос контроллер. Описание кратко: http://design-pattern.ru/patterns/front-controller.html
>>1265663
> Задача на автозамену скобочек в тел. номерах
Не надо экономить строчки. Фигурные скобки ставятся так:
if (условие) {
действия;
}
Варнинги надо исправить:
> PHP Warning: array_push() expects parameter 1 to be array, string given in /home/A2VmLC/prog.php on line 19
> echo "Only these passed negative tests {$mistakes}\n";
Локальная переменная, созданная в функции, не доступна снаружи.
>>1265163
> Задача на проверку телефонов.
То же замечание - форматируй код, так как его невозможно читать.
Идея решения правильная, но код нечитаемый.
>>1264529
> Цель: написать клон Героев 3 только лишь на пхп.
PHP не самый лучший выбор тут. PHP обычно используется для генерации страниц в ответ на HTTP-запрос.То есть ты кликнул в браузере по ссылке - отправился запрос - PHP-скрипт запустился, сгенерировал страницу, отправил ее тебе, браузер отобразил. Этот сценарий не очень стыкуется с игрой, где код постоянно работает, принимает команды пользователя, обновляет изображение.
Конечно, PHP можно заставить работать в долгоживущем режиме, но это будет тяжело, и он не предназначен для создания десктопных игр. Я предлагаю взять другую платформу, а именно что-то из этого:
- HTML5 + JS. В браузер загружается страница, на этой странице загружается JS-программа и выполняется в браузере. Она рисует изображение для игры и реагирует на действия пользователя. В теории, будет работать и на планшетах, но медленнее.
- Electron + HTML5 + JS. То же самое, только HTML-страница, JS-код и браузер упакованы в приложение. Пользователь запускает приложение, внутри него запускается встроенный браузер, отображает страницу, но для пользователя это выглядит как "настоящее" приложение.
- Pygame. Приложение-игра на Питоне, в помощь тебе дается библиотека для работы с графикой. Вроде как поддерживает десктопные ОС и Андроид.
С классами в JS не очень, потому ты можешь захотеть использовать TypeScript - надстройку над JS, которая добавляет синтаксис для классов и проверку типов. В Питоне классы есть.
Если ты не знаешь ни JS, ни Питона, то у меня есть 2 новости. Хорошая: в обоих этих языках есть многое из того, что есть в PHP - массивы, переменные, циклы, классы. Со знанием PHP учить их будет проще. Плохая: у них все же другой синтаксис и есть свои особенности.
Времени вполне хватит, если ты не будешь гнаться за космической графикой и крутым геймплеем.
Наш тред, может быть, сможет тебе помочь советами в случае изучения JS, и может даже с Питоном, хотя это будет не совсем по теме.
>>1264400
> $arr1=explode('',$text);
Это неразбивает текст на буквы, а разбивает на байты. То есть, в случае кириллицы, на половинки букв.
Замену пробелов проще сделать через str_replace или strtr и без цикла.
> if ($arr1[$i]!=$arr2[$j]){
Та же проблема, ты берешь не буквы, а байты. Прочитай урок https://github.com/codedokode/pasta/blob/master/php/strings-utf8.md
> echo "" . $result;
Тут "" не нужно.
В общем, сейчас программа не работает нормально, так как сравнвает байты, а не буквы. Надо это исправить.
>>1265163
> Задача на проверку телефонов.
То же замечание - форматируй код, так как его невозможно читать.
Идея решения правильная, но код нечитаемый.
>>1264529
> Цель: написать клон Героев 3 только лишь на пхп.
PHP не самый лучший выбор тут. PHP обычно используется для генерации страниц в ответ на HTTP-запрос.То есть ты кликнул в браузере по ссылке - отправился запрос - PHP-скрипт запустился, сгенерировал страницу, отправил ее тебе, браузер отобразил. Этот сценарий не очень стыкуется с игрой, где код постоянно работает, принимает команды пользователя, обновляет изображение.
Конечно, PHP можно заставить работать в долгоживущем режиме, но это будет тяжело, и он не предназначен для создания десктопных игр. Я предлагаю взять другую платформу, а именно что-то из этого:
- HTML5 + JS. В браузер загружается страница, на этой странице загружается JS-программа и выполняется в браузере. Она рисует изображение для игры и реагирует на действия пользователя. В теории, будет работать и на планшетах, но медленнее.
- Electron + HTML5 + JS. То же самое, только HTML-страница, JS-код и браузер упакованы в приложение. Пользователь запускает приложение, внутри него запускается встроенный браузер, отображает страницу, но для пользователя это выглядит как "настоящее" приложение.
- Pygame. Приложение-игра на Питоне, в помощь тебе дается библиотека для работы с графикой. Вроде как поддерживает десктопные ОС и Андроид.
С классами в JS не очень, потому ты можешь захотеть использовать TypeScript - надстройку над JS, которая добавляет синтаксис для классов и проверку типов. В Питоне классы есть.
Если ты не знаешь ни JS, ни Питона, то у меня есть 2 новости. Хорошая: в обоих этих языках есть многое из того, что есть в PHP - массивы, переменные, циклы, классы. Со знанием PHP учить их будет проще. Плохая: у них все же другой синтаксис и есть свои особенности.
Времени вполне хватит, если ты не будешь гнаться за космической графикой и крутым геймплеем.
Наш тред, может быть, сможет тебе помочь советами в случае изучения JS, и может даже с Питоном, хотя это будет не совсем по теме.
>>1264400
> $arr1=explode('',$text);
Это неразбивает текст на буквы, а разбивает на байты. То есть, в случае кириллицы, на половинки букв.
Замену пробелов проще сделать через str_replace или strtr и без цикла.
> if ($arr1[$i]!=$arr2[$j]){
Та же проблема, ты берешь не буквы, а байты. Прочитай урок https://github.com/codedokode/pasta/blob/master/php/strings-utf8.md
> echo "" . $result;
Тут "" не нужно.
В общем, сейчас программа не работает нормально, так как сравнвает байты, а не буквы. Надо это исправить.
>>1264400
> $arr1=explode('',$text);
Это неразбивает текст на буквы, а разбивает на байты. То есть, в случае кириллицы, на половинки букв.
Замену пробелов проще сделать через str_replace или strtr и без цикла.
> if ($arr1[$i]!=$arr2[$j]){
Та же проблема, ты берешь не буквы, а байты. Прочитай урок https://github.com/codedokode/pasta/blob/master/php/strings-utf8.md
> echo "" . $result;
Тут "" не нужно.
В общем, сейчас программа не работает нормально, так как сравнвает байты, а не буквы. Надо это исправить.
>>1264380
> Задачка про банкомат - https://ideone.com/SfcMLz
> $bills = array_reverse($bills);
Сортровать по убыванию лучше функцией вроде krsort, смотри мануал http://php.net/manual/ru/array.sorting.php
Функция array_reverse перепроставляет значения ключей (меняет их на 0, 1, 2 ...) и номиналы теряются. Это описано в мануале.
> if($amount >= $nominal and $countBanknote < $value) {
Ты берешь банкноты только если их достаточно. Но можно брать и если их не хватает. Например, сумма 3100, в наличии 5 банкнот по 500 и 7 банкнот по 100. Берем 5x500 + 6x100. Твоя же программа в этом случае не сможет набрать нужную сумму.
Надо исправить эту проблему. У тебя программа вообще пока нерабочая.
>>1264400
> $arr1=explode('',$text);
Это неразбивает текст на буквы, а разбивает на байты. То есть, в случае кириллицы, на половинки букв.
Замену пробелов проще сделать через str_replace или strtr и без цикла.
> if ($arr1[$i]!=$arr2[$j]){
Та же проблема, ты берешь не буквы, а байты. Прочитай урок https://github.com/codedokode/pasta/blob/master/php/strings-utf8.md
> echo "" . $result;
Тут "" не нужно.
В общем, сейчас программа не работает нормально, так как сравнвает байты, а не буквы. Надо это исправить.
>>1264380
> Задачка про банкомат - https://ideone.com/SfcMLz
> $bills = array_reverse($bills);
Сортровать по убыванию лучше функцией вроде krsort, смотри мануал http://php.net/manual/ru/array.sorting.php
Функция array_reverse перепроставляет значения ключей (меняет их на 0, 1, 2 ...) и номиналы теряются. Это описано в мануале.
> if($amount >= $nominal and $countBanknote < $value) {
Ты берешь банкноты только если их достаточно. Но можно брать и если их не хватает. Например, сумма 3100, в наличии 5 банкнот по 500 и 7 банкнот по 100. Берем 5x500 + 6x100. Твоя же программа в этом случае не сможет набрать нужную сумму.
Надо исправить эту проблему. У тебя программа вообще пока нерабочая.
>>1263923
> ОПче, у меня есть идея своего приложения в качестве замены задачам о списке студентов и др. У тебя все очень грамотно расписано в плане того, как реализовать фичи определенные, покрыть тестами, реализовать новые фичи. Я тебе напишу в почту тоже, оч нужна твоя помощь, ниче технически сложного или как там сделать спрашивать не буду, а спрошу какие бы ты классы реализовал, или в какой последовательности реализовавывал бы фичи.
Писал бы сюда, зачем в почту? Я почту реже проверяю, чем сюда захожу, только когда есть время.
>>1263752
> Чувствую себя застрявшим. Куда двигаться дальше? Учить паттерны для более сложных алгоритмов или учить фреймворки, дб, хттп, делать пет прожекты?
делай проекты, если достаточно знаний. Начать можно с задачи про студентов в ОП посте.
>>1263794
> с функцией array_rand() jdoodle.com/a/ERc
Ок, верно.
> w5.6 с функцией array_rand() и православной конкатенацией jdoodle.com/a/ERf
> if (4 >= 0) {
> $name = "$conc";
Это условие всегда выполняется и строчка внутри тоже всегда выполняется. Ее надо поставить после цикла, чтобы она выполнялась только один раз. Также, кавычки тут не нужны.
> PHP Notice: Undefined variable: conc in /home/jdoodle.php on line 21
Это предупреждение надо исправить.
>>1263444
SPA это усложнение и нужно для специфичных фич: работа в оффлайне, сложные интерфейсы, высокая интерактивность. Если у тебя этого нет, то не надо усложнять приложение без надобности. Плюс оно тормозить наверно сильнее будет в виде SPA.
>>1263923
> ОПче, у меня есть идея своего приложения в качестве замены задачам о списке студентов и др. У тебя все очень грамотно расписано в плане того, как реализовать фичи определенные, покрыть тестами, реализовать новые фичи. Я тебе напишу в почту тоже, оч нужна твоя помощь, ниче технически сложного или как там сделать спрашивать не буду, а спрошу какие бы ты классы реализовал, или в какой последовательности реализовавывал бы фичи.
Писал бы сюда, зачем в почту? Я почту реже проверяю, чем сюда захожу, только когда есть время.
>>1263752
> Чувствую себя застрявшим. Куда двигаться дальше? Учить паттерны для более сложных алгоритмов или учить фреймворки, дб, хттп, делать пет прожекты?
делай проекты, если достаточно знаний. Начать можно с задачи про студентов в ОП посте.
>>1263794
> с функцией array_rand() jdoodle.com/a/ERc
Ок, верно.
> w5.6 с функцией array_rand() и православной конкатенацией jdoodle.com/a/ERf
> if (4 >= 0) {
> $name = "$conc";
Это условие всегда выполняется и строчка внутри тоже всегда выполняется. Ее надо поставить после цикла, чтобы она выполнялась только один раз. Также, кавычки тут не нужны.
> PHP Notice: Undefined variable: conc in /home/jdoodle.php on line 21
Это предупреждение надо исправить.
>>1263444
SPA это усложнение и нужно для специфичных фич: работа в оффлайне, сложные интерфейсы, высокая интерактивность. Если у тебя этого нет, то не надо усложнять приложение без надобности. Плюс оно тормозить наверно сильнее будет в виде SPA.
>>1263349
> Как это чудовище натянуть на классы? Тут полей явно больше чем пальцев в моем организме.
Во-первых, проблемы никакой не вижу, в PHP 30 полей в классе не проблема. Ну и по моему, у тебя неудачно спроектирована таблица, явно надо сделать нормализацию. Даже на рисунке полей меньше.
Почитай для начала урок про нормализацию: https://github.com/codedokode/pasta/blob/master/db/normalization.md
> Причем если ЭТО нормализовать, мне кажется производительность упадет в нулину.
Сделай тесты, а не гадай.
>>1262263
> можешь пояснить свой мотив в запиле гайдов и помощи вкатывальщикам на протяжении уже нескольких лет?
А почему бы и нет, если я не буду делиться знаниями, они все равно со временем станут бесполезными. А так, может быть, я хоть чуть-чуть смогу изменть мир вокруг себя и продвинуть прогресс вперед (не знаю, конечно, сильно ли двигается прогресс от создания сайта очередного интернет-магазина). Какой смысл тратить кучу времени на освоение и совершенствование какого-то ремесла и унести его с собой в могилу?
>>1257990
> ОП, какая будет сложность создания пет-проекта - простое весьма по фронту приложение, но пользователь обязательно должен голосом со всем взаимодействовать. Команд будет всего несколько голосовых и они будут весьма простые и однозначные.
Все зависит от используемого сервиса. Если он будет распознавать команды и выдавать результат - то не так и сложно. Но по факту распознавани голоса не такая простая вещь, особенно если надо распознавать разных людей, в зашумленной обстановке итд. Я бы советовал для начала найти такой сервис распознавания и протестировать его, а потом делать выводы.
>>1257803
> Вопрос по исключениям, с правильностью использования которых у меня проблемы.
> Вот абстрактный код на пике.
> Стоит ли делать такой if внутри которого я делаю throw
> или же стоит это оформить иначе, если да то, как и почему?
Вполне нормальный код. Транзакциии еще можно делать через коллбек:
$db->transactional(function ($db) {
$db->execute(...);
});
Там исключение ловит функция transactional.
>>1257907
> Задачка с айпадом: https://ideone.com/mLzoxa
Решение удалено.
>>1257813
> Проверьте, пожалуйста, задачу с палиндромами.
> http://sandbox.onlinephpfunctions.com/code/75e94cacefd198240501dfac4cc93cdca0ac29a3
> if ($a == $b) {
> $result;
Команда $result; ничего не делает и не нужна.
Также, при первом же несовпадении можно выходить из цикла по break.
А в остальном верно.
>>1256983
> Аноны, почему ошибка в 16 строчке? 30 раз смотрел, вроде нету ошибок. Решение https://ideone.com/8sXAP4
Ошибка в 29 строчке, там иногда генерируется индекс 16, которого нет в массиве.
>>1257803
> Вопрос по исключениям, с правильностью использования которых у меня проблемы.
> Вот абстрактный код на пике.
> Стоит ли делать такой if внутри которого я делаю throw
> или же стоит это оформить иначе, если да то, как и почему?
Вполне нормальный код. Транзакциии еще можно делать через коллбек:
$db->transactional(function ($db) {
$db->execute(...);
});
Там исключение ловит функция transactional.
>>1257907
> Задачка с айпадом: https://ideone.com/mLzoxa
Решение удалено.
>>1257813
> Проверьте, пожалуйста, задачу с палиндромами.
> http://sandbox.onlinephpfunctions.com/code/75e94cacefd198240501dfac4cc93cdca0ac29a3
> if ($a == $b) {
> $result;
Команда $result; ничего не делает и не нужна.
Также, при первом же несовпадении можно выходить из цикла по break.
А в остальном верно.
>>1256983
> Аноны, почему ошибка в 16 строчке? 30 раз смотрел, вроде нету ошибок. Решение https://ideone.com/8sXAP4
Ошибка в 29 строчке, там иногда генерируется индекс 16, которого нет в массиве.
>>1256748
> Аноны, чекните задание про рост школьников, все правильно?
все правильно, только не экономь на строчках и заключай тело if в фигурные скобки.
>>1256224
> ОПушка, проверь функцию для этой задачки: https://ideone.com/bU5gHV
Ок, верно.
>>1256073
> В задачке про массивы с 10ю ключами порядок ключей важен или только их наличие?
Порядок не важен.
> Оп, глянь студентов: https://github.com/Awesome-Kirill/fukingStudent
Больше месяца прошло, нехорошо.
Недавно начал читать гайд для новичков из ОП. Весьма интересно. Недавно наткнулся на такую фишку как bootstrap, я так понял это библиотека готовых решений. Насколько оправдано пользование этим ресурсом? Или лучше всё писать ручками?
> Насколько оправдано пользование этим ресурсом?
Ни на сколько. Хреньворк - априори хуйня. Тем более этот страпон.
> полезная задача сделать список студентов
Пошёл нахуй со своими студентами. Лучше делать список гей-шлюх, и то приличнее будет.
Сделал игру с кубиками, не совсем понял за кусок:
exit()
его ставить в конце всех условий или?
Нет, долбоёб, это точка остановки программы. Плюс лишняя точка с запятой в последнем условии.
Это не тред для самоутверждения людей с комплексами. Это тред для помощи новичкам.
Ты такой токсичный.
То, что это останавливает программу, я понял. Но где её ставить? По идее если условие выполнено, это повод остановить программу т.е. ставить после каждого условия?
Я так понял, в интерфейсе все методы это заготовки без реализации, в абстрактном можно прописать не абстрактный метод с реализацией сразу. Вот на практике я Х
хер знает, когда что лучше брать.
Абстрактный класс имеет как минимум один абстрактный (не определенный) метод. Интерфейс - это тот же абстрактный класс, с той разницей, что в нём не может быть свойств и не определены тела методов. Абстрактный класс наследуется, а интерфейс реализуется: наследовать можно только один класс, а реализовать сколько угодно.
>>71319
А тебе не приходило в голову, что программа на пыхапе обычно сама останавливается? Рот твой токсичный.
Обычно ставить не надо нигде. Там в задаче оно ставится, чтобы , если условие в первом блоке if сработало, код ниже бы не выполнялся. Можно (так даже лучше) сделать вообще без exit, если перегруппировать блоки if.
Давай начнем с более общего вопроса. В чем разница между классом и интерфейсом?
Если что, урок про интерфейсы в помощь: https://github.com/codedokode/pasta/blob/master/php/interfaces.md
https://ideone.com/sIORAY
Не совсем понимаю, что не так. Вроде создал нулевую таблицу, потом она заполняется где каждый элемент берет номер $i, и значение рандомного слога а на выходе - болты.
Ты латентный пидор.
Нет ты объясняй давай, что это ещё за не могу.
Как внутри массива располагаются элементы? Чем ассоциативный массив от простого отличается?
Каждому имени в массиве относится ключ, ну как в задачке с ростом было. Имя - рост. Где ключ это рост.
В простых массивах идет поиск по индексу, в ассоциативных по ассоциациям, вроде так
$assoc = array(
"Index" => "value",
"Index" => "value2",
...
);
$numerable = array(
0 => "value",
1 => "value2",
...
);
Ничего странного не замечаешь?
Если у тебя такой вопрос возникает, значит твой чатик не уютный
тг WebDevHeroes
За одинарные может быть? Вроде как доступно больше функций с одинарными кавычками, не? Не срача ради, сугубый интерес.
Дичайший быдлокод (в плане самого алгоритма), ещё и с английскими комментариями. Фу, бля.
Там индекс - целое неотрицательное число, а там - строка. Догнал, кусок долбоёба?
Страшнавыключай
Он спрашивал, что такое ассоциативный массив. К чему твой пример с повторяющимся индексом - не совсем понятно.
Потому что ты не в теме, проходи, не мешай.
Ну я и есть нубас. В прошлый раз Оп мне на ошибки указал, я их исправляю потихонечку. Сейчас еще укажет надеюсь, я снова переделаю. Так, глядишь, и научусь чему.
Всё правильно, так и надо. Только не создавай затруднения уже на начальном этапе. Смотри, как этот код примерно должен выглядеть: https://ideone.com/DyCEJU
Вот этот шкаф представляет собой массив. В нем каждый ящик может хранить только последнее положенное в него (все, что было в ящике перед тем как мы ложим туда - исчезает). Если два ящика назвать одинаково, произойдет коллапс Вселенной (шутка, просто предыдущий исчезнет и шкаф скорее всего развалится).
Посмотри на картинку и ответь на вопросы:
1) Почему некоторые ящики названы в кавычках и все ли из них нужно было в эти кавычки брать. Если не все, то какие и почему?
2) Итак у нас три документа маршируют сохраниться в ящик. Который из них останется в живых если мы откроем ящик после? Который это будет ящик?
Ох, мне аж чуть плохо не стало, подумал 1С.
1) Без ковычек числа да? 007 - ковычек не надо
2) Смотря какой порядок, если с права на лево, то выживет левый в папке index
1) не все языки простят тебе 007 в качестве ключа.
2) ну теперь то ты понял свою ошибку в $pieces["$i"]?
Надо на работе как-нибудь захерачить сразу в продакшен такое. Начальника с инфарктом скорая увезет, наверно...
Смотри, вот практически твой же код, только написанный по-человечески, сравни: https://www.ideone.com/kPx9jn
Фу, блядь, нахуй он ему язык вырвал? И почему он жёлтый?
> Выпускной сертификат от ОП-а показал быстро
Твоя опа-хреньворкщица сама сертификат не хочет показать? Или там только справка бакалавра?
Мне больше всего нравится новость про то, что в 7.4 добавят типизированные свойства классов: https://wiki.php.net/rfc/typed_properties_v2
Осталось еще $ у переменных убрать, и будет Java.
Я так понимаю, что пытался всё воткнуть в $i - т.е. это было не число как я задумывал, а именно имя $i ему уже присваивались значения, и высвечивалось последнее?
Ура! Ты молодец. Да, ты в цикле обновлял значение у текстового ключа "$i", а не добавлял новые числовые ключи $i. Впредь будь внимательнее, или я тебя заебу вопросами ты понял?
У Фаулера позаимствовал.
with
let.
Все разрешилось рестартом сервера.
Рекомендую бесплатные. Темы платных курсов можно будет изучить после, самостоятельно и бесплатно.
В наших задачах по CSS последнее задание - сверстать макет сайта. Но надо понимать, что верстка это еще не все, почти всегда например требуется использовать JS, значит надо дополнительно его изучать.
А так, в вебе никаких секретов нет и при упорстве все можно освоить бесплатно.
При этом я не говорю, что платные курсы это плохо. Если это не курсы вида "купить за деньги учебник", а например, курсы подразумевают что препод следит за успеваемостью, помогает в сложных случаях и тд, то это конечно может быть более эффективно чем самостоятельная учеба.
SQL еще.
Если твоя задача как можно быстрее делать сайты, то можно взять CMS - там вообще программирования не нужно, но сделать можно только то, что заложено в CMS или ее модули.
Такой еще вопрос от другого анона: насколько в работе (да и вообще на практике) нужно именно программирование а не использование CMS-ок?
Спрашиваю про уровень джуна со стажем. Реально ли новичку дрючить КМС-ки, так почти ничего за свою "карьеру" и не написав?
Взял бы и попробовал использовать какую-нибудь CMS. Wordpress или Drupal. Там теоретически ничего сложного, но по факту много всяких подвохов. Так что я советую изучение программирования не забрасывать.
Я изучаю для себя, хочу сделать свой проект с возможностью модернизации последующей, и чтобы голову не ломать с переделкой в дальнейшем хочется делать если не хорошо, то хотя бы правильно
>>1240285 - https://github.com/Qevg/filehosting
Извини, анончик, постараюсь глянуть в ближайшее время.
Если что, предыдущий тред доступен в архивах: https://phpclub.tech/pr/res/1232710.html
А так, вроде как проверил все посты в старом треде, вот последние непроверенные задачки. Позно, конечно, но лучше поздно, чем никогда.
>>1256038
> Калькулятор ОПа. https://3v4l.org/D5Apr
Решено верно.
> Подскажите в каком направлении плыть чтобы ввести в него поддержку десятичных знаков.
Тут есть разные подходы. Можно регуляркой разбить выражение на части, чтобы каждое дробное число или знак операции было отдельным куском строки, и преобразовать его в тип float с помощью floatval($x). А можно читать символы по одному и добавлять к строке. А перед вычислением проверить эту строку на правильность регуляркой и преобразовать в float.
>>1255784
> Ребят, вопрос по symfony - если мне нужен минимальный функционал API причем даже не CRUD, а просто ~5 эндпоинтов, мне кажется, что для этого не стоит тащить целый бандл типа api-platform/fosrestbundle и достаточно будет добавить просто эти 5 эндпоинтов в роуты?
Достаточно добавить.
>>1255400
> Аноны, что делать, если я хочу свои говноподелия просматривать с мобилки/планшета, но именно через локальный сервер?
Проще всего на компьютере в конфиге сервера поставить привязку (bind) к адресу 0.0.0.0 - это значит "слушать на всех сетевых интерфейсах" (там может стоять 127.0.0.1 - слушать только на loopback-интерфейсе, к которому нельзя подключиться снаружи). После этого посмотреть IP компьютера и зайти на него с телефона (http://192.168.x.y/).
>>1253706
> Добрый вечер, такой вопрос по системам очередей (MQ). К примеру у меня есть определенные данные которые мне в любом случае надо обработать и ни в коем случае нельзя их потерять. На данный момент я вижу, что MQ тут реально был бы кстати, но встает следующий вопрос - нормальный ли подход если я организую работу в следующем ключе:
> 1. Создаем задачу с данными
> 2. Первый Consumer создает запись в БД и Продюсит следующую задачу с обработкой
> 3. Второй Consumer обрабатывает данные и Продюсит следующую задачу
> 4. Третий Consumer получает обработанные данные и создает ещё одну задачу
> 5. Четвертый Consumer делает реквест с отправкой данных конечному адресату
> Или можно как-то по другому всё сделать? Нельзя чтобы на каком нибудь из этапов потерялись данные.
> Ещё думаю над таким вариантом
> 1. Получаем данные и создаем тут же запись в БД (молимся чтобы БД была доступна, сеть работала и запись создалась успешно), тут же создаем задачу в RabbitMQ
> 2. Первый Consumer Обрабатывает данные и продюсит следующую задачу
> 3. Получаем данные вторым Consumer, обновляем БД (снова молимся) и отправляем данные конечному получателю
> ОП и другие небезразличные помогайте
Первый вопрос, который возникает: если для выполнения задачи надо сделать несколько действий, что мешает сделать их в одном скрипте? То есть берем задачу, делаем все нужные обработки и сохраняем результаты. Зачем разбивать это на части?
А в общем тут есть 2 подхода: хранить задачу в MQ либо хранить задачу в БД, а MQ использовать для уведомления воркера о ее появлении. Подход с БД имеет тот плюс, что ты всегда можешь увидеть список и статус задач.
MQ вообще чаще используют для немного других задач, например, когда данные идут переменным потоком, а обрабаотывать их хочется не по одной записи, а пачками. MQ позводяет таким образом сглажить нагрузку - если данных придет слишком много, они просто одождут в очереди. Пример: счетчик просмотров страниц. Информация о просмотрах копится в очереди, а скрипт по расписанию вынимает пчку записей, группирует и обновляет число просмотров в БД.
В описанной тобой ситуации, если задач не слишком много, можно вообще обойтись без MQ, consumer может периодически проверять наличие новых задач в БД и выполнять их.
Что касается надежности, надо смотреть на конкретную очередь - некоторые предоставляют гарантии сохранности данных.
>>1255400
> Аноны, что делать, если я хочу свои говноподелия просматривать с мобилки/планшета, но именно через локальный сервер?
Проще всего на компьютере в конфиге сервера поставить привязку (bind) к адресу 0.0.0.0 - это значит "слушать на всех сетевых интерфейсах" (там может стоять 127.0.0.1 - слушать только на loopback-интерфейсе, к которому нельзя подключиться снаружи). После этого посмотреть IP компьютера и зайти на него с телефона (http://192.168.x.y/).
>>1253706
> Добрый вечер, такой вопрос по системам очередей (MQ). К примеру у меня есть определенные данные которые мне в любом случае надо обработать и ни в коем случае нельзя их потерять. На данный момент я вижу, что MQ тут реально был бы кстати, но встает следующий вопрос - нормальный ли подход если я организую работу в следующем ключе:
> 1. Создаем задачу с данными
> 2. Первый Consumer создает запись в БД и Продюсит следующую задачу с обработкой
> 3. Второй Consumer обрабатывает данные и Продюсит следующую задачу
> 4. Третий Consumer получает обработанные данные и создает ещё одну задачу
> 5. Четвертый Consumer делает реквест с отправкой данных конечному адресату
> Или можно как-то по другому всё сделать? Нельзя чтобы на каком нибудь из этапов потерялись данные.
> Ещё думаю над таким вариантом
> 1. Получаем данные и создаем тут же запись в БД (молимся чтобы БД была доступна, сеть работала и запись создалась успешно), тут же создаем задачу в RabbitMQ
> 2. Первый Consumer Обрабатывает данные и продюсит следующую задачу
> 3. Получаем данные вторым Consumer, обновляем БД (снова молимся) и отправляем данные конечному получателю
> ОП и другие небезразличные помогайте
Первый вопрос, который возникает: если для выполнения задачи надо сделать несколько действий, что мешает сделать их в одном скрипте? То есть берем задачу, делаем все нужные обработки и сохраняем результаты. Зачем разбивать это на части?
А в общем тут есть 2 подхода: хранить задачу в MQ либо хранить задачу в БД, а MQ использовать для уведомления воркера о ее появлении. Подход с БД имеет тот плюс, что ты всегда можешь увидеть список и статус задач.
MQ вообще чаще используют для немного других задач, например, когда данные идут переменным потоком, а обрабаотывать их хочется не по одной записи, а пачками. MQ позводяет таким образом сглажить нагрузку - если данных придет слишком много, они просто одождут в очереди. Пример: счетчик просмотров страниц. Информация о просмотрах копится в очереди, а скрипт по расписанию вынимает пчку записей, группирует и обновляет число просмотров в БД.
В описанной тобой ситуации, если задач не слишком много, можно вообще обойтись без MQ, consumer может периодически проверять наличие новых задач в БД и выполнять их.
Что касается надежности, надо смотреть на конкретную очередь - некоторые предоставляют гарантии сохранности данных.
>>1248514
> http://sandbox.onlinephpfunctions.com/code/13dd69c45baf6239448f6cf4f104365e29663936
> Привет, ОП!
> Я правильно решил эту мини-задачку из ООПа?
Да, все верно.
>>1244359
>> addEmployee(Employee $e)
> ОП, извини, что вопросов много задают тупых, но никак не могу вкурить, что ты имел ввиду под этим.
Я имел в виду, что для добавления работников в департамент можно сделать такой метод, куда передается уже созданный объект работника. Вместо того, чтобы поручать департаменту самому создавать работников.
>>1238140
> Оцените решение
> $dep <= 1000000;
Вообще, тут должно быть <, а не <=, в остальном верно.
>>1238138
Задача про группировку слов по первой букве
> lcfirst($word[0]);
Это будет работать только для латиницы, для кириллицы нет: https://github.com/codedokode/pasta/blob/master/php/strings-utf8.md
Также, у тебя там много вложенных циклов. Это все можно сделать одним циклом:
список = [];
перебираем слова {
берем первую букву;
добавляем слово в массив список[буква];
}
Ну и варнинги надо исправить:
> PHP Notice: Undefined variable: combined in /home/Y1BEf2/prog.php on line 17
> PHP Warning: in_array() expects parameter 2 to be array, null given in /home/Y1BEf2/prog.php on line 17
>>1237587
> Опчик, проверь пожалуйста задачу про ООО Вектор
> public function setRank($rank){
> switch ($rank){
> case 1:
> $this->rank = 1;
Это не удачная идея, что ты в поле rank вместо ранга сохранешь не сам ранг, а множитель. Ну представь, тебе надо будет повысить ранг работнику на один. Как ты это сделаешь?
> public function setSalary($baseSalary){
Лучше было назвать setBaseSalary(), чтобы не путать базовую ставку и итоговую зарплату.
> class Manager extends Employee{
> protected $coffeeConsumption = 20;
У тебя наследник Employee должен определить зарплату, кофе итд. Но это никак не документировано и не проверяется. Лучше использовать абстрактные методы, чтобы решить эту проблему:
abstract function getBaseSalary();
В остальном верно.
Ждем версию с антикризисными мерами.
>>1238138
Задача про группировку слов по первой букве
> lcfirst($word[0]);
Это будет работать только для латиницы, для кириллицы нет: https://github.com/codedokode/pasta/blob/master/php/strings-utf8.md
Также, у тебя там много вложенных циклов. Это все можно сделать одним циклом:
список = [];
перебираем слова {
берем первую букву;
добавляем слово в массив список[буква];
}
Ну и варнинги надо исправить:
> PHP Notice: Undefined variable: combined in /home/Y1BEf2/prog.php on line 17
> PHP Warning: in_array() expects parameter 2 to be array, null given in /home/Y1BEf2/prog.php on line 17
>>1237587
> Опчик, проверь пожалуйста задачу про ООО Вектор
> public function setRank($rank){
> switch ($rank){
> case 1:
> $this->rank = 1;
Это не удачная идея, что ты в поле rank вместо ранга сохранешь не сам ранг, а множитель. Ну представь, тебе надо будет повысить ранг работнику на один. Как ты это сделаешь?
> public function setSalary($baseSalary){
Лучше было назвать setBaseSalary(), чтобы не путать базовую ставку и итоговую зарплату.
> class Manager extends Employee{
> protected $coffeeConsumption = 20;
У тебя наследник Employee должен определить зарплату, кофе итд. Но это никак не документировано и не проверяется. Лучше использовать абстрактные методы, чтобы решить эту проблему:
abstract function getBaseSalary();
В остальном верно.
Ждем версию с антикризисными мерами.
Вообще, там была идея сделать объекты без классов, на прототипах. Вот тут вот https://medium.com/@benastontweet/lesson-1a-the-history-of-javascript-8c1ce3bffb17 пишут, что автор вдохновлялся языками Java, Scheme и Self (можешь почитать про последние 2 для расширения кругозора).
В традиционном ООП мы описываем класс с полями и методами, при желании наследуем классы, а затем создаем объекты этих классов. В прототипном подходе классы выкидывают как ненужную сущность и объекты создают из других объектов с помощью "наследования" через прототипы.
Класс с полями и методами из традиционного ООП в прототипном заменен на базовый объект с методами. Операции наследования классов и создания объекта класса в прототипном ООП заменены на одну операцию создания нового объекта.
То есть мы создаем "базовый" объект такого вида:
var basePerson = {
setSalary: function (s) { this.salary = s; },
getSalary: function() { return this.salary; },
getName: function() { return this.name; }
};
А затем от него создаем (наследуем) уже конкретные объекты:
var ivan = Object.create(basePerson, { name: "Ivan", salary: 100 });
var peter = Object.create(basePerson, { name: "Peter", salary: 200 });
console.log(peter.getName());
Object.create() создает новый объект с указанным прототипом и свойствами.
Для удобства, можно добавить функцию-конструктор для создания объектов:
functon newPerson(name, salary) {
return Object.create(basePerson, { name: name, salary: salary });
}
var sidor = newPerson('Sidor', 300);
Как видишь, это похоже на традиционный ООП, где классы сделаны в виде объектов.
Наследование базовых объектов делается аналогично созданию:
var baseManager = Object.create(basePerson, {
getSubordinates: function () { ... },
setSubordinates: function () { ... }
});
var fedor = Object.create(baseManager, { ... });
Правда, в первоначальных версиях ES3 почему-то не сделали Object.create(), а заставили создавать объекты только через конструкторы:
// Код, что и выше, но в версии для ES3
function Person(name, salary) {
this.name = name;
this.salary = salary;
}
Person.prototype = basePerson;
var sidor = new Person('Sidor', 300);
Из-за отсутствия Object.create() наследование базовых объектов в ES3 делается очень коряво и я не рискну написать его по памяти.
В таком подходе есть и плюсы - например, здесь базовый объект можно передавать в функцию (в PHP класс нельзя передать или сохранить в переменную, только имя класса). В некоторых ООП-языках, впрочем, для классов есть представляющие их объекты:
- в Яве: https://docs.oracle.com/javase/7/docs/api/java/lang/Class.html
- в Руби: https://ruby-doc.org/core-2.5.1/Class.html
Ну и в общем прототипный ООП как-то не очень нашел поддержку и люди начали писать библиотеки для имитации традиционного ООП на классах. А в ES6 завезли синтаксис для описания классов, правда самих классов фактически по прежнему нет.
Вообще, там была идея сделать объекты без классов, на прототипах. Вот тут вот https://medium.com/@benastontweet/lesson-1a-the-history-of-javascript-8c1ce3bffb17 пишут, что автор вдохновлялся языками Java, Scheme и Self (можешь почитать про последние 2 для расширения кругозора).
В традиционном ООП мы описываем класс с полями и методами, при желании наследуем классы, а затем создаем объекты этих классов. В прототипном подходе классы выкидывают как ненужную сущность и объекты создают из других объектов с помощью "наследования" через прототипы.
Класс с полями и методами из традиционного ООП в прототипном заменен на базовый объект с методами. Операции наследования классов и создания объекта класса в прототипном ООП заменены на одну операцию создания нового объекта.
То есть мы создаем "базовый" объект такого вида:
var basePerson = {
setSalary: function (s) { this.salary = s; },
getSalary: function() { return this.salary; },
getName: function() { return this.name; }
};
А затем от него создаем (наследуем) уже конкретные объекты:
var ivan = Object.create(basePerson, { name: "Ivan", salary: 100 });
var peter = Object.create(basePerson, { name: "Peter", salary: 200 });
console.log(peter.getName());
Object.create() создает новый объект с указанным прототипом и свойствами.
Для удобства, можно добавить функцию-конструктор для создания объектов:
functon newPerson(name, salary) {
return Object.create(basePerson, { name: name, salary: salary });
}
var sidor = newPerson('Sidor', 300);
Как видишь, это похоже на традиционный ООП, где классы сделаны в виде объектов.
Наследование базовых объектов делается аналогично созданию:
var baseManager = Object.create(basePerson, {
getSubordinates: function () { ... },
setSubordinates: function () { ... }
});
var fedor = Object.create(baseManager, { ... });
Правда, в первоначальных версиях ES3 почему-то не сделали Object.create(), а заставили создавать объекты только через конструкторы:
// Код, что и выше, но в версии для ES3
function Person(name, salary) {
this.name = name;
this.salary = salary;
}
Person.prototype = basePerson;
var sidor = new Person('Sidor', 300);
Из-за отсутствия Object.create() наследование базовых объектов в ES3 делается очень коряво и я не рискну написать его по памяти.
В таком подходе есть и плюсы - например, здесь базовый объект можно передавать в функцию (в PHP класс нельзя передать или сохранить в переменную, только имя класса). В некоторых ООП-языках, впрочем, для классов есть представляющие их объекты:
- в Яве: https://docs.oracle.com/javase/7/docs/api/java/lang/Class.html
- в Руби: https://ruby-doc.org/core-2.5.1/Class.html
Ну и в общем прототипный ООП как-то не очень нашел поддержку и люди начали писать библиотеки для имитации традиционного ООП на классах. А в ES6 завезли синтаксис для описания классов, правда самих классов фактически по прежнему нет.
В js есть только объекты. Больше ничего.
Есть еще примитивы, но их можно тоже рассматривать в качестве синглтон объектов, потому как они боксятся, а сделаны разумеется для производительности. (тем более что сейчас ничего не мешает у примитивных добавить в цепочку прототипов прокси объект, отлавливащий сообщения, типа присваивания, и реалиховать поведение прототипов как полноценных объектов, но это ни к чему. проще воспринимать их как синглтоны. когда надо, любой примитив можно обернуть в полноценный независимый объект).
Так. Короче только объекты.
Все объекты делятся на callable и non-callable. Callable это функции, в понимании большинства. Но по факту это все те же объекты, со всеми свойствами что и у других.
Все объекты могут принимать всего несколько типов сообщений - get, set и call. При чем call может принимать только callable объект. при попытке послать call сообщение не-callable объекту будет исключение.
Сообщение get содержит один параметр, сообщение set два. Сообщение call параметром содержит кортеж аргументов, а так контекст this.
Если в объекте (а так же в цепочке прототипов) не назначены слушатели для get и set с определенными параметрами, ищутся слоты с такими именами в объекте и по цепочке. Если находится возвращается то, что в них лежит. Если в них лежит callable объект и ему посылают сообщние call сразу как получили его из слота, то у него будет перегружен контекст (this) на объект из чьего слота его получили. Если только этот объект не был сконструирован стрелочным синтаксисом, иначе контекст перегрузить нельзя. Если после получение callable объекта из слота его сразу не вызвать, а например положить ссылку на него в переменную, то контекст будет сброшен на тот, который был установлен у него в момент его создания (и это не обязательно будет тот же объект из чьего слота его получили).
У callable объектов есть scope (область видимости) и контекст (this) в момент посылки им сообщения call (вызова). scope средствами языка перегрузить нельзя (на самом деле частично можно изъебнуться с помощью eval), но некоторые окружения позволяют (например в ноде есть модеуль vm), this перегружается у callable объектов сконструированных не-стрелочным синтаксисом
Классов нет. Есть конструкторы. Любой конструктор принимает новый созданный объект, которому выставлен определенный прототип (другой объект). Оператор instanceof (someObject instanceof SomeClassName) проверяет лишь есть ли в цепочке прототипов у someObject объект который лежит у SomeClassConstructor в слоте с именем prototype. На сам конструктор ему поебать. Чтобы сменить класс, достаточно сменить цепочку прототипов. Даже если объект был сконструированным определенным конструктором.
Так же у объектов есть параметр ограничения доступа, контролирующие его расширяемость или изменяемость (sealed, extensible, frozen). У слотов объекта есть параметры configurable, enumerable, writable. Параметры слотов объекта не влияют на объекты, что в них лежат. Они лишь контролируют доступ к самим слотам.
Все. Никаких классов. Никаких интерфейсов. Как отдельных сущностей. По факту все есть объект и все строит из них.
наследование реализуется выстраиванием цепочки прототипов. Инкапсуляция только на уровне scope'в (читай замыканий).
В остальном все меняется и все динамично, если только специально все не зафризить в момент конструирования. Но обычно этим никто не заморачивается по причине оверхеда и бессмысленности. Разве только фанатики по иммутабельности, н это все из разряда те, кому надо чтобы им по рукам бил компилятор\рантайм\дядя петя. Все "привычные" понятия тянуться в язык для еще более простого вкатывания тех, кто приходит из других языков. Так уж сложилось, что есть куча литературы по привычному, статически классовому ООП, но очень мало по мессадж-пассинг\прототайп-базед\мета-программинг. Все эти притянутые понятия выливают в синтаксический сахар, который не делает ничего полезного, а даже наоборот, еще больше вносит путаницы и от того непонимамания многих вещей в языке. При этом часто этот синтаксический сахар дэже урезан и вспомнинают об этом лишь после (как например проебались с полями в конструкции class и тянут ее теперь только в proposol'ах будущих версий).
JS истинно объектный язык. В современный язык притащили много вкусных вещей для метапрограммирования. Нову примитивную сущность Symbol, и Proxy-объекты. С помощью которых можно еще больше и сильнее перегружать и менять поведение в динамике.
Другое дело, что почти никто не умеет этим пользоваться и не понимает, что такое объектное программирование на самом деле.
Им нужно не объектное, а статически типизированное. А какие именно структуры будут скрываться за этими типами, не собо важно. Важно что это просто структуры и функции, строго привязанные к ним, или иногда менее строго. То, что в Java\C++ это больше структурное программирование, нежели объектное. Объектное программирование не может существовать без динамической среды. Это противоречит самому понятию объекта. А динамическое программирование это слишком сложна и непанятна. И как бы не старались с пеной у рта фанатики кричать про низкий порог входа - низкий он именно что для входа, а не для всего остального. Модификация программ в рантайме всегда было уделом креативно мыслящих людей. Для большинства это слишком сложный уровень высокой абстракции.
В js есть только объекты. Больше ничего.
Есть еще примитивы, но их можно тоже рассматривать в качестве синглтон объектов, потому как они боксятся, а сделаны разумеется для производительности. (тем более что сейчас ничего не мешает у примитивных добавить в цепочку прототипов прокси объект, отлавливащий сообщения, типа присваивания, и реалиховать поведение прототипов как полноценных объектов, но это ни к чему. проще воспринимать их как синглтоны. когда надо, любой примитив можно обернуть в полноценный независимый объект).
Так. Короче только объекты.
Все объекты делятся на callable и non-callable. Callable это функции, в понимании большинства. Но по факту это все те же объекты, со всеми свойствами что и у других.
Все объекты могут принимать всего несколько типов сообщений - get, set и call. При чем call может принимать только callable объект. при попытке послать call сообщение не-callable объекту будет исключение.
Сообщение get содержит один параметр, сообщение set два. Сообщение call параметром содержит кортеж аргументов, а так контекст this.
Если в объекте (а так же в цепочке прототипов) не назначены слушатели для get и set с определенными параметрами, ищутся слоты с такими именами в объекте и по цепочке. Если находится возвращается то, что в них лежит. Если в них лежит callable объект и ему посылают сообщние call сразу как получили его из слота, то у него будет перегружен контекст (this) на объект из чьего слота его получили. Если только этот объект не был сконструирован стрелочным синтаксисом, иначе контекст перегрузить нельзя. Если после получение callable объекта из слота его сразу не вызвать, а например положить ссылку на него в переменную, то контекст будет сброшен на тот, который был установлен у него в момент его создания (и это не обязательно будет тот же объект из чьего слота его получили).
У callable объектов есть scope (область видимости) и контекст (this) в момент посылки им сообщения call (вызова). scope средствами языка перегрузить нельзя (на самом деле частично можно изъебнуться с помощью eval), но некоторые окружения позволяют (например в ноде есть модеуль vm), this перегружается у callable объектов сконструированных не-стрелочным синтаксисом
Классов нет. Есть конструкторы. Любой конструктор принимает новый созданный объект, которому выставлен определенный прототип (другой объект). Оператор instanceof (someObject instanceof SomeClassName) проверяет лишь есть ли в цепочке прототипов у someObject объект который лежит у SomeClassConstructor в слоте с именем prototype. На сам конструктор ему поебать. Чтобы сменить класс, достаточно сменить цепочку прототипов. Даже если объект был сконструированным определенным конструктором.
Так же у объектов есть параметр ограничения доступа, контролирующие его расширяемость или изменяемость (sealed, extensible, frozen). У слотов объекта есть параметры configurable, enumerable, writable. Параметры слотов объекта не влияют на объекты, что в них лежат. Они лишь контролируют доступ к самим слотам.
Все. Никаких классов. Никаких интерфейсов. Как отдельных сущностей. По факту все есть объект и все строит из них.
наследование реализуется выстраиванием цепочки прототипов. Инкапсуляция только на уровне scope'в (читай замыканий).
В остальном все меняется и все динамично, если только специально все не зафризить в момент конструирования. Но обычно этим никто не заморачивается по причине оверхеда и бессмысленности. Разве только фанатики по иммутабельности, н это все из разряда те, кому надо чтобы им по рукам бил компилятор\рантайм\дядя петя. Все "привычные" понятия тянуться в язык для еще более простого вкатывания тех, кто приходит из других языков. Так уж сложилось, что есть куча литературы по привычному, статически классовому ООП, но очень мало по мессадж-пассинг\прототайп-базед\мета-программинг. Все эти притянутые понятия выливают в синтаксический сахар, который не делает ничего полезного, а даже наоборот, еще больше вносит путаницы и от того непонимамания многих вещей в языке. При этом часто этот синтаксический сахар дэже урезан и вспомнинают об этом лишь после (как например проебались с полями в конструкции class и тянут ее теперь только в proposol'ах будущих версий).
JS истинно объектный язык. В современный язык притащили много вкусных вещей для метапрограммирования. Нову примитивную сущность Symbol, и Proxy-объекты. С помощью которых можно еще больше и сильнее перегружать и менять поведение в динамике.
Другое дело, что почти никто не умеет этим пользоваться и не понимает, что такое объектное программирование на самом деле.
Им нужно не объектное, а статически типизированное. А какие именно структуры будут скрываться за этими типами, не собо важно. Важно что это просто структуры и функции, строго привязанные к ним, или иногда менее строго. То, что в Java\C++ это больше структурное программирование, нежели объектное. Объектное программирование не может существовать без динамической среды. Это противоречит самому понятию объекта. А динамическое программирование это слишком сложна и непанятна. И как бы не старались с пеной у рта фанатики кричать про низкий порог входа - низкий он именно что для входа, а не для всего остального. Модификация программ в рантайме всегда было уделом креативно мыслящих людей. Для большинства это слишком сложный уровень высокой абстракции.
Примитив это все же не объект. Простой пример:
var a = 6;
a.x = 1;
console.log(a.x); // undefined
ты охуенен. Посоветуй литературу для развития или сайты. Да чего угодно. Не доку по жс или реакту, а вообще что-то типо шаблонов и современном программировании, подходов к разработке и т.д. что "сложна и непанятна".
>Модификация программ в рантайме всегда было уделом креативно мыслящих людей. Для большинства это слишком сложный уровень высокой абстракции.
Читай внимательнее
> их можно тоже рассматривать в качестве синглтон объектов
И во-первых - пик 1.
Во-вторых - пик 2.
Нифига себе волшебство.
Пиши на тупскрипте, никто не запрещает.
>динамическое типизирование
php, python, lua, perl - тоже запретить?
Может еще беспартийных расстреливать?
Можно, но для такой простой задачи тащить огромный фреймворк смысла мало, так как в нем уже все сделано на готово. Предполагается, что простую задачу ты делаешь на микрофреймворке, чтобы разобраться как устроено веб-приложение, а большой фреймворк берешь для более сложных задач вроде TestHub.
Ну ты попробуй, давай посмотрим, что получится.
Еще вопрос, какой лучше делать максимальный размер файла, и хранить ли его вечно или какой-то срок?
>>72269
Вообще, ты прав. Как-то слишком все просто выйдет через Ларавел.
$a = '\x61';
$b = "\x61"
Если сделать var_dump, в первом случае выведется, как есть. Во втором случае выведется "a".
Что это за кодировка?
Как работают двойные кавычки по декодингу таких сущностей?
И как в php раскодировать переменную $a, чтобы в дампе было тоже "a"?
Так, символ в шестнадцатеричной системе, понял. Значит двойные кавычки такую последовательность сами конвертируют. А как все-таки быть и одинарными кавычками?
А никак, в одинарных кавычках ничего не сконвертируется. Баш напоминает. И вообще я мимокрокодил.
Блин, как же быть?
Мне один сервис отдает данные в виде такой строки: '\x61\x61\x61'
И мне ее надо у себя на сайте сконвертировать в читаемые символы.
Зацените мой YodaSpeak(хотя скорее Yoba). Короче смотрите и завидуйте моему изящному коду))) Кста тз перепутал и теперь йода рандомом пиздит лол
https://repl.it/@Ninogi/UncomfortableWickedTransformations
Ты, к сожалению, плохо прочел мануал.
Экранирующие последовательности работают только если ты пишешь их прямо в коде:
$a = "\x41";
Здесь при разборе строки PHP заменит \x41 на A и сохранит в память строку "A" (без кавычек). То есть экранирующие посл-ти работают только в строках в коде на этапе разбора программы. В ходе работы программы строки хранятся в памяти уже в преобразованном виде и обработка бекслешей не производится.
То есть эти последовательности нужны только для записи в коде символов, которые нельзя набрать на клавиатуре, вроде \n.
Если во время выполнения программы у тебя в переменной хранится строка вида "\x..." то с ней ничего делаться не будет.
Однако, есть функции как stripslashes и stripcslashes. Почитай про них.
Анон, ты наверное не понял.
Вот есть у меня переменная $a:
$a = '\x41';
Во время работы скрипта, в переменной будет именно строка из символов '\x41' без всяких преобразований.
Так вот, как мне дальше в скрипте значение переменной $a преобразовать в символ A?
>Так вот, как мне дальше в скрипте значение переменной $a преобразовать в символ A?
в двойные кавычки ебани echo "\x41";
мимикрокодил
ууу, как же сложно-то.
$a = '\x41';
$b = pseudo_convert($a);
echo $b; // A
вот так возможно сделать какой-либо функцией?
Энкодинг бесполезен. На моменте интерпретации строки в двойных кавычках, уже будет получен символ А.
Наконец-то решение.
Только вот так будет правильно: echo pack("H*", '41');
Как же быть со строкой '\x41\x41\x41\x41'?
preg_match'ем искать цифры, потом их прогонять через pack и склеивать?
>preg_match'ем искать цифры, потом их прогонять через pack и склеивать?
Да))
Когда приходить такое - это пиздец.
Если это приходит с какого-то сервера то значит сериализация запорота
>symphony
symfony
>Laravel
На счет него лучше других людей не слушать.
Очень распиарен, много промыток, которые будут говорить, ларавелевские практики это бест практис.
Надо самому пробовать.
Сам пробовал и то и это.
Говнокод есть и там и там, но ларавельщики вообще тупые нахуй какие-то.
>алгоритмы и структуры данных
Любое нормальное тех. собеседования и этого и начинается. Это основа, дебил. Если ты, чмо тупое, не знал об этом, то не теряй время, а читай учебники и решай задачи. Через годик освоишь.
>> Извини, анончик, постараюсь глянуть в ближайшее время.
в выходные doker and CI постараюсь прикрутить
вот тут ещё сделал рефакторинг и написал тесты
https://github.com/Qevg/Student-list
На веб-макакия? Нет, в основном.
Бывает, элементарщину спрашивают.
Пару раз было просили что то реализовать, но они ебанатами были полными.
Пыхеру редко когда это все надо, особенно крудошлепам уоторые магазины по продаже бисера пишут.
А вот про стандатные структуры типа \SplQueue, часто спрашивают.
Так что если сможешь объяснить что это и нахуя нужно, то нехило так блеснешь знаниями
Указал в конфиге апача :
LoadModule rewrite_module modules/mod_rewrite.so
<Directory "${SRVROOT}/htdocs">
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>
<VirtualHost *:8080>
DocumentRoot "${SRVROOT}/htdocs/megafun/public"
ServerName megafun
</VirtualHost>
Перезапустил апач.
А теперь вопрос, почему это нихуя не работает?
Ты не написал, что ты делаешь и что происходит, в чем именно ошибка.
В hosts имя домена прописал? Если нет, то почему? Если не прописал, то подумай, что делает браузер при вводе адреса сайта.
Если прописал, то что получается при попытке открыть сайт? Что в логе ошибок Апача?
>Ты не написал, что ты делаешь и что происходит, в чем именно ошибка.
Это называется недосып, совсем крыша поехала.
А проблему я уже решил.
Спасибо. Элементарщина, это типа найти сложность алгоритма и что это вообще такое, чем отличается сортировка слиянием и пузырьком с точки зрения времени выполнения, ну и всё в этом духе?
Все на чем можно набирать текст в текстовый редактор подойдет.
Если денег не жалко, то 13 + дюймов на базе интела от 8gb оперативки, ssd 128gb+ и батарея поживучей (тут главное не купить "планшет в корпусе ноутбука"). Среди моих знакомых сейчас в тренде синкпады, т.к. последние Макбуки Про пугают все постоянными косяками с клавиатурой.
>Элементарщина, это типа найти сложность алгоритма и что это вообще такое, чем отличается сортировка слиянием и пузырьком с точки зрения времени выполнения, ну и всё в этом духе?
Просто, какие знаешь, чем отличаются
https://github.com/richBlueElephant/phpClub/issues/90
Нужно написать класс обёртку над массивом ключ => значение. Необходимо иметь поле с самим массивом хлебных крошек, и пару методов для добавления и получения их. А также, в идеале, написать красивые стили для них.
https://ru.wikipedia.org/wiki/Навигационная_цепочка
Необходимые знания:
-Умение пользоваться Composer'ом, чтобы развернуть проект у себя на локальной машине.
-Минимальное знание ООП, чтобы написать простой класс.
-Минимальное знание git.
Чему вы можете научится выполняя эту задачу:
-Разворачивать рабочий "боевой" проект, на своей локальной машине.
-Применять свои знания на, опять же, боевом проекте.
-Делать Pull Request'ы, которые просто необходимо уметь.
Чувствуйте себя свободно задавать если есть какие-то вопросы.
Думаю, дело хорошее, надо помочь. Если у кого-то есть немного времени (ну ок, если вы начинающий, то совсем быстро разобраться не получится), и есть желание поковыряться в коде, поработать с более-менее реальным проектом, то пожалуйста - зарегистрируйтесь на гитхабе (бесплатно, без СМС) и отпишитесь в задаче. Если что-то непонятно, то вопросы можно задать тут тоже.
Если, например, вы сейчас готовитесь делать задачу про студентов, или делаете, то у вас знаний вполне достаточно.
Проверь, нет ли в нем неприятных ограничений. Например, я сталкивался с ноутом, где стояло ограничение на 4 Гб памяти (больше нельзя поставить).
>1366x768
Я б нистал меньше 1080p. В /hw/ есть тред синкпадо-анонов, есть смысл с ними проконсультироваться для твоего бюджета. Может можно L380 дешево проапгрейдить.
Да-да, работаем и все благодаря этому треду.
>ну ок, если вы начинающий, то совсем быстро разобраться не получится
А вот не нужно пугать начинающих! Всё получится если иметь желание и энтузиазм разобраться. Главное начать и, если что-то непонятно, задать правильный вопрос.
Уже опередили.
Но ничего страшного! Ты всё равно можешь взяться с какое-нибудь другое issue и добавиться к нам в конфу в слаке ( https://join.slack.com/t/phpclub-group/shared_invite/enQtMzA2MjcyMTAwNjc5LTNlZTI3ZjE5MTgyZWVhZjc3MmMyMzlhZGJmYTg0ODQ3YjAzYWRmMGNjZmJhYjdlMWFhZjg5MzNhNWE1YzdmNjc ).
К примеру, у нас есть такая же супер простая задача для рефактиринга валидации https://github.com/richBlueElephant/phpClub/issues/10
Если ты делаешь "Студентов" или уже сделал, то знаний вполне хватит чтобы с ней справиться.
Чувствую себя свободно задавать любые вопросы.
Здравствуйте, господа. Пишет вам java-собрат. Пару дней назад получил от знакомого заказ на wordpress интернет магазин, вполне стандартный, с онлайн конрзиной, оплатой и избранным. Локация ДС
Никогда не занимался таким, но сложно не должно быть. Сколько ценник ломить?
Как белые люди делают?
Подскажите, вот у ОПа в задаче про список студентов предлагается каждого студента делать объектом, но зачем это мне?
В любом случае обработка действия это обращение к БД->получение данных->формирование таблицы, зачем мне добавлять еще шаг ->загнать данные в объекты-> перед формированием таблицы?
И вообще, мускль неплохо так и в командную строку выводит в виде таблицы, может мне просто скриншот отдавать, и обращений к БД не надо никаких, профит.
Прописываю Вам регулярный просмотре аниме 2 раза в сутки, утром и вечером.
А я люблю обмазываться объектами когда делаю студентов. Каждый день я хожу по земле с черным блокнотом и собераю в него все сущности которые могу придумать. На два полных блокнота целый день уходит. Зато, когда после тяжёлого дня я прихожу домой, сажусь за пеку, включаю любимую IDE…ммм и сваливаю в нее свое сокровище. И набираю, представляя, что меня поглотил единый организм Object. Мне вообще кажется, что объекты, умеют думать, у них есть свои семьи, города, чувства, не прекращайте плодить сущности, лучше приютите у себя, говорите с ними, ласкайте их…. А вчера в ванной, мне преснился чудный сон, как будто я нырнул в море, и оно прератилось в интерфейс, рыбы, водоросли, медузы, все в виде объектов, даже небо, даже Аллах!.
Содомит
Вот такая поебень, зачем?
Вообще, твой вопрос абсолютно правильный. Разумеется, переусложнение кода просто так и добавление ненужных частей - это плохо.
Но давай я отвечу вопросом на вопрос и спрошу: а какие плюсы/минусы есть у представления студента в виде массива или в виде объекта?
Подсказка: ну например, представь, что речь идет не про студентов, а про какой-то проект больше размером, который писал не ты, и с которым ты разбираешься. И ты видишь 2 функции: одна получает на вход данные в виде массива, другая в виде объекта:
function f1(array $student) { ... }
function f2(Student $student) { ... }
В какой функции будет проще разобраться?
Также, предполагается, что функция получения студентов универсальная и может использоваться не только для вывода таблицы. Ну например, может быть мы поменяли правила валидации и хотим перепроверить всех студентов в БД на соответствие им.
Соответственно, исходя из плюсов/минусов мы и выбираем нужный вариант.
Вопрос по ООП-Будильнику.
Как лучше реализовать изменение параметров Alarm, через AlarmClock?
В каких случаях стоит использовать выбрасывание исключений?
Спасибо.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<?php
if (!$_COOKIE["NumVisited"]) {
setcookie("NumVisited", 1, time() + 1800);
} else {
$_COOKIE["NumVisited"]++;
}
var_dump ($_COOKIE["NumVisited"]);
?>
</body>
</html>
Вылезает Warning: Cannot modify header information - headers already sent by (output started at C:\блаблабла.php) in C:\блаблабла.php on line 16
Что с этим делать? В гугле какой-то пиздеж про запятые и про header(), но ничего все равно не работает.
Это зависит от того, как ты реализуешь архитектуру.
Если ты делаешь все одним классом, то выбор только один. Если ты для каждой тревоги делаешь свой объект, то логичнее менять ее свойства через него.
Желательно проектировать АПИ (набор методов для управления будильником) так, чтобы они были удобными в использовании, логичными (не требовали лишних аргументов), защищали от ошибок.
Исключение выбрасывается, если функции переданы некорректные данные (например: время 25 часов 99 минут) или она из-за непредвиденных обстоятельств не может выполнить свою работу. Урок: https://github.com/codedokode/pasta/blob/master/php/exceptions.md
Во-первых, если ты не слышал про HTTP, то прочитай что-нибудь про него, без этого никак, например, тут: https://github.com/codedokode/pasta/blob/master/network/http.md
Во-вторых, а как по-твоему работает функция setcookie? Она, очевидно, добавляет в HTTP-ответ HTTP заголовок. Но HTTP заголовки в HTTP-ответе должны идти до тела ответа, а вывод HTML кода начинает отдачу тела ответа.
Понел, спасибо.
https://ideone.com/kLyMgg
Я идиот, простите. В строке
>if (($anonDice1 == $anonDice2) && ($compDice1 == $compDice2)) {
забыл закрыть вторую скобку. Теперь все работает
Зачем тебе вообще скобки в этом выражении?
jdoodle.com/a/HQs
Новый айПад
jdoodle.com/a/HQJ
Стих
jdoodle.com/a/H4L
Да
>jdoodle.com/a/G3e
это не кодерский подход. А если тебе скажут группировать по сочетанию первых двух букв? Будешь уже 32x32 ифов писать?
Этот сайт не дает сохранять без регистрации, так что только скрин.
$haystack = 'name';
$needle = '9763215619';
есть выражения:
$stmt = $this -> mysqli -> prepare("SELECT FROM table WHERE ? LIKE ? ORDER BY file_id DESC");
$stmt -> bind_param('ss', $haystack, $needle);
Когда делаю execute выдает ноль рузультатов, а если просто делаю:
$stmt = $this -> mysqli -> prepare("SELECT FROM table WHERE name LIKE '9763215619' ORDER BY file_id DESC");
все работает. В чем может быть проблема?
Ты хотел сделать WHERE name LIKE '1234'
А получилось WHERE 'name' LIKE '1234'
То есть сравнение строки со строкой.
Для подстановки имени колонки придется вставлять ее прямо в запрос, предварительно проверив по белому списку:
$allowed = ['name', 'age'];
if (!in_array($field, $allowed)) {
throw new \Exception(...);
}
...prepare("... WHERE `$field` LIKE ? ... ");
Нет, это нормально. Ты можешь подставить сам:
$query = "select * from table where {$name} like ?";
Но если ты берешь это из инпута, то обязан проверить. Например сперва прогнать через белый список.
Как. Здравствуйте, товарищъ Хайвмайнд.
/ ?([+] ?7 ?-?| ?8) ?-? ?[(]? ?[0-9]?[0-9] ?-?[0-9] ?-?[0-9] ?-? ?[)]? ?-? ?[0-9] ?-? ?[0-9] ?-? ?[0-9] ?-? ?[0-9] ?-? ?[0-9] ?-? ?[0-9] ?-? ?[0-9]?/
В яваскрипте словари ({ a: 1, b:2}) не сохраняют порядок элементов. Они лишь используются для сопоставления ключей и значений. Массивы сохраняют порядок, но в них ключи числовые и идут по порядку.
А в PHP массивы сохраняют порядок и объединяют в себе функционал массивов и словарей из JS.
Такой комментарий несет мало пользы, если не содержит подсказок или объяснения, что именно плохо.
В данном случае надо избавиться от повторов в регулярке. Дам подсказку, как это сделать.
Допустим, у нас есть выражение для "одной буквы": [a-z]. Чтобы записать "от 2 до 5 букв", можно использовать фигурные скобки: [a-z]{2,5}.
Да понятно. Пришлось это обходить заворачиванием в новый массив, в котором под нулевым ключем все ключи, а под первым все значения. Тогда порядок можно сохранить.
это в лоб, прочитай условия задачи и примеры внимательно
function getSmtn()
{
$loop = \React\EventLoop\Factory::create();
$connector = new \React\Socket\Connector($loop);
$connector->connect('...')->then(function (\React\Socket\ConnectionInterface $connection) use ($loop) {
$connection->on('data', function ($data) use ($connection) {
$smtn = $data;
$connection->close();
});
});
$loop->run();
return $smtn;
}
Асинхронная функция не может вернуть результат сразу. Обычно они возвращают промис, который позже раскроется либо в результат, либо в исключение.
$promise = getSmtnAsync();
$promise->done(...);
У промисов PHP есть неприятная особенность, в сравнении с JS промисами: они не сообщают об необработанных исключениях. Если ты не поставил обработчик (в done/then), то исключение просто потеряется. А ведь это может быть любое исключение, в том числе ErrorException вызванное например опечаткой в имени переменной или функции.
Аналогично, в PHP ошибки чтения/записи в поток по умолчанию игнорируются, если ты не поставил обработчик на on('error', ...). В общем, обработка ошибок сделана максимально плохо.
В твоем коде вообще логичнее всего было бы вернуть объект connection. Если же надо прочитать все данные до конца, тогда надо их читать в функции и по окончанию передать в промис через Deferred:
$def = new Deferred();
// На основании исследования пальца и потолка я решил что это эффективнее, чем строка. В реальности лучше проверить тестами.
$buffer = [];
$connection->on('data', function ($d) use ... { $buffer[] = $d });
$connection->on('error', function ($e) .. { $def->reject(4e); });
$connection->on('end', function () {
$content = implode('', $buffer);
$def->resolve($content);
});
return $def->promise();
Тут только надо проверить последовательность прихода событий, чтобы например ошибка не потерялась, если end приходит раньше error.
Не забывай, обработка ошибок сделана максимально плохо и тебе надо делать ее полностью самостоятельно.
Асинхронная функция не может вернуть результат сразу. Обычно они возвращают промис, который позже раскроется либо в результат, либо в исключение.
$promise = getSmtnAsync();
$promise->done(...);
У промисов PHP есть неприятная особенность, в сравнении с JS промисами: они не сообщают об необработанных исключениях. Если ты не поставил обработчик (в done/then), то исключение просто потеряется. А ведь это может быть любое исключение, в том числе ErrorException вызванное например опечаткой в имени переменной или функции.
Аналогично, в PHP ошибки чтения/записи в поток по умолчанию игнорируются, если ты не поставил обработчик на on('error', ...). В общем, обработка ошибок сделана максимально плохо.
В твоем коде вообще логичнее всего было бы вернуть объект connection. Если же надо прочитать все данные до конца, тогда надо их читать в функции и по окончанию передать в промис через Deferred:
$def = new Deferred();
// На основании исследования пальца и потолка я решил что это эффективнее, чем строка. В реальности лучше проверить тестами.
$buffer = [];
$connection->on('data', function ($d) use ... { $buffer[] = $d });
$connection->on('error', function ($e) .. { $def->reject(4e); });
$connection->on('end', function () {
$content = implode('', $buffer);
$def->resolve($content);
});
return $def->promise();
Тут только надо проверить последовательность прихода событий, чтобы например ошибка не потерялась, если end приходит раньше error.
Не забывай, обработка ошибок сделана максимально плохо и тебе надо делать ее полностью самостоятельно.
Я вижу, анон запутался. Давайте ему поможем.
Итак. Дана другая задача: напишите регулярку, которая проверит математическое выражение на правильность. Математическое выражение может состоять из целых неотрицательных чисел, знаков + и -, и пробелов.
Примеры:
Правильные выражения:
123
1+2+3
1+3-2
Неправильные:
xyz (это не число)
-2 (у нас в задаче нет отриц. чисел)
1++2 (2 знака подряд)
1 2 (нет знака между числами)
Пишем регулярку. Структуру выражения можно записать как:
число знак число знак число ...
Как это выразить регуляркой? Здесь можно использовать звездочку, чтобы сказать, что за первым числом могут следовать еще произвольное количество чисел, отделенных знаками:
число (знак число)*
Продолжим. Как записать "число" в виде регулярки? Это просто 1 или более цифр:
число = [0-9]+
Знак это плюс или минус: [+\-]
Соберем это вместе:
^[0-9]+([+\-][0-9]+)*$
Наконец, надо учесть наличие необязательных пробелов между числами и знаками и мы получим итоговое выражение:
^\s*[0-9]+\s*([+\-]\s*[0-9]+\s*)*$
Получилось немного громоздко, но это терпимо. Как альтернатива, можно просто вырезать из выражения все пробелы и проверять его упрощенной регуляркой.
Попробуй так же записать свое выражение. Что в нем может встретиться и где.
Я вижу, анон запутался. Давайте ему поможем.
Итак. Дана другая задача: напишите регулярку, которая проверит математическое выражение на правильность. Математическое выражение может состоять из целых неотрицательных чисел, знаков + и -, и пробелов.
Примеры:
Правильные выражения:
123
1+2+3
1+3-2
Неправильные:
xyz (это не число)
-2 (у нас в задаче нет отриц. чисел)
1++2 (2 знака подряд)
1 2 (нет знака между числами)
Пишем регулярку. Структуру выражения можно записать как:
число знак число знак число ...
Как это выразить регуляркой? Здесь можно использовать звездочку, чтобы сказать, что за первым числом могут следовать еще произвольное количество чисел, отделенных знаками:
число (знак число)*
Продолжим. Как записать "число" в виде регулярки? Это просто 1 или более цифр:
число = [0-9]+
Знак это плюс или минус: [+\-]
Соберем это вместе:
^[0-9]+([+\-][0-9]+)*$
Наконец, надо учесть наличие необязательных пробелов между числами и знаками и мы получим итоговое выражение:
^\s*[0-9]+\s*([+\-]\s*[0-9]+\s*)*$
Получилось немного громоздко, но это терпимо. Как альтернатива, можно просто вырезать из выражения все пробелы и проверять его упрощенной регуляркой.
Попробуй так же записать свое выражение. Что в нем может встретиться и где.
Еще куки можно поставить c помощью мета тега:
echo "<meta http-equiv="Set-Cookie" content="NAME=value; EXPIRES=date; DOMAIN=domain_name; PATH=path; SECURE" />";
Но так делать, конечно, не стоит, если только нужно установить куку, а заголовки по какой-либо причине уже были отправлены клиенту и изменить это нельзя.
Ммм регулярка...
Работает со знаком вопроса, но наполовину. Больше одного знака не цифры чот не хочет, разве запись "{10}" не относится к символам, отличных от цифры?
Нет. У тебя откуда-то ошибочное мнение, что можно за полгода вайти-в-айти и начать зарабатывать. Минимум год, если ты умный (судя по вопросам - нет). максимум 2 года, на эту цифру и рассчитывай.
Ну тут смотря что указывается под "зарабатывать" и "полгода". Если он ежедневно будет задрачивать теорию/кодить часов +6 то на джуна может и вкотиться. Мне кажется на начальном этапе решают больше параметры типа гитхаб + общая адекватность + отсутствие вредных привычек + наличие семьи/ребенка. Будет ЗАРАБАТЫВАТЬ %копейки% и СОВЕРШЕНСТВОВАТЬСЯ %иначе выкинут%.
А потом как у всех.
Бляяяяяять, разметка! Я обосрался дважды -_- И тот анон тоже ошибся. Вот она, регулярочка:
>^\\s?(8|\\+\\s?7)([\\s\\(-]\\d[\\s\\)-]){10}$
Опушка, а когда задачки проверять будешь? Ты для многих из нас был главным источником мотивации.
Это не истинный оп.
Пруфы? Я лично много лет назад тестировал отдачу файла с именем с кириллицей в разных браузерах. ИЕ тогда интерпретировал содержимое заголовка как текст в Windows-1251, а другие браузеры как utf-8, если не путаю.
Если тебе интересно, например, как проблема решается в Симфони то можно глянуть код тут https://github.com/symfony/http-foundation/blob/master/BinaryFileResponse.php#L156
Пока 100% работающий метод это поместить имя файла в конец ссылки. Ну и для новых браузеров будет работать метод из Симфони.
(кстати там же можно увидеть код, поддерживающий отдачу через X-Accel-Redirect)
Хм, действительо. Проверил киррилицу в жопере, огнелисе и хроме - работает, а эксплорер хероту выдает.
header('Content-Disposition: attachment; filename="'.urlencode($data[0]['orig_name']).'"');
и теперь в эксплорере под нужным именем сохраняется. Иероглифы тоже проверил.
Я пытался самостоятельно закончить шифровальный мессенджер на JS фреймворке и с PHP на бэкенде, но оказалось, что Angular не способен в server-side rendering с другими языками.
Я даже сделал PR для одного из их инструментов для этого, чтобы починить ленивую подгрузку роутов
https://github.com/angular/universal/issues/1000
https://github.com/angular/universal/issues/1069
https://github.com/angular/universal/commit/c16860c06ed645a0f3a6937191d1f9b7a6e2dc48
Когда я сделал это, я тестировал подгрузку шаблона просто:
$connector->connect('...')->then(function ($connection) use ($loop) {
$options = [
'id' => 1,
'url' => '/',
'document' => '<app-root></app-root>'
];
$connection->write(json_encode($options));
$connection->on('data', function ($data) use ($connection) {
$template = json_decode($data, JSON_OBJECT_AS_ARRAY)['html'];
include __DIR__ . '/../templates/index.phtml';
$connection->close();
});
});
Мне удавалось просто заинклудить шаблон, но проблемы начались когда я начал писать реальный код и установил Symfony, где рендеринг шаблона выполняется через return, и, к тому же, я обнаружил что с Angular server-side rendering даже нет причины использовать PHP, потому что он уже и так всё делает.
Я хотел написать чтобы приложение способно было работать без JS, а JS лишь добавлял плавности для подгрузки и/или перехода между компонентами.
Мне нужно чтобы я мог выдать шаблон с помощью PHP, а JS просто повесился поверх него. Чтобы максимум что мне пришлось сделать для этого, это скомпилировать JS код через Webpack или через что ещё это делают?. Ни больше не меньше!
Такой фронтэнд фреймворк существует? Вы можете посоветовать?
Я готов написать такое приложение и на ES6 и транспилировать его через Babel, чтобы получить поддержку относительно старых браузеров, но, опять же, я не уверен какие библиотеки я должен использовать.
Мне ни один из предложенных гуглом шаблонизаторов не нравится, потому что в них нужно определять шаблон либо как строку, либо как скрипт с типом type="script/name of template engine".
Не совсем ясно какую библиотеку использовать для роутинга - в гугле только одна библиотека по первой ссылке и куча блогов о том как написать собственный, и, наконец, документация по роутингу для Vue.js и ReactJS.
Все это не понятно и нужно тестировать самому.
Может мне просто взять ReactJS? Он подойдет для такой задачи?
А я потратил всё лето на изучение Angular, как напрасно как жаль, эх...
Я пытался самостоятельно закончить шифровальный мессенджер на JS фреймворке и с PHP на бэкенде, но оказалось, что Angular не способен в server-side rendering с другими языками.
Я даже сделал PR для одного из их инструментов для этого, чтобы починить ленивую подгрузку роутов
https://github.com/angular/universal/issues/1000
https://github.com/angular/universal/issues/1069
https://github.com/angular/universal/commit/c16860c06ed645a0f3a6937191d1f9b7a6e2dc48
Когда я сделал это, я тестировал подгрузку шаблона просто:
$connector->connect('...')->then(function ($connection) use ($loop) {
$options = [
'id' => 1,
'url' => '/',
'document' => '<app-root></app-root>'
];
$connection->write(json_encode($options));
$connection->on('data', function ($data) use ($connection) {
$template = json_decode($data, JSON_OBJECT_AS_ARRAY)['html'];
include __DIR__ . '/../templates/index.phtml';
$connection->close();
});
});
Мне удавалось просто заинклудить шаблон, но проблемы начались когда я начал писать реальный код и установил Symfony, где рендеринг шаблона выполняется через return, и, к тому же, я обнаружил что с Angular server-side rendering даже нет причины использовать PHP, потому что он уже и так всё делает.
Я хотел написать чтобы приложение способно было работать без JS, а JS лишь добавлял плавности для подгрузки и/или перехода между компонентами.
Мне нужно чтобы я мог выдать шаблон с помощью PHP, а JS просто повесился поверх него. Чтобы максимум что мне пришлось сделать для этого, это скомпилировать JS код через Webpack или через что ещё это делают?. Ни больше не меньше!
Такой фронтэнд фреймворк существует? Вы можете посоветовать?
Я готов написать такое приложение и на ES6 и транспилировать его через Babel, чтобы получить поддержку относительно старых браузеров, но, опять же, я не уверен какие библиотеки я должен использовать.
Мне ни один из предложенных гуглом шаблонизаторов не нравится, потому что в них нужно определять шаблон либо как строку, либо как скрипт с типом type="script/name of template engine".
Не совсем ясно какую библиотеку использовать для роутинга - в гугле только одна библиотека по первой ссылке и куча блогов о том как написать собственный, и, наконец, документация по роутингу для Vue.js и ReactJS.
Все это не понятно и нужно тестировать самому.
Может мне просто взять ReactJS? Он подойдет для такой задачи?
А я потратил всё лето на изучение Angular, как напрасно как жаль, эх...
Ну, я думаю, что изучение Angular все же будет полезно. Хотя бы кругозор расширит.
> Я хотел написать чтобы приложение способно было работать без JS, а JS лишь добавлял плавности для подгрузки и/или перехода между компонентами.
Вообще, есть такая штука, как pjax - она перехватывает клики по ссылкам и вместо перехода загружает страницу аяксом и вставляет ее в DOM. Но это не для интеративных приложений - это для ускорения переходов на "классических" сайтах. Используется на гитхабе, например.
Есть подход, когда мы рендерим страницы на сервере и пишем JS код, который добавляет им интерактивности (progressive enhancement). Это не очень тебе подойдет, так как это подходит для "сайтов", а не "приложений". И придется дублировать шаблоны в PHP и JS коде.
Что касается, server side rendering - его первоочередная цель - это сделать сайты, построенные на SPA, индексируемыми (что, как мне кажется, проще решить отказом от SPA для таких сайтов).
Для интерактивных приложений (вроде мессенджера) лучше все же использовать именно SPA, иначе расходы трафика будут большие, и любые действия будут сопровождаться перезагрузкой страницы, что небыстро. Индексирование им не нужно. Это по сути не сайт, а приложение.
В твоем случае логичнее всего сделать основным режимом SPA, а если хочется поддержка браузеров без JS, то можно поддерживать ограниченный функционал (например, упрощенный просмотр сообщений и упрощенная отправка). Сделать полноценный аналог без JS будет сложно. По таким причинам:
1) любое действие требует перезагрузки страницы. Ну представь, например, фильтр по контактам, работающий по мере набора текста - это нельзя сделать без JS (только если превратить его в классическую форму с кнопкой). Или например открывающийся интерактивно попап для выбора смайликов.
2) нужно как-то сохранять состояние при перезагрузках страницы. Представь сценарий: пользователь вводит текст сообщения, затем жмет на кнопку добавления смайлика (которая открывает попап с ними). Нам надо перезагрузить страницу, но не потерять введенный текст. Это сама по себе сложная задача. Какой-то майкрософтовский фреймворк делал так: он в конце выполнения серверного скрипта сериализовал состояние (значения переменных) и вставлял в страницу в виде строки. При выполнении любого действия это состояние (с помощью простого JS) в запросе POST отправлялось на сервер, и значения переменных восстанавливались. Эта штука называлась viewState: https://msdn.microsoft.com/en-us/library/bb386448.aspx
Или представь такой сценарий: пользователь в оффлайне отправляет сообщение, оно сохраняется в localStorage, пользователь закрывает вкладку. Затем пользователь снова открывает вкладку - и в отрендеренной сервером странице этого сообщения нету.
Именно поэтому, мне кажется, есть смысл оставить только минимальный функционал в версии без JS.
Я вижу такие варианты:
- сделать отдельные страницы на отдельных роутах для упрощенной HTML-версии (как в Gmail). Они могут быть сделаны на PHP, или же на JS, но отдельным модулем, и не включены в браузерное приложение.
- вставить в существующие Angular шаблоны условия для отключения лишнего функционала при работе на сервере, скрыть часть элементов страницы (которые не работают без JS), убрать лишние роуты.
По твоему PHP коду: в нем ошибка. Событие data не говорит о том, что все данные приняты. Оно говорит о поступлении куска данных. Ты должен собирать приходящие данные в буфер до получения события end, которое говорит о том, что пир закончил передачу данных и закрыл TCP-соединение на передачу. В ответ на это ты делаешь close(). Также ты должен проверять событие error, которое говорит об ошибке в процессе работы соединения.
Не может быть проблемы из-за этого, что ты не получил все данные до конца?
Также, ты должен прокидывать в ангулар-приложение HTTP-заголовки. Например, авторизационные куки, если они проверяются в приложении.
> Мне удавалось просто заинклудить шаблон, но проблемы начались когда я начал писать реальный код и установил Symfony, где рендеринг шаблона выполняется через return
Напиши, в чем проблемы.
> я обнаружил что с Angular server-side rendering даже нет причины использовать PHP, потому что он уже и так всё делает.
Это тоже вариант - оставить в PHP только API (и, может быть, страницы авторизации/регистрации), а рендеринг страниц мессенджера отдать Node.JS приложению. Почему нет?
> Я хотел написать чтобы приложение способно было работать без JS, а JS лишь добавлял плавности для подгрузки и/или перехода между компонентами.
Это хороший подход при написании веб-приложений, которые больше похожи на сайты - где есть страницы, меню, а JS лишь добавляет интерактивности. Но мессенджер это приложение, а не сайт. И тут имеет смысл основной сделать именно SPA версию.
А так, это умеет делать реакт. Можно отрендерить страницу на сервере, и потом к ней подцепить скрипты, когда они загрузятся. Я видел, например, дата-атрибуты в HTML-коде медузы (https://meduza.io) - можешь поковырять, если интересно.
Судя по мануалу, Ангулар умеет что-то похожее: https://angular.io/guide/universal#the-root-appmodule
Это позволяет показать какие-то данные до загрузки кода, но страница будет неинтерактивной (разве что на ней будут работать ссылки и классические формы).
То есть ты можешь, например, отрендерить на сервере страницу со списком контактов и последними сообщениями, а потом подцепить к ней приложение. Причем отрендерить стоит упрощенную версию страницы, чтобы пользователь не тыкал зря на неработающие кнопки. Сделать контакты ссылками - это позволит переключаться между ними. Сделать форму отправки классической HTML формой.
А после подгрузки JS кода будут отрендерены дополнительные элементы, нажатия на контакты будут обрабатываться приложением, как и форма отправки сообщения.
Это, как мне кажется, умеет и Ангулар, и Реакт.
Если тебя беспокоит скорость загрузки JS кода и потребление трафика при загрузке (типичная проблема для SPA приложений), то я бы думал об его разделении на части и уменьшении. Ну, условно говоря, если у нас есть страница настроек, нам не надо подгружать контроллер и шаблон для нее сразу - можно это сделать, когда пользователь ее откроет. Вебпак позволяет разделять код на бандлы.
Также, для ускорения загрузки стоит "впекать" часть данных при генерации страницы на сервере. Если приложению после загрузки надо, например, загрузить список контактов, то можно его весь или часть вставить в тело страницы, например в теге script type="application/json" data-url="/api/contacts". Наверно, это как-то можно автоматизировать.
> Я готов написать такое приложение и на ES6 и транспилировать его через Babel, чтобы получить поддержку относительно старых браузеров, но, опять же, я не уверен какие библиотеки я должен использовать.
Babel транспилирует в ES5, для поддержки совсем старых браузеров добавляется ES5 shim, который при удачном стечении обстоятельств позволяет работать коду в ES3 браузерах (стоит только помнить, что совсем старые браузеры могут не поддерживать часть HTML5 тегов и новые CSS правила. Тут нужно тестирование). При этом современным браузерам в идеале хорошо бы отдавать ES6. Ну и при разработке желательно избежать запуска Babel, который не очень быстро работает, а грузить ES6 код напрямую.
Ну, я думаю, что изучение Angular все же будет полезно. Хотя бы кругозор расширит.
> Я хотел написать чтобы приложение способно было работать без JS, а JS лишь добавлял плавности для подгрузки и/или перехода между компонентами.
Вообще, есть такая штука, как pjax - она перехватывает клики по ссылкам и вместо перехода загружает страницу аяксом и вставляет ее в DOM. Но это не для интеративных приложений - это для ускорения переходов на "классических" сайтах. Используется на гитхабе, например.
Есть подход, когда мы рендерим страницы на сервере и пишем JS код, который добавляет им интерактивности (progressive enhancement). Это не очень тебе подойдет, так как это подходит для "сайтов", а не "приложений". И придется дублировать шаблоны в PHP и JS коде.
Что касается, server side rendering - его первоочередная цель - это сделать сайты, построенные на SPA, индексируемыми (что, как мне кажется, проще решить отказом от SPA для таких сайтов).
Для интерактивных приложений (вроде мессенджера) лучше все же использовать именно SPA, иначе расходы трафика будут большие, и любые действия будут сопровождаться перезагрузкой страницы, что небыстро. Индексирование им не нужно. Это по сути не сайт, а приложение.
В твоем случае логичнее всего сделать основным режимом SPA, а если хочется поддержка браузеров без JS, то можно поддерживать ограниченный функционал (например, упрощенный просмотр сообщений и упрощенная отправка). Сделать полноценный аналог без JS будет сложно. По таким причинам:
1) любое действие требует перезагрузки страницы. Ну представь, например, фильтр по контактам, работающий по мере набора текста - это нельзя сделать без JS (только если превратить его в классическую форму с кнопкой). Или например открывающийся интерактивно попап для выбора смайликов.
2) нужно как-то сохранять состояние при перезагрузках страницы. Представь сценарий: пользователь вводит текст сообщения, затем жмет на кнопку добавления смайлика (которая открывает попап с ними). Нам надо перезагрузить страницу, но не потерять введенный текст. Это сама по себе сложная задача. Какой-то майкрософтовский фреймворк делал так: он в конце выполнения серверного скрипта сериализовал состояние (значения переменных) и вставлял в страницу в виде строки. При выполнении любого действия это состояние (с помощью простого JS) в запросе POST отправлялось на сервер, и значения переменных восстанавливались. Эта штука называлась viewState: https://msdn.microsoft.com/en-us/library/bb386448.aspx
Или представь такой сценарий: пользователь в оффлайне отправляет сообщение, оно сохраняется в localStorage, пользователь закрывает вкладку. Затем пользователь снова открывает вкладку - и в отрендеренной сервером странице этого сообщения нету.
Именно поэтому, мне кажется, есть смысл оставить только минимальный функционал в версии без JS.
Я вижу такие варианты:
- сделать отдельные страницы на отдельных роутах для упрощенной HTML-версии (как в Gmail). Они могут быть сделаны на PHP, или же на JS, но отдельным модулем, и не включены в браузерное приложение.
- вставить в существующие Angular шаблоны условия для отключения лишнего функционала при работе на сервере, скрыть часть элементов страницы (которые не работают без JS), убрать лишние роуты.
По твоему PHP коду: в нем ошибка. Событие data не говорит о том, что все данные приняты. Оно говорит о поступлении куска данных. Ты должен собирать приходящие данные в буфер до получения события end, которое говорит о том, что пир закончил передачу данных и закрыл TCP-соединение на передачу. В ответ на это ты делаешь close(). Также ты должен проверять событие error, которое говорит об ошибке в процессе работы соединения.
Не может быть проблемы из-за этого, что ты не получил все данные до конца?
Также, ты должен прокидывать в ангулар-приложение HTTP-заголовки. Например, авторизационные куки, если они проверяются в приложении.
> Мне удавалось просто заинклудить шаблон, но проблемы начались когда я начал писать реальный код и установил Symfony, где рендеринг шаблона выполняется через return
Напиши, в чем проблемы.
> я обнаружил что с Angular server-side rendering даже нет причины использовать PHP, потому что он уже и так всё делает.
Это тоже вариант - оставить в PHP только API (и, может быть, страницы авторизации/регистрации), а рендеринг страниц мессенджера отдать Node.JS приложению. Почему нет?
> Я хотел написать чтобы приложение способно было работать без JS, а JS лишь добавлял плавности для подгрузки и/или перехода между компонентами.
Это хороший подход при написании веб-приложений, которые больше похожи на сайты - где есть страницы, меню, а JS лишь добавляет интерактивности. Но мессенджер это приложение, а не сайт. И тут имеет смысл основной сделать именно SPA версию.
А так, это умеет делать реакт. Можно отрендерить страницу на сервере, и потом к ней подцепить скрипты, когда они загрузятся. Я видел, например, дата-атрибуты в HTML-коде медузы (https://meduza.io) - можешь поковырять, если интересно.
Судя по мануалу, Ангулар умеет что-то похожее: https://angular.io/guide/universal#the-root-appmodule
Это позволяет показать какие-то данные до загрузки кода, но страница будет неинтерактивной (разве что на ней будут работать ссылки и классические формы).
То есть ты можешь, например, отрендерить на сервере страницу со списком контактов и последними сообщениями, а потом подцепить к ней приложение. Причем отрендерить стоит упрощенную версию страницы, чтобы пользователь не тыкал зря на неработающие кнопки. Сделать контакты ссылками - это позволит переключаться между ними. Сделать форму отправки классической HTML формой.
А после подгрузки JS кода будут отрендерены дополнительные элементы, нажатия на контакты будут обрабатываться приложением, как и форма отправки сообщения.
Это, как мне кажется, умеет и Ангулар, и Реакт.
Если тебя беспокоит скорость загрузки JS кода и потребление трафика при загрузке (типичная проблема для SPA приложений), то я бы думал об его разделении на части и уменьшении. Ну, условно говоря, если у нас есть страница настроек, нам не надо подгружать контроллер и шаблон для нее сразу - можно это сделать, когда пользователь ее откроет. Вебпак позволяет разделять код на бандлы.
Также, для ускорения загрузки стоит "впекать" часть данных при генерации страницы на сервере. Если приложению после загрузки надо, например, загрузить список контактов, то можно его весь или часть вставить в тело страницы, например в теге script type="application/json" data-url="/api/contacts". Наверно, это как-то можно автоматизировать.
> Я готов написать такое приложение и на ES6 и транспилировать его через Babel, чтобы получить поддержку относительно старых браузеров, но, опять же, я не уверен какие библиотеки я должен использовать.
Babel транспилирует в ES5, для поддержки совсем старых браузеров добавляется ES5 shim, который при удачном стечении обстоятельств позволяет работать коду в ES3 браузерах (стоит только помнить, что совсем старые браузеры могут не поддерживать часть HTML5 тегов и новые CSS правила. Тут нужно тестирование). При этом современным браузерам в идеале хорошо бы отдавать ES6. Ну и при разработке желательно избежать запуска Babel, который не очень быстро работает, а грузить ES6 код напрямую.
Есть вывод шаблона через слим :
$response = $this -> view -> render($response,'home.phtml', $data_success);
Есть шаблон home.phtml с кодом:
<? if(isset($data_success)): ?>
Код №1
<? else: ?>
Код №2
<? endif; ?>
Вопрос: почему всегда отображается код номер два?
Сам разобрался. Анальный фреймворк все переданные значения переименовывает автоматически.
>То есть ты можешь, например, отрендерить на сервере страницу со списком контактов и последними сообщениями, а потом подцепить к ней приложение. Причем отрендерить стоит упрощенную версию страницы, чтобы пользователь не тыкал зря на неработающие кнопки. Сделать контакты ссылками - это позволит переключаться между ними. Сделать форму отправки классической HTML формой.
>
>А после подгрузки JS кода будут отрендерены дополнительные элементы, нажатия на контакты будут обрабатываться приложением, как и форма отправки сообщения.
А вот моё "черновое" приложение чата на чистом JS, как раз так и работало: - сначала отдавалась отрендеренная страница на PHP, а потом инициализировался JS, и все переходы по контактам, подгрузка новых или старых сообщений, и поиск контактов происходили "плавно" (если не считать времени на получение сообщений через http и дешифровку). Кстати, и если отключить JS в браузере, то можно так же было отправлять сообщения из той же формы, искать контакты, и подгружать старые сообщения, переходя по ссылке которая при включенном JS скрывалась при скролле вверх. Только это было моей первой работой и код получался запутанным. Хотелось бы, с моими новыми знаниями о JS, написать что-то погибче, используя современные инструменты и протоколы.
>В твоем случае логичнее всего сделать основным режимом SPA, а если хочется поддержка браузеров без JS, то можно поддерживать ограниченный функционал (например, упрощенный просмотр сообщений и упрощенная отправка). Сделать полноценный аналог без JS будет сложно. По таким причинам:
>
>1) любое действие требует перезагрузки страницы. Ну представь, например, фильтр по контактам, работающий по мере набора текста - это нельзя сделать без JS (только если превратить его в классическую форму с кнопкой). Или например открывающийся интерактивно попап для выбора смайликов.
>2) нужно как-то сохранять состояние при перезагрузках страницы. Представь сценарий: пользователь вводит текст сообщения, затем жмет на кнопку добавления смайлика (которая открывает попап с ними). Нам надо перезагрузить страницу, но не потерять введенный текст. Это сама по себе сложная задача. Какой-то майкрософтовский фреймворк делал так: он в конце выполнения серверного скрипта сериализовал состояние (значения переменных) и вставлял в страницу в виде строки. При выполнении любого действия это состояние (с помощью простого JS) в запросе POST отправлялось на сервер, и значения переменных восстанавливались. Эта штука называлась viewState: https://msdn.microsoft.com/en-us/library/bb386448.aspx
Ну вот, как у меня и было, в случае с поиском контактов, можно сделать классическую форму с кнопкой, затем, при инициализации JS, отменить интерфейс её отправки и обрабатывать эту форму уже с помощью самого JS.
В случае со смайлами, можно с сервера отрендерить форму без кнопки смайлов, а после загрузки JS, плавно вывести её (а при JS роутенге можно выводить её сразу).
>Или представь такой сценарий: пользователь в оффлайне отправляет сообщение, оно сохраняется в localStorage, пользователь закрывает вкладку. Затем пользователь снова открывает вкладку - и в отрендеренной сервером странице этого сообщения нету.
Тут нужно сначала определить, где именно будут хранится сообщения... Или, если это не имеет значения, то всегда отправлять сообщения из localStorage на сервер при восстановлении соединения и обновлять вкладку.
В общем, везде можно придумать что-то.
>Именно поэтому, мне кажется, есть смысл оставить только минимальный функционал в версии без JS.
Да, на это и расчет. Чтобы без JS, по крайней мере, и работало.
>> я обнаружил что с Angular server-side rendering даже нет причины использовать PHP, потому что он уже и так всё делает.
>Это тоже вариант - оставить в PHP только API (и, может быть, страницы авторизации/регистрации), а рендеринг страниц мессенджера отдать Node.JS приложению. Почему нет?
А можно и API написать на Node.js. Только я не умею писать сервера, а в мануале по Angular'у написано что их пример сервера не безопасен https://angular.io/guide/universal#universal-web-server
>This sample server is not secure! Be sure to add middleware to authenticate and authorize users just as you would for a normal Angular application server.
Или я что-то путаю?
Так как мне следует поступить? Я склоняюсь к тому чтобы попробовать React, и если с ним не получится, то написать на ES6, и если и на нём не получится, то на Node.js уж железно получится написать приложение на Angular'е!
>То есть ты можешь, например, отрендерить на сервере страницу со списком контактов и последними сообщениями, а потом подцепить к ней приложение. Причем отрендерить стоит упрощенную версию страницы, чтобы пользователь не тыкал зря на неработающие кнопки. Сделать контакты ссылками - это позволит переключаться между ними. Сделать форму отправки классической HTML формой.
>
>А после подгрузки JS кода будут отрендерены дополнительные элементы, нажатия на контакты будут обрабатываться приложением, как и форма отправки сообщения.
А вот моё "черновое" приложение чата на чистом JS, как раз так и работало: - сначала отдавалась отрендеренная страница на PHP, а потом инициализировался JS, и все переходы по контактам, подгрузка новых или старых сообщений, и поиск контактов происходили "плавно" (если не считать времени на получение сообщений через http и дешифровку). Кстати, и если отключить JS в браузере, то можно так же было отправлять сообщения из той же формы, искать контакты, и подгружать старые сообщения, переходя по ссылке которая при включенном JS скрывалась при скролле вверх. Только это было моей первой работой и код получался запутанным. Хотелось бы, с моими новыми знаниями о JS, написать что-то погибче, используя современные инструменты и протоколы.
>В твоем случае логичнее всего сделать основным режимом SPA, а если хочется поддержка браузеров без JS, то можно поддерживать ограниченный функционал (например, упрощенный просмотр сообщений и упрощенная отправка). Сделать полноценный аналог без JS будет сложно. По таким причинам:
>
>1) любое действие требует перезагрузки страницы. Ну представь, например, фильтр по контактам, работающий по мере набора текста - это нельзя сделать без JS (только если превратить его в классическую форму с кнопкой). Или например открывающийся интерактивно попап для выбора смайликов.
>2) нужно как-то сохранять состояние при перезагрузках страницы. Представь сценарий: пользователь вводит текст сообщения, затем жмет на кнопку добавления смайлика (которая открывает попап с ними). Нам надо перезагрузить страницу, но не потерять введенный текст. Это сама по себе сложная задача. Какой-то майкрософтовский фреймворк делал так: он в конце выполнения серверного скрипта сериализовал состояние (значения переменных) и вставлял в страницу в виде строки. При выполнении любого действия это состояние (с помощью простого JS) в запросе POST отправлялось на сервер, и значения переменных восстанавливались. Эта штука называлась viewState: https://msdn.microsoft.com/en-us/library/bb386448.aspx
Ну вот, как у меня и было, в случае с поиском контактов, можно сделать классическую форму с кнопкой, затем, при инициализации JS, отменить интерфейс её отправки и обрабатывать эту форму уже с помощью самого JS.
В случае со смайлами, можно с сервера отрендерить форму без кнопки смайлов, а после загрузки JS, плавно вывести её (а при JS роутенге можно выводить её сразу).
>Или представь такой сценарий: пользователь в оффлайне отправляет сообщение, оно сохраняется в localStorage, пользователь закрывает вкладку. Затем пользователь снова открывает вкладку - и в отрендеренной сервером странице этого сообщения нету.
Тут нужно сначала определить, где именно будут хранится сообщения... Или, если это не имеет значения, то всегда отправлять сообщения из localStorage на сервер при восстановлении соединения и обновлять вкладку.
В общем, везде можно придумать что-то.
>Именно поэтому, мне кажется, есть смысл оставить только минимальный функционал в версии без JS.
Да, на это и расчет. Чтобы без JS, по крайней мере, и работало.
>> я обнаружил что с Angular server-side rendering даже нет причины использовать PHP, потому что он уже и так всё делает.
>Это тоже вариант - оставить в PHP только API (и, может быть, страницы авторизации/регистрации), а рендеринг страниц мессенджера отдать Node.JS приложению. Почему нет?
А можно и API написать на Node.js. Только я не умею писать сервера, а в мануале по Angular'у написано что их пример сервера не безопасен https://angular.io/guide/universal#universal-web-server
>This sample server is not secure! Be sure to add middleware to authenticate and authorize users just as you would for a normal Angular application server.
Или я что-то путаю?
Так как мне следует поступить? Я склоняюсь к тому чтобы попробовать React, и если с ним не получится, то написать на ES6, и если и на нём не получится, то на Node.js уж железно получится написать приложение на Angular'е!
>Я вижу такие варианты:
>
>- сделать отдельные страницы на отдельных роутах для упрощенной HTML-версии (как в Gmail). Они могут быть сделаны на PHP, или же на JS, но отдельным модулем, и не включены в браузерное приложение.
То есть сделать, например роут '/conversation/:id/' отдельно на PHP и отдельно на JS? Как понять отдельным модулем? Отдельным от чего? Как модули JS могут быть не включены в браузерное приложение? То есть, имеется ввиду, пререндерить сначала модуль, например, на Node.js?
>По твоему PHP коду: в нем ошибка. Событие data не говорит о том, что все данные приняты. Оно говорит о поступлении куска данных. Ты должен собирать приходящие данные в буфер до получения события end, которое говорит о том, что пир закончил передачу данных и закрыл TCP-соединение на передачу. В ответ на это ты делаешь close(). Также ты должен проверять событие error, которое говорит об ошибке в процессе работы соединения.
>
>Не может быть проблемы из-за этого, что ты не получил все данные до конца?
Я конечно же об это знал, что сокеты могут отправить сигнал о завершении трансляции, но в этом случае не подумал об этом, потому что так было в примере предложенным самими разработчиками этого инструмента, и мне самому очень не понятно как устроен серверный код Angular'а и JS.
https://github.com/angular/universal/issues/1000
>import * as net from 'net';
>
>const client = net.createConnection(9090, 'localhost', () => {
> const renderOptions = {id: 1, url: '/path',
> document: '<app-root></app-root>'} as SocketEngineRenderOptions;
> client.write(JSON.stringify(renderOptions));
>});
>
>client.on('data', data => {
> const res = JSON.parse(data.toString()) as SocketEngineResponse;
> server.close();
> done();
>});
Здесь нет проблемы с получением данных, потому что я проверял вывод шаблонов без Symfony и всё было в порядке.1-pic
>Также, ты должен прокидывать в ангулар-приложение HTTP-заголовки. Например, авторизационные куки, если они проверяются в приложении.
Я не знаю как это сделать и думаю что информации об этом не существует. Я вспоминаю вот это обсуждение по этому поводу https://github.com/angular/universal/issues/1000#issuecomment-391463462
>>What are your thoughts about cookies?
>I havn't put any effort into cookies just yet, but that's definitely something we can add onto these new additions. Right now i'd just like to keep it simple and make sure it solves the problems that people have with Universal on other platforms.
Кстати, полноценная возможность коммуникации Angular Universal с другими языками ещё только в разработке https://github.com/angular/universal#in-progress
>Node.js bridge protocol to communicate with different language backends - Django, Go, PHP etc.
Интересно как это будет и избавит ли это меня от текущих проблем.
>> Мне удавалось просто заинклудить шаблон, но проблемы начались когда я начал писать реальный код и установил Symfony, где рендеринг шаблона выполняется через return
>Напиши, в чем проблемы.
В том что шаблон я получаю в асинхронной функции, а в Symfony я могу отрендерить его только в синхроном коде контроллера, вызвав return.
>Если тебя беспокоит скорость загрузки JS кода и потребление трафика при загрузке (типичная проблема для SPA приложений), то я бы думал об его разделении на части и уменьшении. Ну, условно говоря, если у нас есть страница настроек, нам не надо подгружать контроллер и шаблон для нее сразу - можно это сделать, когда пользователь ее откроет. Вебпак позволяет разделять код на бандлы.
В Ангуляре есть ленивая подгрузка роутов когда модули загружаются только когда они нужны. Не уверен только как именно это работает - лениво загружается код по сети или лениво загружается инициализация модулей. Мне ещё предстоит узнать, какую конкретно играет роль Webpack по отношению к Ангуляру.
https://angular.io/guide/router#milestone-6-asynchronous-routing
>> Я готов написать такое приложение и на ES6 и транспилировать его через Babel, чтобы получить поддержку относительно старых браузеров, но, опять же, я не уверен какие библиотеки я должен использовать.
>Babel транспилирует в ES5, для поддержки совсем старых браузеров добавляется ES5 shim, который при удачном стечении обстоятельств позволяет работать коду в ES3 браузерах (стоит только помнить, что совсем старые браузеры могут не поддерживать часть HTML5 тегов и новые CSS правила. Тут нужно тестирование). При этом современным браузерам в идеале хорошо бы отдавать ES6. Ну и при разработке желательно избежать запуска Babel, который не очень быстро работает, а грузить ES6 код напрямую.
Разве Babel не транспилирует ES6 ещё? Почему-то его оффициальный сайт не открывается.
>Я вижу такие варианты:
>
>- сделать отдельные страницы на отдельных роутах для упрощенной HTML-версии (как в Gmail). Они могут быть сделаны на PHP, или же на JS, но отдельным модулем, и не включены в браузерное приложение.
То есть сделать, например роут '/conversation/:id/' отдельно на PHP и отдельно на JS? Как понять отдельным модулем? Отдельным от чего? Как модули JS могут быть не включены в браузерное приложение? То есть, имеется ввиду, пререндерить сначала модуль, например, на Node.js?
>По твоему PHP коду: в нем ошибка. Событие data не говорит о том, что все данные приняты. Оно говорит о поступлении куска данных. Ты должен собирать приходящие данные в буфер до получения события end, которое говорит о том, что пир закончил передачу данных и закрыл TCP-соединение на передачу. В ответ на это ты делаешь close(). Также ты должен проверять событие error, которое говорит об ошибке в процессе работы соединения.
>
>Не может быть проблемы из-за этого, что ты не получил все данные до конца?
Я конечно же об это знал, что сокеты могут отправить сигнал о завершении трансляции, но в этом случае не подумал об этом, потому что так было в примере предложенным самими разработчиками этого инструмента, и мне самому очень не понятно как устроен серверный код Angular'а и JS.
https://github.com/angular/universal/issues/1000
>import * as net from 'net';
>
>const client = net.createConnection(9090, 'localhost', () => {
> const renderOptions = {id: 1, url: '/path',
> document: '<app-root></app-root>'} as SocketEngineRenderOptions;
> client.write(JSON.stringify(renderOptions));
>});
>
>client.on('data', data => {
> const res = JSON.parse(data.toString()) as SocketEngineResponse;
> server.close();
> done();
>});
Здесь нет проблемы с получением данных, потому что я проверял вывод шаблонов без Symfony и всё было в порядке.1-pic
>Также, ты должен прокидывать в ангулар-приложение HTTP-заголовки. Например, авторизационные куки, если они проверяются в приложении.
Я не знаю как это сделать и думаю что информации об этом не существует. Я вспоминаю вот это обсуждение по этому поводу https://github.com/angular/universal/issues/1000#issuecomment-391463462
>>What are your thoughts about cookies?
>I havn't put any effort into cookies just yet, but that's definitely something we can add onto these new additions. Right now i'd just like to keep it simple and make sure it solves the problems that people have with Universal on other platforms.
Кстати, полноценная возможность коммуникации Angular Universal с другими языками ещё только в разработке https://github.com/angular/universal#in-progress
>Node.js bridge protocol to communicate with different language backends - Django, Go, PHP etc.
Интересно как это будет и избавит ли это меня от текущих проблем.
>> Мне удавалось просто заинклудить шаблон, но проблемы начались когда я начал писать реальный код и установил Symfony, где рендеринг шаблона выполняется через return
>Напиши, в чем проблемы.
В том что шаблон я получаю в асинхронной функции, а в Symfony я могу отрендерить его только в синхроном коде контроллера, вызвав return.
>Если тебя беспокоит скорость загрузки JS кода и потребление трафика при загрузке (типичная проблема для SPA приложений), то я бы думал об его разделении на части и уменьшении. Ну, условно говоря, если у нас есть страница настроек, нам не надо подгружать контроллер и шаблон для нее сразу - можно это сделать, когда пользователь ее откроет. Вебпак позволяет разделять код на бандлы.
В Ангуляре есть ленивая подгрузка роутов когда модули загружаются только когда они нужны. Не уверен только как именно это работает - лениво загружается код по сети или лениво загружается инициализация модулей. Мне ещё предстоит узнать, какую конкретно играет роль Webpack по отношению к Ангуляру.
https://angular.io/guide/router#milestone-6-asynchronous-routing
>> Я готов написать такое приложение и на ES6 и транспилировать его через Babel, чтобы получить поддержку относительно старых браузеров, но, опять же, я не уверен какие библиотеки я должен использовать.
>Babel транспилирует в ES5, для поддержки совсем старых браузеров добавляется ES5 shim, который при удачном стечении обстоятельств позволяет работать коду в ES3 браузерах (стоит только помнить, что совсем старые браузеры могут не поддерживать часть HTML5 тегов и новые CSS правила. Тут нужно тестирование). При этом современным браузерам в идеале хорошо бы отдавать ES6. Ну и при разработке желательно избежать запуска Babel, который не очень быстро работает, а грузить ES6 код напрямую.
Разве Babel не транспилирует ES6 ещё? Почему-то его оффициальный сайт не открывается.
* на изображении 2-pic нужно обратить внимание на переменные заголовка (title) - в PHP шаблоне выведется 'Symfony', а в Angular выведется 'ng'.
Ребят, у меня вопрос по организации процесса разработки - деплоя. Хотелось бы узнать как вы это автоматизируете и увидеть на реальных примерах весь процесс.
Как я делаю это сейчас: есть у меня несколько сайтов. Поменял я, допустим, какой-то код, сохранил файл, закоммитил и залил через ide на рабочий сервер.
Может кто-нибудь подробно расписать как это всё автоматизируется, чтобы сам процесс загрузки изменённых файлов на рабочий сервер происходил автономно, а от разработчика требовался только коммит в мастер ветку, например.
Сам ты аниме.
Вопрос: Может кто нибудь подсказать как открыть сайт для любого пользователя?
Надо что бы можно было прописать ip , порт и подключится с любого компьютера
>Сиськи! Внимание! Молния! Внимание привлек)
Укатывайся обратно к себе на пикабу, сын собаки сутулой.
Как вариант, можно сделать авторизацию на уровне apache-сервера с помощью .htaccess
Решил задачку https://ideone.com/e.js/o57cn0
Все хорошо, но не выполняется условие в 13 строке, не могу понять чому. Уже поздно и мб я в глаза ебусь, но сколько не разбираю непонятно. Хэлп.
Норм синтаксис, вот $a жуть.
Я так понимаю нетбинс более менее норм?
посмотрел в вики, оказалось что это не тривиальная операция, остаток - это типа частичка которая дополняет неполное частное, при этом поведение при отрицательных числах тоже не тривиально, тут надо смотреть формулу, а не интуитивно понимать.
9/90 = 90 * 0 + 9
сьеби, токсичный даун
Заменил ссылки в html, чтобы обращения шли не к localhost, а к сайту. Всякие css и js файлы подключил, в общем:
$content = str_replace('href="/', 'href="https://site.com/', $content);
$content = str_replace('src="/', 'src="https://site.com/', $content);
Но оказалось, что остались еще post- и get-запросы с относительными ссылками, которые в итоге тоже обращаются к локалхосту. Как перенаправлять их на site.com?
Ты хентай 90-х
Всё перегуглил. Нужно что-то отправлять в http-заголовках, как я понял, но что конкретно уже не понимаю.
Как заменить Request URL: http://localhost/al_im.php
На Request URL: https://site.com/al_im.php ?
Поменять отправляемый заголовок Host: localhost? Я пробовал:
curl_setopt($ch, CURLOPT_HTTPHEADER, "Host: site.com");
Но ничего не поменялось. Кажется, оно даже не отправилось.
Есть тег base, но с ним аякс-запросы получатся кроссдоменными и работать, конечно же не будут. Ты что-то делаешь не то. Я вообще не понимаю, зачем ты заменяешь ссылки в тексте страницы, да и еще и таким кривым, корявым методом.
Вот тег твой очень помог, а я вообще даже не думал смотреть в сторону html. А метод был корявым, потому что этого для начала хватало и альтернатив я не знал.
Буду теперь искать, как Access-Control-Allow-Origin обойти. Это же возможно?
Я тут читал архивач в глубь, там был разговор на эту тему. К тому времени как упорные аноны берутся за эту задачу, они уже начинают ходить по собеседованиям и как правило находят работу.
Я тоже читал часть старых тредов (на phpclub.tech), никто даже на процентов 30 не реализовывал того, что описано в задаче, только самые базовые вещи, которые средний разраб накидает за вечер.
>>78585
Так и есть, если реализовать полностью ту задачу с полным покрытием тестами и деплоем, то можно апплаиться на junior+/middle-
Задачу очень долго делать и не очень понятно зачем, если с такими навыками уже можно получать деньги.
Вылетает вот такая ошибка:
In Db.php line 506:
Db: SQLSTATE[08006] [7] could not connect to server: Connection refused
Is the server running on host "postgres" (172.18.0.4) and accepting
TCP/IP connections on port 5432? while creating PDO connection
https://travis-ci.com/Qevg/filehosting/builds/87855623
На локалке все работает, а в travis нет
postgres из official image конфиги там правильные
думал может проблема в том, что postgresql(сервис) не успевает запуститься сделал https://github.com/Qevg/filehosting/blob/master/.docker/postgres/wait-for-postgres.sh как в доке написано https://docs.docker.com/compose/startup-order/
Но это не помогло или я неправильно его сделал (https://travis-ci.com/Qevg/filehosting/builds/87855849) filehosting.site | Postgres is up - executing command показывает уже после того как codeception запустился. Есть у кого идеи что не так?
https://github.com/Qevg/filehosting
https://travis-ci.com/Qevg/filehosting/builds
Если кому не лень попробуйте у себя запустить. Нужен git, docker, docker-compose, composer
git clone https://github.com/Qevg/filehosting.git
cd filehosting
composer install
make configure-docker-testing
docker-compose -f docker-compose.testing.yml build
docker-compose -f docker-compose.testing.yml run --rm codecept run
и в /etc/hosts 127.0.0.1 filehosting.site
Вылетает вот такая ошибка:
In Db.php line 506:
Db: SQLSTATE[08006] [7] could not connect to server: Connection refused
Is the server running on host "postgres" (172.18.0.4) and accepting
TCP/IP connections on port 5432? while creating PDO connection
https://travis-ci.com/Qevg/filehosting/builds/87855623
На локалке все работает, а в travis нет
postgres из official image конфиги там правильные
думал может проблема в том, что postgresql(сервис) не успевает запуститься сделал https://github.com/Qevg/filehosting/blob/master/.docker/postgres/wait-for-postgres.sh как в доке написано https://docs.docker.com/compose/startup-order/
Но это не помогло или я неправильно его сделал (https://travis-ci.com/Qevg/filehosting/builds/87855849) filehosting.site | Postgres is up - executing command показывает уже после того как codeception запустился. Есть у кого идеи что не так?
https://github.com/Qevg/filehosting
https://travis-ci.com/Qevg/filehosting/builds
Если кому не лень попробуйте у себя запустить. Нужен git, docker, docker-compose, composer
git clone https://github.com/Qevg/filehosting.git
cd filehosting
composer install
make configure-docker-testing
docker-compose -f docker-compose.testing.yml build
docker-compose -f docker-compose.testing.yml run --rm codecept run
и в /etc/hosts 127.0.0.1 filehosting.site
Вообще в докеркомпостер конфиге можно определить ГЛАВНЫЙ сервис, например, в котором поднимается php-fpm делается копосер инсталл и вообще хранится код, когда этот сервис соберется то остальные уже должны будут собранными быть
UPD:
app:
build:
context: docker/php7-fpm
volumes:
- ./:/var/www/site:cached
depends_on:
- mysql
- mongodb
- beanstalkd
В итоге с перерывами уже 3 года кожу по сути. Дальше вектора в итоге не дошел в силу лени и неусидчивости.
Прочел ли ты примечания к пункту depends_on?
https://docs.docker.com/compose/compose-file/#depends_on
И от это: https://docs.docker.com/compose/startup-order/
Я не вижу у тебя в логе сообщений от Постгрес о том, что он запускается. Значит, он не успевает запуститься. Если вдруг он их не пишет по дефолту, то поставь опцию, чтобы он подробно все писал в консоль.
Читаем мануал:
> To handle this, design your application to attempt to re-establish a connection to the database after a failure.
Это так разработчики Докера вежливо написали, что проблему решать не собираются.
То бишь они советуют сделать в приложении реконнект (я думаю, нет: этот совет рассчитан на приложение, которое работает как сервер и в фоне поддерживает пул соединений). Но в твоем случае лучше перед запуском codecept влепить баш скрипт, который тестирует (через клиент ком. строки или php скрипт) наличие соединения.
Получается, ты wait-for-postgres не туда влепил. Нгиксу-то что, ему постгрес даром не нужен.
Заодно придется влепить еще ожидание всех остальных сервисов. Это можно объединить в один скрипт. То есть у тебя все сервисы не спеша поднимаются, и кодесепшен не запускается, пока ко всем не удастся приконнектиться. Не забудь сделать таймаут и разумное ограничение числа попыток, чтобы он там месяц не висел в ожидании коннекта.
Зависимости будут такие:
- codecept зависит от nginx, postgres, redis, sphinx, chrome
- nginx зависит от php
Кстати, я не очень понял, а то, что написано в command - оно внутри докер-контейнера запускается или на хосте? Если внутри, то откуда в контейнере нгинкса есть psql? (вопрос от человека, никогда не пользовавшегося докером)
И еще. Я вижу, у тебя там php компилируется. Это каждый раз будет происходить? Я хотел было дать совет кешировать папку с образами докер, но в мануале тревиса написано противоположное: https://docs.travis-ci.com/user/caching/#things-not-to-cache
Прочел ли ты примечания к пункту depends_on?
https://docs.docker.com/compose/compose-file/#depends_on
И от это: https://docs.docker.com/compose/startup-order/
Я не вижу у тебя в логе сообщений от Постгрес о том, что он запускается. Значит, он не успевает запуститься. Если вдруг он их не пишет по дефолту, то поставь опцию, чтобы он подробно все писал в консоль.
Читаем мануал:
> To handle this, design your application to attempt to re-establish a connection to the database after a failure.
Это так разработчики Докера вежливо написали, что проблему решать не собираются.
То бишь они советуют сделать в приложении реконнект (я думаю, нет: этот совет рассчитан на приложение, которое работает как сервер и в фоне поддерживает пул соединений). Но в твоем случае лучше перед запуском codecept влепить баш скрипт, который тестирует (через клиент ком. строки или php скрипт) наличие соединения.
Получается, ты wait-for-postgres не туда влепил. Нгиксу-то что, ему постгрес даром не нужен.
Заодно придется влепить еще ожидание всех остальных сервисов. Это можно объединить в один скрипт. То есть у тебя все сервисы не спеша поднимаются, и кодесепшен не запускается, пока ко всем не удастся приконнектиться. Не забудь сделать таймаут и разумное ограничение числа попыток, чтобы он там месяц не висел в ожидании коннекта.
Зависимости будут такие:
- codecept зависит от nginx, postgres, redis, sphinx, chrome
- nginx зависит от php
Кстати, я не очень понял, а то, что написано в command - оно внутри докер-контейнера запускается или на хосте? Если внутри, то откуда в контейнере нгинкса есть psql? (вопрос от человека, никогда не пользовавшегося докером)
И еще. Я вижу, у тебя там php компилируется. Это каждый раз будет происходить? Я хотел было дать совет кешировать папку с образами докер, но в мануале тревиса написано противоположное: https://docs.travis-ci.com/user/caching/#things-not-to-cache
Middle во многих компаниях это года 3 опыта, желательно на фреймворках. Задачу делать, конечно же, имеет смысл - ОП поможет тебе писать большие приложения правильно, соблюдая все лучшие практики, а не наобум.
Это не так просто, так как ты скорее всего за NAT провайдера и снаружи к тебе не подсоединиться.
Выше давали ссылку на сервис, который позволяет это обойти за счет проксирования: https://ngrok.com/
>>77622
Самый простой способ - деплой через гит. На сервере добавляешь в git hook баш-скрипт, который при пуше делает нужные действия: composer install, cache:warmup (для Симфони), прогон миграций итд. Не забудь set -e и проверку на ошибки в скрипте, так как баш скрипт по умолчанию при ошибке продолжает выполнять следующие команды.
Это годится для ненагруженного продакшена. Этот метод деплоя не "бесшовный", так как обновление происходит не мгновенно и есть период, когда часть файлов старая, а часть новая. Или когда файлы выложены, а команды деплоя еще не выполнены.
Для атомарного деплоя (для нагруженных сайтов) придется заморочиться: создаем новую папку, копируем файлы в нее, выполняем там все нужные команды, переключаем на сервере корневой каталог на новую папку. Плюс - возможность так же атомарно откатиться на старую папку.
На dev сервере это неудобно, так как надо делать коммит для выкладки изменений. Там лучше написать баш скрипт на основе rsync, который копирует изменившиеся файлы на сервер.
Более сложные способы - освоить ansible например. Он понадобится, когда у тебя будет не один, а больше серверов.
Больше ссылок:
- https://toster.ru/q/305788
- https://www.youtube.com/watch?v=qMu4YHJV1Z8 / https://www.slideshare.net/BadooDev/5-php-70464795 (заблокирован в РФ)
Почти никак. В стандарте сказано, что для элементов форм браузер сам решает, какие стили применять, а какие игнорировать. Разве что размер и цвет можно поменять. Что делать? Можно взять кастомное поле. Рисуем свою кнопку, поверх нее кладем прозрачный инпут, при выборе файла выводим яваскриптом имя. Плюс - любая кастомизация, минус - можно ухудшить элемент, может каком-то браузере стандартный лучше выглядит и работает.
>>77501
Давай я еще раз объясню возможные сценарии.
1) Главное у нас JS приложение. Браузеры без JS получают упрощенные HTML версии отрендеренных на сервере страниц
Запускаем на сервере наше JS-приложение. Пользователь заходит на главную, приложение пререндерит ему упрощенную главную страницу, отдает. Дополнительно отдает JS-код. Если браузер поддерживает JS, то код запускается и прицепляется к странице, делая ее полноценной.
Когда пользователь куда-то жмет, код перехватывает нажатие, получает данные через АПИ и отрисовывает на стороне браузера. Если у пользователя отключен JS, то при нажатии происходит переход по ссылке и упрощенная страница рендерится на сервере.
PHP тут отвечает только на запросы к API. Этот роутинг между PHP и JS можно настроить на нгинксе.
2) Есть отдельная упрощенная версия приложения
Запускаем на сервере наше JS-приложение. Пользователь заходит на главную, получает пустую страницу + ссылку на упрощенную версию (/html/) + JS код. Если он поддерживает JS, то приложение запускается и рисует в браузере интерфейс. Если нет - то он жмет на ссылку (или редиректится автоматом) на упрощенную версию.
Упрощенная версия рендерится запущенным на сервере JS приложением. У нее отдельный URL, и может быть, отдельные шаблоны. А может, она использует стандартные шаблоны, но с флагом для скрытия части элементов.
PHP тут отвечает только на запросы к API
> То есть сделать, например роут '/conversation/:id/' отдельно на PHP и отдельно на JS?
Если ты хочешь, чтобы запросы проходили через PHP, то сделать в нем этот роут и проксировать его на серверное JS-приложение, которое отрендерит его. Если ты не хочешь усложнять, то на уровне нгинкс проксируешь этот роут в серверное JS-приложение.
Если пользователь зашел напрямую на этот URL - он получает HTML страницу + JS приложение (на случай если у него включен JS). Если же пользователь внутри JS приложения нажимает на контакт, то никаких страниц не загружается, а приложение отправляет запрос к АПИ и своими силами выводит данные.
То есть роут и шаблон будет один - в JS приложении. Но оно может работать как в браузере (если в нем включен JS), так и на сервере.
Есть еще третий вариант - обрабатывать этот роут в PHP и выдавать упрощенную версию страницы. Мне он не очень нравится, так как подразумевает дублирование кода между JS и PHP приложением.
> Как понять отдельным модулем?
Если ты решил сделать отдельные, упрощенные версии страниц на отдельных URL (/html/conversation/:id/), то код для них незачем включать в браузерное приложение - он нужен только на сервере (и наоборот, код для отображения полноценных страниц в браузере не нужен на сервере). Логично разделить код на "бандлы" и не отправлять серверный "бандл" в браузер.
> Как модули JS могут быть не включены в браузерное приложение?
Если ты собираешь код вебпаком, то можешь настроить, чтобы он собирался в несколько отдельных "бандлов", а не в один огромный файл. И в браузере не грузить ненужные бандлы.
> Я конечно же об это знал, что сокеты могут отправить сигнал о завершении трансляции, но в этом случае не подумал об этом, потому что так было в примере предложенным самими разработчиками этого инструмента, и мне самому очень не понятно как устроен серверный код Angular'а и JS.
Я понимаю так: в ангуларе есть модуль platform-server. Он предоставляет функцию https://angular.io/api/platform-server/renderModuleFactory, которая берет HTML-код (пустышку с тегом <app-root>), URL, и рендерит в него содержимое данной страницы, как браузере. Также, в platform-server есть простейшая эмуляция браузерных API вроде document, DOM, window, location, чтобы код не падал с ошибкой из-за их отстутствия.
Ты берешь
1) Node.JS
2) модуль platform-server
3) свое ангулар-приложение
И добавляешь к ним небольшой вспомогательный скрипт. Этот скрипт поднимает HTTP-сервер, принимает HTTP-запросы от браузера и вызывает renderModuleFactory, которая настраивает окружение, вызывает твое приложение и оно рендерит запрошенную страницу. И отдает назад в браузер. То есть на сервере выполняется по сути тот же код, что в браузере, и рендерится статическая HTML страница. И почти без усилий ты получаешь серверную версию своего ангулар-приложения для браузеров без JS.
Твое приложение думает, что оно запущено в браузере, и работает точно так же. Шлет запросы к АПИ, берет шаблон, отрисовывает данные в нем (упс, не знаю, как там с промисами - не отрисует ли приложение просто индикатор загрузки, не дождавшись ответа АПИ?).
Описано тут: https://angular.io/guide/universal#how-it-works
> Здесь нет проблемы с получением данных, потому что я проверял вывод шаблонов без Symfony и всё было в порядке.
Это не значит, что код 100% корректный. Может, у тебя просто время передачи данных было такое, что они передались одним блоком. Плюс, ты наверно передавал данные на локалхосте между 2 процессами, почти без задержек.
Код некорректный. Событие data обозначает приход одной порции данных (причем размер порции никак не документирован и зависит от многих факторов), а не всех переданных данных. У тебя просто так вышло, что данные влезли в одну порцию.
Кстати, у тебя там server.close() вместо client.close().
> Я не знаю как это сделать и думаю что информации об этом не существует.
Даже если ее не существует, если понимать, как Angular universal работает, то можно попробовать придумать решение.
Тебе приходит HTTP-запрос от пользователя. В нем есть куки. Твое ангулар-приложение скорее всего использует их 2 путями:
- извлекает из document.cookie и что-то делает
- отправляет аякс-запросы, к которым они прикрепляются в браузере автоматически
На сервере, естественно, этого всего по умолчанию нет.
В platform-server наверно есть какая-то эмуляция видимых из браузера кук (document.cookie). Тебе надо их в нее как-то передать. Если там нет эмулции кук - придется сделать или найти библиотеку для этого.
Плюс, в platform-server есть эмуляция XMLHttpRequest для отправки аякс-запросов. Нужно как-то куки и туда прокинуть, если твое АПИ как-то их проверяет (вот мы и поняли, почему авторизация в АПИ без кук в данном случае удобнее).
При прокидывании кук ты должен помнить про асинхронность ноды и про то, что в теории она может обрабатывать несколько запросов параллельно. От разных пользователей с разными куками. Значит, установить куки глобально нельзя - нужно для каждого обрабатываемого запроса работать со своими куками.
Я погуглил по "angular platform-server pass cookies".
Судя по https://github.com/angular/angular/issues/15730 - возможность прокинуть куки есть, хоть и с багами.
> Кстати, полноценная возможность коммуникации Angular Universal с другими языками ещё только в разработке
В описанном мной варианте она не нужна.
> В том что шаблон я получаю в асинхронной функции, а в Symfony я могу отрендерить его только в синхроном коде контроллера
Ты получаешь шаблон (точнее, HTML код) из сокета. Используй синхронную библиотеку или функцию для работы с сокетами. Например: socket_create() + fwrite() в цикле (он с первого раза может не записать все данные) + stream_get_contents(). Не забудь проверку на ошибки. Ты разве не работал с сокетами Беркли, с TCP?
Там JS код для Ноды, он асинхронный. В PHP мы можем писать синхронный код и не мучаться.
> Разве Babel не транспилирует ES6 ещё?
Да, он транспилирует ES6 в ES5. А к ES5 коду мы можем добавить ES5 shim дял браузеров, которые поддерживают только ES3, и надеяться, что это заработает. Если не заработает - давать им HTML версию.
Если у тебя есть время, я бы советовал полностью разобраться в этом. Так как пока есть пробелы в знаниях. Я всегда готов ответить на вопросы и пояснить.
Почти никак. В стандарте сказано, что для элементов форм браузер сам решает, какие стили применять, а какие игнорировать. Разве что размер и цвет можно поменять. Что делать? Можно взять кастомное поле. Рисуем свою кнопку, поверх нее кладем прозрачный инпут, при выборе файла выводим яваскриптом имя. Плюс - любая кастомизация, минус - можно ухудшить элемент, может каком-то браузере стандартный лучше выглядит и работает.
>>77501
Давай я еще раз объясню возможные сценарии.
1) Главное у нас JS приложение. Браузеры без JS получают упрощенные HTML версии отрендеренных на сервере страниц
Запускаем на сервере наше JS-приложение. Пользователь заходит на главную, приложение пререндерит ему упрощенную главную страницу, отдает. Дополнительно отдает JS-код. Если браузер поддерживает JS, то код запускается и прицепляется к странице, делая ее полноценной.
Когда пользователь куда-то жмет, код перехватывает нажатие, получает данные через АПИ и отрисовывает на стороне браузера. Если у пользователя отключен JS, то при нажатии происходит переход по ссылке и упрощенная страница рендерится на сервере.
PHP тут отвечает только на запросы к API. Этот роутинг между PHP и JS можно настроить на нгинксе.
2) Есть отдельная упрощенная версия приложения
Запускаем на сервере наше JS-приложение. Пользователь заходит на главную, получает пустую страницу + ссылку на упрощенную версию (/html/) + JS код. Если он поддерживает JS, то приложение запускается и рисует в браузере интерфейс. Если нет - то он жмет на ссылку (или редиректится автоматом) на упрощенную версию.
Упрощенная версия рендерится запущенным на сервере JS приложением. У нее отдельный URL, и может быть, отдельные шаблоны. А может, она использует стандартные шаблоны, но с флагом для скрытия части элементов.
PHP тут отвечает только на запросы к API
> То есть сделать, например роут '/conversation/:id/' отдельно на PHP и отдельно на JS?
Если ты хочешь, чтобы запросы проходили через PHP, то сделать в нем этот роут и проксировать его на серверное JS-приложение, которое отрендерит его. Если ты не хочешь усложнять, то на уровне нгинкс проксируешь этот роут в серверное JS-приложение.
Если пользователь зашел напрямую на этот URL - он получает HTML страницу + JS приложение (на случай если у него включен JS). Если же пользователь внутри JS приложения нажимает на контакт, то никаких страниц не загружается, а приложение отправляет запрос к АПИ и своими силами выводит данные.
То есть роут и шаблон будет один - в JS приложении. Но оно может работать как в браузере (если в нем включен JS), так и на сервере.
Есть еще третий вариант - обрабатывать этот роут в PHP и выдавать упрощенную версию страницы. Мне он не очень нравится, так как подразумевает дублирование кода между JS и PHP приложением.
> Как понять отдельным модулем?
Если ты решил сделать отдельные, упрощенные версии страниц на отдельных URL (/html/conversation/:id/), то код для них незачем включать в браузерное приложение - он нужен только на сервере (и наоборот, код для отображения полноценных страниц в браузере не нужен на сервере). Логично разделить код на "бандлы" и не отправлять серверный "бандл" в браузер.
> Как модули JS могут быть не включены в браузерное приложение?
Если ты собираешь код вебпаком, то можешь настроить, чтобы он собирался в несколько отдельных "бандлов", а не в один огромный файл. И в браузере не грузить ненужные бандлы.
> Я конечно же об это знал, что сокеты могут отправить сигнал о завершении трансляции, но в этом случае не подумал об этом, потому что так было в примере предложенным самими разработчиками этого инструмента, и мне самому очень не понятно как устроен серверный код Angular'а и JS.
Я понимаю так: в ангуларе есть модуль platform-server. Он предоставляет функцию https://angular.io/api/platform-server/renderModuleFactory, которая берет HTML-код (пустышку с тегом <app-root>), URL, и рендерит в него содержимое данной страницы, как браузере. Также, в platform-server есть простейшая эмуляция браузерных API вроде document, DOM, window, location, чтобы код не падал с ошибкой из-за их отстутствия.
Ты берешь
1) Node.JS
2) модуль platform-server
3) свое ангулар-приложение
И добавляешь к ним небольшой вспомогательный скрипт. Этот скрипт поднимает HTTP-сервер, принимает HTTP-запросы от браузера и вызывает renderModuleFactory, которая настраивает окружение, вызывает твое приложение и оно рендерит запрошенную страницу. И отдает назад в браузер. То есть на сервере выполняется по сути тот же код, что в браузере, и рендерится статическая HTML страница. И почти без усилий ты получаешь серверную версию своего ангулар-приложения для браузеров без JS.
Твое приложение думает, что оно запущено в браузере, и работает точно так же. Шлет запросы к АПИ, берет шаблон, отрисовывает данные в нем (упс, не знаю, как там с промисами - не отрисует ли приложение просто индикатор загрузки, не дождавшись ответа АПИ?).
Описано тут: https://angular.io/guide/universal#how-it-works
> Здесь нет проблемы с получением данных, потому что я проверял вывод шаблонов без Symfony и всё было в порядке.
Это не значит, что код 100% корректный. Может, у тебя просто время передачи данных было такое, что они передались одним блоком. Плюс, ты наверно передавал данные на локалхосте между 2 процессами, почти без задержек.
Код некорректный. Событие data обозначает приход одной порции данных (причем размер порции никак не документирован и зависит от многих факторов), а не всех переданных данных. У тебя просто так вышло, что данные влезли в одну порцию.
Кстати, у тебя там server.close() вместо client.close().
> Я не знаю как это сделать и думаю что информации об этом не существует.
Даже если ее не существует, если понимать, как Angular universal работает, то можно попробовать придумать решение.
Тебе приходит HTTP-запрос от пользователя. В нем есть куки. Твое ангулар-приложение скорее всего использует их 2 путями:
- извлекает из document.cookie и что-то делает
- отправляет аякс-запросы, к которым они прикрепляются в браузере автоматически
На сервере, естественно, этого всего по умолчанию нет.
В platform-server наверно есть какая-то эмуляция видимых из браузера кук (document.cookie). Тебе надо их в нее как-то передать. Если там нет эмулции кук - придется сделать или найти библиотеку для этого.
Плюс, в platform-server есть эмуляция XMLHttpRequest для отправки аякс-запросов. Нужно как-то куки и туда прокинуть, если твое АПИ как-то их проверяет (вот мы и поняли, почему авторизация в АПИ без кук в данном случае удобнее).
При прокидывании кук ты должен помнить про асинхронность ноды и про то, что в теории она может обрабатывать несколько запросов параллельно. От разных пользователей с разными куками. Значит, установить куки глобально нельзя - нужно для каждого обрабатываемого запроса работать со своими куками.
Я погуглил по "angular platform-server pass cookies".
Судя по https://github.com/angular/angular/issues/15730 - возможность прокинуть куки есть, хоть и с багами.
> Кстати, полноценная возможность коммуникации Angular Universal с другими языками ещё только в разработке
В описанном мной варианте она не нужна.
> В том что шаблон я получаю в асинхронной функции, а в Symfony я могу отрендерить его только в синхроном коде контроллера
Ты получаешь шаблон (точнее, HTML код) из сокета. Используй синхронную библиотеку или функцию для работы с сокетами. Например: socket_create() + fwrite() в цикле (он с первого раза может не записать все данные) + stream_get_contents(). Не забудь проверку на ошибки. Ты разве не работал с сокетами Беркли, с TCP?
Там JS код для Ноды, он асинхронный. В PHP мы можем писать синхронный код и не мучаться.
> Разве Babel не транспилирует ES6 ещё?
Да, он транспилирует ES6 в ES5. А к ES5 коду мы можем добавить ES5 shim дял браузеров, которые поддерживают только ES3, и надеяться, что это заработает. Если не заработает - давать им HTML версию.
Если у тебя есть время, я бы советовал полностью разобраться в этом. Так как пока есть пробелы в знаниях. Я всегда готов ответить на вопросы и пояснить.
> сначала отдавалась отрендеренная страница на PHP, а потом инициализировался JS, и все переходы по контактам, подгрузка новых или старых сообщений, и поиск контактов происходили "плавно" (если не считать времени на получение сообщений через http и дешифровку).
Так тоже можно, пока приложение простое. Как только оно превращается в полноценное MVC приложение, начинает само хранить данные, рендерить их в шаблон, работать в оффлайне - получается дублирование кода - тебе нужен одинаковый шаблон в PHP и в JS, одинаковый код для обработки данных, одинаковые классы и там, и там.
Если твой код просто посылает аякс-запрос на сервер, получает HTML, вставляет его в DOM (или делает небольшие изменения через jQuery) - это работает. Но если ты хочешь в браузере работать с моделями и рендрить их в шаблоны - это уже не работает. Так как у тебя получается дублирование кода.
>>Или представь такой сценарий: пользователь в оффлайне отправляет сообщение, оно сохраняется в localStorage, пользователь закрывает вкладку. Затем пользователь снова открывает вкладку - и в отрендеренной сервером странице этого сообщения нету.
> Тут нужно сначала определить, где именно будут хранится сообщения... Или, если это не имеет значения, то всегда отправлять сообщения из localStorage на сервер при восстановлении соединения и обновлять вкладку.
Это не выход. Представь, что интернет пропал в тот момент, когда пользователь печатал сообщение. Но это не большая проблема, в описанном мной случае сообщение не теряется, просто его не будет в отрендеренной сервером странице и оно отобразится чуть позже, когда активируется JS-приложение в браузере.
> А можно и API написать на Node.js
Тогда можно на PHP. По идее синхронный код на PHP написать проще. Хотя асинхронный с ReactPHP (или с нодой, или с Го) будет быстрее, что важно для мессенджера. Ну и сложные задачи ведь интереснее.
> Только я не умею писать сервера
Надо изучить сокеты Беркли и попробовать что-то написать. Я могу придумать задачку. Для начала: сделай 2 приложения, клиент и сервер. Сервер открывает порт X, слушает его, принимает соединение, выводит, все, что передано, в консоль, закрывает соединение, ждет следущее и так бесконечно. Клиент при запуске соединяется с сервером на порту X и передает указанное в аргументах командной строки сообщение.
Писать можно на любом языке, синхронно или асинхронно.
Если вдруг ты это уже делал и знаешь, и хочешь писать именно на Ноде, то изучай express например. Сделай на нем hello world.
> в мануале по Angular'у написано что их пример сервера не безопасен
Ну значит надо написать безопасный. Хотя было бы хорошо пояснить, что в нем не так.
> Я склоняюсь к тому чтобы попробовать React, и если с ним не получится, то написать на ES6, и если и на нём не получится, то на Node.js уж железно получится написать приложение на Angular'е!
Ты по моему смешал все в кучу. ES6 - это версия JS, а React/Angular - фреймворки. Писать можно на любом.
> то на Node.js уж железно получится написать приложение на Angular'е!
Angular предназначен для браузера. На ноде он запускается только для серверного рендеринга и это дополнительная фича, а не основное предназначение. На сервере, если ты пишешь чисто серверное приложение, ни ангулар, ни реакт не нужны, это оверинжиниринг, там хватит обычного шаблонизатора, коих под ноду предостаточно.
Не путай:
- обычный шаблонизатор: получает данные и шаблон, рендерит HTML. Самое то для сервера.
- ангулар/реакт: получает данные ("модель" или view model, что точнее) и шаблон, рендерит, записывает в DOM, данные меняются, он снова рендерит и снова обновляет ДОМ. Так пока пользователь не закроет вкладку. Самое то для браузерного приложения.
Разница между реакт и ангулар в том, как они ищут изменения.
- ангулар сравнивает текущее состояние модели с сохраненным предыдущим, находит различия и обновляет части DOM, которые зависели от этих данных (то есть рендерит заново только кусок шаблона с измененными данными). Например, если ты в поле ввода вывел значение из модели, потом поменял его в модели, ангулар перерендерит и обновит поле ввода.
- реакт берет модель, рендерит из нее DOM и сранивает этот DOM с текущим на странице. Находит различия и вносит изменения в DOM на странице.
Ну и еще, реакт это только библиотека для view, а англуар это полноценный фреймворк, который предоставляет еще например DI, и многое другое.
> сначала отдавалась отрендеренная страница на PHP, а потом инициализировался JS, и все переходы по контактам, подгрузка новых или старых сообщений, и поиск контактов происходили "плавно" (если не считать времени на получение сообщений через http и дешифровку).
Так тоже можно, пока приложение простое. Как только оно превращается в полноценное MVC приложение, начинает само хранить данные, рендерить их в шаблон, работать в оффлайне - получается дублирование кода - тебе нужен одинаковый шаблон в PHP и в JS, одинаковый код для обработки данных, одинаковые классы и там, и там.
Если твой код просто посылает аякс-запрос на сервер, получает HTML, вставляет его в DOM (или делает небольшие изменения через jQuery) - это работает. Но если ты хочешь в браузере работать с моделями и рендрить их в шаблоны - это уже не работает. Так как у тебя получается дублирование кода.
>>Или представь такой сценарий: пользователь в оффлайне отправляет сообщение, оно сохраняется в localStorage, пользователь закрывает вкладку. Затем пользователь снова открывает вкладку - и в отрендеренной сервером странице этого сообщения нету.
> Тут нужно сначала определить, где именно будут хранится сообщения... Или, если это не имеет значения, то всегда отправлять сообщения из localStorage на сервер при восстановлении соединения и обновлять вкладку.
Это не выход. Представь, что интернет пропал в тот момент, когда пользователь печатал сообщение. Но это не большая проблема, в описанном мной случае сообщение не теряется, просто его не будет в отрендеренной сервером странице и оно отобразится чуть позже, когда активируется JS-приложение в браузере.
> А можно и API написать на Node.js
Тогда можно на PHP. По идее синхронный код на PHP написать проще. Хотя асинхронный с ReactPHP (или с нодой, или с Го) будет быстрее, что важно для мессенджера. Ну и сложные задачи ведь интереснее.
> Только я не умею писать сервера
Надо изучить сокеты Беркли и попробовать что-то написать. Я могу придумать задачку. Для начала: сделай 2 приложения, клиент и сервер. Сервер открывает порт X, слушает его, принимает соединение, выводит, все, что передано, в консоль, закрывает соединение, ждет следущее и так бесконечно. Клиент при запуске соединяется с сервером на порту X и передает указанное в аргументах командной строки сообщение.
Писать можно на любом языке, синхронно или асинхронно.
Если вдруг ты это уже делал и знаешь, и хочешь писать именно на Ноде, то изучай express например. Сделай на нем hello world.
> в мануале по Angular'у написано что их пример сервера не безопасен
Ну значит надо написать безопасный. Хотя было бы хорошо пояснить, что в нем не так.
> Я склоняюсь к тому чтобы попробовать React, и если с ним не получится, то написать на ES6, и если и на нём не получится, то на Node.js уж железно получится написать приложение на Angular'е!
Ты по моему смешал все в кучу. ES6 - это версия JS, а React/Angular - фреймворки. Писать можно на любом.
> то на Node.js уж железно получится написать приложение на Angular'е!
Angular предназначен для браузера. На ноде он запускается только для серверного рендеринга и это дополнительная фича, а не основное предназначение. На сервере, если ты пишешь чисто серверное приложение, ни ангулар, ни реакт не нужны, это оверинжиниринг, там хватит обычного шаблонизатора, коих под ноду предостаточно.
Не путай:
- обычный шаблонизатор: получает данные и шаблон, рендерит HTML. Самое то для сервера.
- ангулар/реакт: получает данные ("модель" или view model, что точнее) и шаблон, рендерит, записывает в DOM, данные меняются, он снова рендерит и снова обновляет ДОМ. Так пока пользователь не закроет вкладку. Самое то для браузерного приложения.
Разница между реакт и ангулар в том, как они ищут изменения.
- ангулар сравнивает текущее состояние модели с сохраненным предыдущим, находит различия и обновляет части DOM, которые зависели от этих данных (то есть рендерит заново только кусок шаблона с измененными данными). Например, если ты в поле ввода вывел значение из модели, потом поменял его в модели, ангулар перерендерит и обновит поле ввода.
- реакт берет модель, рендерит из нее DOM и сранивает этот DOM с текущим на странице. Находит различия и вносит изменения в DOM на странице.
Ну и еще, реакт это только библиотека для view, а англуар это полноценный фреймворк, который предоставляет еще например DI, и многое другое.
Я хотел добавить: не думай, что есть одна лучшая, универсальная архитектура. Для разных случаев подходят разные решения.
Ты делаешь форум - один подход. Делаешь сайт с редко менябщейся документацией - другой. Делаешь интерактивное приложение (мессенджер) - третий.
> В итоге с перерывами уже 3 года кожу по сути. Дальше вектора в итоге не дошел в силу лени и неусидчивости.
А на работе как дела? Часто нагоняй получаешь от ТимЛида?Повышали зп? Менял место работы?
Какие подводные? Заведётся ли докер? Вообще, стоит ли пробовать такое?
Вопрос: как создавать этот хэш? Какой функцией или алгоритмом?
Или могут и я где-то проебался?
Вот загуглил про нее, думаю какой алгоритм теперь выбрать.
Алао на счёт соли непонятно: как ее сгенерить и какой длины, подставлять в начало или конец, можно ли хранить ее как константу класса или обязательно в БД?
Приватные функции родительского абстрактного класса могут использоваться в защищённых функциях в нем же. А доступ к защищённым есть у дочернего класса.
Пожалуй, поясню немного. Вот какой смысл в этой хуйне? Чтобы что? Пик 1
Лол, пока формулировал вопрос - разобрался (относительно). Пик 2 - работает, но я не очень понимаю как, почему и за счёт чего.
То есть, если в родителе есть приватный метод, который вызывается внутри публичной функции этого же родителя, то при запуске этой унаследованной публичной функции приватный метод спокойно дёрнется. Вопрос только в том - как? Видимо, я чего-то не понял про области видимости и всю эту хуйню.
Почему если я реализую в ребёнке идентичный по коду метод, то он не будет работать, а унаследованный от родителя - будет? Пик 3. Если вместо $this в 22 строке использовать parent::, то ничего не изменится.
>>79399
Не до конца уверен, что правильно осознал написанное, но пока аутировал тут - на мой вопрос ответили. Ну и хуй с ним, всё равно вкину в тред, может, кому-то другому поможет наблюдение за ходом моей мысли.
Но при вскрывшхиося обстоятельствах получается вот есть. Есть класс АК (абстрактный класс), он содержит приватное свойство $prop. Он же (АК) содержит метод pub_fn(), который меняет значение $prop и выводит его на экран. На основе АК мы создаём другой класс, К1. Делаем объект О1К1, вызываем его функцию pub_fn(), которую его класс унаследовал от АК1, свойство меняется и выводится. Создаём О2К1, свойство меняется и выводится.
Но где, блжард, это свойство находится? Оно вообще часть чего? Если оно часть объекта, то с хуя ли внутри класса К1 не получается получить к нему доступ через $this? Мой взгляд, который заключался в том, что объект - это некая единая сущность, которая просто "собирает воедино весь код относящихся к нему классов" (ну, типа, есть АК (абстрактный класс), там объявлено свойство $prop, это свойство - часть объекта, этой частью объекта мы можем манипулировать и из класса К1, который унаследован от АК) - тупое говно тупого говна? Видимо, объект - это какая-то такая не очень цельная хуита, в которой, условно говоря, каждый класс имеет некую свою область видимости не связанную со внешним миром?
То есть, $this - не указание на объект как таковой, а указание на "ту часть объекта, которая связана с этим классом"?
>>78721
Мне нравится 3-ий вариант с дублированием кода, но я не могу понять, почему это плохо - это плата за то чтобы опыт пользователя был максимально комфортным.
В отличие от первых двух вариантов, не нужно иметь отдельно и JS и PHP приложения на сервере, а можно обойтись чем-то одним - либо PHP, либо JS.
И к тому же, всё равно не получится не дублировать код. Допустим в упрощенной HTML версии есть формы (поиск или отправка сообщения), их всё равно нужно будет обработать на сервере так же как и в фронтенд JS приложении. Разве это не так?
Если не существует универсальной архитектуры, то почему бы не применить и такой способ?
Однако, как я уже писал, первые два способа можно улучшить, отказавшись от PHP и писать API на Node.js.
И даже можно ещё сильнее улучшить это, отрисовав Angular приложение на сервере Node.js, и тогда не придётся дублировать код. Только придётся самому написать библиотеку для проброса кукисов и не ясно какой ответ будет от запросов отправленных с упрощенной HTML страницы, и как там с промисами. Но об этом позже.
>> Я склоняюсь к тому чтобы попробовать React, и если с ним не получится, то написать на ES6, и если и на нём не получится, то на Node.js уж железно получится написать приложение на Angular'е!
>Ты по моему смешал все в кучу. ES6 - это версия JS, а React/Angular - фреймворки. Писать можно на любом.
Я имел ввиду, что у меня есть три варианта на чем написать приложение.
1) PHP (Symfony) + React на фронтенде
+Использование популярного фронтенд фреймворка
+Сверх быстрая отрисовка DOM
-Нужно изучить React, чтобы понять может ли он подхватывать отрендеренную на сервере HTML страницу и дальше работать как SPA приложение
-Дублирование серверного и клиентского кода
2) PHP (Symfony) + нативное ES6 приложение на фронтенде
+Не нужно ничего изучать
-Вспомогательные библиотеки могут не соответствовать заданным требованиям
-Дублирование серверного и клиентского кода
3) Node.JS + Angular
+Использование популярного фронтенд фреймворка
+Возможность подключить модуль platform-server на сервере Node.js и легко вывести отрендеренную Angular'ом стрианицу
-Нужно изучить устройство Node.js сервера
-Нужно написать безопасный скрипт для подъема сервера и вызова renderModuleFactory
-Нужно пробрасывать кукисы используя не совершенный подход, ранее испытав неудачный опыт с Angular Socket Engine (это тяжело поддерживать)
-Неизвестно какой ответ будет от запросов отправленных с упрощенной HTML страницы и будут ли промисы выполняться тоже на серверной части или "подхватяться" на клиентской
И ещё мне сейчас пришел 4-ый вариант с вашей подсказкой про socket_create():
4) PHP (Symfony) + Angular
+Использование популярного фронтенд фреймворка
+PHP отвечает и за отрисовку и за API приложения
+Не нужно ничего изучать
-Нужно пробрасывать кукисы используя не совершенный подход, ранее испытав неудачный опыт с Angular Socket Engine (это тяжело поддерживать)
-Неизвестно какой ответ будет от запросов отправленных с упрощенной HTML страницы и будут ли промисы выполнятся тоже на серверной части или "подхватяться" на клиентской
-Тяжело поддерживать, в связи с тем, что данный подход мало известен, т.е. имеет низкий порог вхождения для сторонних разработчиков
У меня есть пробелы в знаниях, так как отсутствует опыт написания современных JS приложений, поэтому мне бы пригодился ваш совет что из этого выбрать, чтобы было просто надёжно, т.е. чтобы в дальнейшем не возникало каких-то проблем с подхватом HTML страницы JS кодом, чтобы после подхвата работало полноценное SPA приложение, чтобы на сервере не нужно было без конца применять не совершенные подходы. Если сократить, то вопрос будет простым - может ли React подхватывать HTML страницу и вешать на неё JS?
>Кстати, у тебя там server.close() вместо client.close().
Где? $connection это же вроде client, разве нет?
>>78721
Мне нравится 3-ий вариант с дублированием кода, но я не могу понять, почему это плохо - это плата за то чтобы опыт пользователя был максимально комфортным.
В отличие от первых двух вариантов, не нужно иметь отдельно и JS и PHP приложения на сервере, а можно обойтись чем-то одним - либо PHP, либо JS.
И к тому же, всё равно не получится не дублировать код. Допустим в упрощенной HTML версии есть формы (поиск или отправка сообщения), их всё равно нужно будет обработать на сервере так же как и в фронтенд JS приложении. Разве это не так?
Если не существует универсальной архитектуры, то почему бы не применить и такой способ?
Однако, как я уже писал, первые два способа можно улучшить, отказавшись от PHP и писать API на Node.js.
И даже можно ещё сильнее улучшить это, отрисовав Angular приложение на сервере Node.js, и тогда не придётся дублировать код. Только придётся самому написать библиотеку для проброса кукисов и не ясно какой ответ будет от запросов отправленных с упрощенной HTML страницы, и как там с промисами. Но об этом позже.
>> Я склоняюсь к тому чтобы попробовать React, и если с ним не получится, то написать на ES6, и если и на нём не получится, то на Node.js уж железно получится написать приложение на Angular'е!
>Ты по моему смешал все в кучу. ES6 - это версия JS, а React/Angular - фреймворки. Писать можно на любом.
Я имел ввиду, что у меня есть три варианта на чем написать приложение.
1) PHP (Symfony) + React на фронтенде
+Использование популярного фронтенд фреймворка
+Сверх быстрая отрисовка DOM
-Нужно изучить React, чтобы понять может ли он подхватывать отрендеренную на сервере HTML страницу и дальше работать как SPA приложение
-Дублирование серверного и клиентского кода
2) PHP (Symfony) + нативное ES6 приложение на фронтенде
+Не нужно ничего изучать
-Вспомогательные библиотеки могут не соответствовать заданным требованиям
-Дублирование серверного и клиентского кода
3) Node.JS + Angular
+Использование популярного фронтенд фреймворка
+Возможность подключить модуль platform-server на сервере Node.js и легко вывести отрендеренную Angular'ом стрианицу
-Нужно изучить устройство Node.js сервера
-Нужно написать безопасный скрипт для подъема сервера и вызова renderModuleFactory
-Нужно пробрасывать кукисы используя не совершенный подход, ранее испытав неудачный опыт с Angular Socket Engine (это тяжело поддерживать)
-Неизвестно какой ответ будет от запросов отправленных с упрощенной HTML страницы и будут ли промисы выполняться тоже на серверной части или "подхватяться" на клиентской
И ещё мне сейчас пришел 4-ый вариант с вашей подсказкой про socket_create():
4) PHP (Symfony) + Angular
+Использование популярного фронтенд фреймворка
+PHP отвечает и за отрисовку и за API приложения
+Не нужно ничего изучать
-Нужно пробрасывать кукисы используя не совершенный подход, ранее испытав неудачный опыт с Angular Socket Engine (это тяжело поддерживать)
-Неизвестно какой ответ будет от запросов отправленных с упрощенной HTML страницы и будут ли промисы выполнятся тоже на серверной части или "подхватяться" на клиентской
-Тяжело поддерживать, в связи с тем, что данный подход мало известен, т.е. имеет низкий порог вхождения для сторонних разработчиков
У меня есть пробелы в знаниях, так как отсутствует опыт написания современных JS приложений, поэтому мне бы пригодился ваш совет что из этого выбрать, чтобы было просто надёжно, т.е. чтобы в дальнейшем не возникало каких-то проблем с подхватом HTML страницы JS кодом, чтобы после подхвата работало полноценное SPA приложение, чтобы на сервере не нужно было без конца применять не совершенные подходы. Если сократить, то вопрос будет простым - может ли React подхватывать HTML страницу и вешать на неё JS?
>Кстати, у тебя там server.close() вместо client.close().
Где? $connection это же вроде client, разве нет?
Я не работал с ним, так что предлагаю изучить https://wiki.freebsd.org/Docker и проверить экспериментально.
С удивлением прочел, что в FreeBSD есть слой совместимости с линуксом.
Но вообще, на PHP можно и без докера разрабатывать.
Это не хеш. Хеш это результат математического преобразования исходных данных. Почитай определение: https://ru.wikipedia.org/wiki/Хеширование
Тебе нужен просто случайно сгенерированный надежным генератором токен. В PHP7 для этого есть random_int и random_bytes.
"Приватное" поле значит. что обращаться к нему можно только из кода в том же классе, то есть кода, который написан между class { ... и }.
От того, что ты сделал класс-наследник, ничего не меняется. Из наследника обращаться к приватному полю нельзя, но можно вызвать метод базового класса, который имеет доступ к полю.
Наследование не значит, что методы куда-то переносятся в другой класс. Они остаются на месте, просто если в наследнике такого метода нет, то он ищется в предках (с проверкой прав доступа)
Если тебе система кажется не очень логичной, то представь такое: представь, что каждый класс пишет отдельный человек. И он не имеет доступа к другому коду, кроме своего класса.
Если он хочет использовать другой класс, то ему не дают посмотреть весь код, а только доступные ему (публичные или защищенные) поля и методы.
Тогда приватные поля и методы - это то, что он оставил только для себя. Соответственно, он полностью контролирует, как с ними можно работать, что в них класть, итд. Публичные/защищенные элементы класса - это то, что позволяет использовать другим, опять же контролируя при этом их использование.
Идея в том, что с помощью прав доступа автор класса может контролировать то, как он будет использоваться. И это позволяет ему давать гарантии, что код будет работать корректно.
Таким образом, реализуется инкапсуляция - сокрытие внутреннего устройства класса и разделение ответственности между классами.
Свойство это часть объекта. Класс же просто описывает, каике именно свойства есть у объектов и какие у них значения по умолчанию.
При этом вся логика доступа работает так, как описано в классах.
Если тебе хочется представить, как это выглядит, то пожалуйста:
Когда ты описываешь класс, PHP читает это описание и сохраняет в память в удобному ему виде:
[Класс]
Название: Parent
Предок: нету
Поля:
- private $a = null
- public $b = 1
Методы: ....
В классе хранятся только значения свойств по умолчанию.
Если ты наследуешь класс - он сохраняет в память описание второго класса и ставит ссылку на базовый:
[Класс]
Название: Child
Предок: Parent
Поля:
- public $b = 3; // переопределяем значение поля по умолчанию
- public $c = 2;
- private $a = 10; // это другое поле! не то же, что выше
Методы: ....
Когда ты создаешь объект определенного класса, PHP читает его описание, определяет, какие есть свойства у класса и всех его предков, выделяет кусок памяти, размечает его и сохраняет туда начальные значения свойств (которые позже можно поменять). Заодно он сохраняет ссылку на описание класса:
[Объект]
Ссылка на класс: Child
Значения полей:
- Parent#a/private: null
- Child#b: 3
- Child#c: 2
- Child#a/private: 10
Здесь свойство b встречается только 1 раз, так как определение в классе Child просто переопределяет то, что в Parent.
Потом вызывает конструктор. Заметь, что в объекте список методов не хранится, так как он есть в классе, удалять или добавлять методы в объект нельзя и потому незачем его дублировать.
Когда ты что-то делаешь со свойством объекта (читаешь или пишешь), PHP сначала определяет, какое свойство тебе нужно (с учетом правил доступа) и меняет его значение.
Если ты из класса Parent сделаешь $this->a = .., то PHP будет искать поля в таком порядке:
приватное поле Parent#a
Child#a
Parent#a
Если ты из класса Child сделаешь $this->a = ..., то PHP будет искать поле в таком порядке:
приватное поле Child#a
Child#a
Parent#a
Если снаружи - то он будет искать в порядке
Child#a
Parent#a
Вот интересный код для проверки (и для собеседования):
class A
{
private $a = 1;
}
class B extends A
{
private $a = 2;
}
class C extends B
{
public $a = 3;
}
class D extends C
{
public $a = 4;
}
var_dump(new A);
var_dump(new B);
var_dump(new C);
var_dump(new D);
Что он выведет? Попробуй подумать, потом смотри ответ https://ideone.com/VM3tVG
Свойство это часть объекта. Класс же просто описывает, каике именно свойства есть у объектов и какие у них значения по умолчанию.
При этом вся логика доступа работает так, как описано в классах.
Если тебе хочется представить, как это выглядит, то пожалуйста:
Когда ты описываешь класс, PHP читает это описание и сохраняет в память в удобному ему виде:
[Класс]
Название: Parent
Предок: нету
Поля:
- private $a = null
- public $b = 1
Методы: ....
В классе хранятся только значения свойств по умолчанию.
Если ты наследуешь класс - он сохраняет в память описание второго класса и ставит ссылку на базовый:
[Класс]
Название: Child
Предок: Parent
Поля:
- public $b = 3; // переопределяем значение поля по умолчанию
- public $c = 2;
- private $a = 10; // это другое поле! не то же, что выше
Методы: ....
Когда ты создаешь объект определенного класса, PHP читает его описание, определяет, какие есть свойства у класса и всех его предков, выделяет кусок памяти, размечает его и сохраняет туда начальные значения свойств (которые позже можно поменять). Заодно он сохраняет ссылку на описание класса:
[Объект]
Ссылка на класс: Child
Значения полей:
- Parent#a/private: null
- Child#b: 3
- Child#c: 2
- Child#a/private: 10
Здесь свойство b встречается только 1 раз, так как определение в классе Child просто переопределяет то, что в Parent.
Потом вызывает конструктор. Заметь, что в объекте список методов не хранится, так как он есть в классе, удалять или добавлять методы в объект нельзя и потому незачем его дублировать.
Когда ты что-то делаешь со свойством объекта (читаешь или пишешь), PHP сначала определяет, какое свойство тебе нужно (с учетом правил доступа) и меняет его значение.
Если ты из класса Parent сделаешь $this->a = .., то PHP будет искать поля в таком порядке:
приватное поле Parent#a
Child#a
Parent#a
Если ты из класса Child сделаешь $this->a = ..., то PHP будет искать поле в таком порядке:
приватное поле Child#a
Child#a
Parent#a
Если снаружи - то он будет искать в порядке
Child#a
Parent#a
Вот интересный код для проверки (и для собеседования):
class A
{
private $a = 1;
}
class B extends A
{
private $a = 2;
}
class C extends B
{
public $a = 3;
}
class D extends C
{
public $a = 4;
}
var_dump(new A);
var_dump(new B);
var_dump(new C);
var_dump(new D);
Что он выведет? Попробуй подумать, потом смотри ответ https://ideone.com/VM3tVG
А как же коллизии? Для разный email'ов теоретически может быть одинаковая "рандомная" строка.
> То есть, $this - не указание на объект как таковой, а указание на "ту часть объекта, которая связана с этим классом"?
Это указание на объект, просто при поиске свойства или метода проверяются правила доступа. И учитывается, из какого класса мы пытаемся к ним обратиться.
1) Ну-ка посчитай вероятность такой коллизии
2) Ты можешь при генерации проверить, нет ли коллизии, и перегенерировать.
>2) Ты можешь при генерации проверить, нет ли коллизии, и перегенерировать
Тогда лишний запрос к БД.
Не легче ли поюзать что-то типа:
$salt = 'verystrongsalt';
$token = hash('sha256', $salt . '
При использовании хеша возможны те же коллизии.
Плюс, если украсть соль, то можно получить все хеши сразу.
Какой плюс у хешей тут? Я не вижу.
Я замечаю, что когда некоторые люди узнают про хеш-функции, они пытаются везде их использовать, даже там, где не надо.
>Какой плюс у хешей тут? Я не вижу.
Ну хотя бы не делать лишний запрос в БД, чтобы искать, есть ли такая рандомная строка или нет.
Спасибо, анон, за пояснения про деплой - очень полезно.
Пошел нахуй
Подскажите пожалуйста как добавлять запрос в конец URI по клику на кнопку, может есть способ проще чем разбирать текущий и собирать новый?
В той же задаче про список студентов: поиск index.php?search=хуй, потом сортировка &sort_by=first_name, а потом го на вторую страницу &page=2.
Смотри, у меня уже есть результат поиска, выглядит так: i.php?search=хуй
Делаю кнопку с href='i.php?sort_by=хуй'.
И таблица будет отсортирована, только результаты поиска пойдут по пизде, а хотелось бы чтоб по клику стало i.php?search=хуй&sort_by=хуй, но может же быть сортировка и до поиска.
Удобнее всего собирать с нуля функцией с кучей аргументов.
Зачем что-то делать с URL, что-то там дописывать, вырезать? Это плохой путь.
Кстати, есть еще относительные URL вида ?sort=name : https://github.com/codedokode/pasta/blob/master/network/urls.md
ПРИСВАИВАЕШЬ ПЕРЕМЕННУЮ
@
ПРИСВАИВАЕТСЯ
@
ТЕПЕРЬ У ТЕБЯ ДВЕ ПЕРЕМЕННЫХ
@
ЗАБЫЛ ПРИСВОИТЬ
@
А ОНА УЖЕ ПРИСВОЕНА ДО ТЕБЯ
@
ЛОГИЧНОСТЬ
Да, это, скорее, на миддла.
>Самый простой способ - деплой через гит. На сервере добавляешь в git hook баш-скрипт, который при пуше делает нужные действия
А как git на рабочем сервере узнает об этом пуше?
Я думаю сделать так: на локальной машине, где ведётся разработка, я делаю пуш в удалённый репозиторий (битбакет), на битбакете настраиваю веб-хук, инфа о пуше через веб-хук летит на рабочий сервер по адресу сайта и там я уже запускаю composer если надо, git pull и т.д.
Хуйня или норм?
>включаешь видеокурс
>в первом же ролики говорят, что либо ты используешь пхп-сторм, либо идешь нахуй
Как это надоело.
>>78720
>Рисуем свою кнопку, поверх нее кладем прозрачный инпут, при выборе файла выводим яваскриптом имя
Как-то так?
Все оче плохо?
Давно уже.
Ах да, бэкенд-жуниор.
Если в студию сокол идешь - ничего не надо, если в приличную контору - не успеешь.
>Если в студию сокол идешь - ничего не надо
Других и нет у нас.
Ну энивей минимум-то надо какой-то. https://laravel.com/docs/5.7 хватит дрочнуть, чтобы писать интернет-магазинчики для наебизнесменов мухосрани?
>то чувство, когда в мухосранске только две вакансии на пхп-джуна и в одной из них прямым текстом пишут, что берут только студентов.
Го в дс, будем снимать одну комнатку на двоих :3
https://ideone.com/iDy18v
Вроде решил, но хуле в условии написано дописать строчку? Или я неправильно решил?
https://ideone.com/S8pq4n
Дайте, пожалуйста, совет, как можно попроще решить задачу с палиндромами, ибо я придумал только через костыли.
error_reporting(-1);
echo "Бросаем кубик...\n";
$random = mt_rand($1, $6);
echo "Выпало $random\n";
?>
Почему строчка с рандомом неправильная? хуле ему надо?
Нахуя нужно \n если можно поставить ; и писать с новой строчки?
В $mt_rand ты вместо простого интервала от 1 до 6 ссылаешься на переменные $1 и $6
bump
Вопрос запутанный. $_POST - это переменная в PHP (в которую данные попадают из тела HTTP POST-запроса). Ajax - это способ отправки запросов на сервер из JS-кода.
Поясни, о какой ситуации идет речь.
Я говорю, зачем мне отправлять серверу данные из формы через ajax, если их можно отправить сабмитом в указанный action. Дело только в отсутствии необходимости обновлять страницу?
https://2ch.hk/pr/res/1281608.html (М)
ПЕРЕКАТ
https://2ch.hk/pr/res/1281608.html (М)
ПЕРЕКАТ
https://2ch.hk/pr/res/1281608.html (М)
ПЕРЕКАТ
https://2ch.hk/pr/res/1281608.html (М)
А другие действия как то можно сократить?
Я тут не местный, самоучитель ОПа не открывал ни разу. Но если к этому моменту ты уже знаешь про циклы, то можно сократить. Получаешь список ключей массива, потом циклом проходишь по ним. Не нужно 100500 if.
Это копия, сохраненная 24 ноября 2018 года.
Скачать тред: только с превью, с превью и прикрепленными файлами.
Второй вариант может долго скачиваться. Файлы будут только в живых или недавно утонувших тредах. Подробнее
Если вам полезен архив М.Двача, пожертвуйте на оплату сервера.