Этого треда уже нет.
Это копия, сохраненная 5 декабря 2017 года.

Скачать тред: только с превью, с превью и прикрепленными файлами.
Второй вариант может долго скачиваться. Файлы будут только в живых или недавно утонувших тредах. Подробнее

Если вам полезен архив М.Двача, пожертвуйте на оплату сервера.
Клуб любителей изучать PHP/webdev 95 #1082507 В конец треда | Веб
Добро пожаловать. Тут мы изучаем язык PHP (а также JS/CSS/HTML/SQL), решаем задачки и даже делаем простые сайты! Зачем? Кто-то хочет сделать себе блог, кто-то приобрести новую профессию, кому-то просто нечего делать.

Пожалуйста, пишите один большой пост вместо нескольких маленьких и не флудите не по теме.

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

Предыдущий тред был тут: >>1067944 (OP) . Еще предыдущие треды ищутся в гугле по словам "клуб изучающих php" или в архиваче.

Мейлач лежит? Есть запасной тред на доброчане: /s/res/23225.xhtml#i46467

Что самое главное для программиста? Умение аккуратно оформлять код (как, написано во втором посте).

Правила: ведем себя воспитанно, помогаем новичкам, читаем учебники, решаем задачки, постим ссылки на решения, ОП их проверяет и дает советы и замечания. ОП заходит редко, где-то раз в 2-3 дня, у него мало времени, не жди его, решай задачки дальше. ОП отвечает на все вопросы по его задачкам и учебнику, а вот насчет каких-то других вещей - только если останется время. Но в треде немало анонимных экспертов разного уровня, так что вряд ли вопрос останется без ответа.

С чего начать

У нас есть свои уроки по основам PHP, они собраны и выложены по адресу http://archive-ipq-co.narod.ru/ Это учебник для изучающих с нуля, то есть если ты вообще ничего не знаешь, то можно начать с него. Он простой и понятный. Там есть задачи, их нужно решать (чтобы стать программистом, надо писать код — иначе никак). Пости ссылки на решения в тред, мы их проверим, напишем замечания и дадим советы по улучшению. С другой стороны, если этот учебник тебе не нравится, можно читать любой другой. Или официальный мануал. Или все сразу.

Устанавливать пока что ничего не требуется, разве что редактор кода вроде Sublime Text 3, Notepad++, Visual Studio Code, Netbeans PHP или PhpStorm (с ним будет удобнее).

Если не знаешь как решать, запости код, напиши в каком месте остановился и попроси подсказку.

Ты прошел весь учебник? Молодец, но это были лишь основы языка PHP, этого недостаточно. Вот что в идеале надо изучить еще: ООП, как работает веб-сервер, HTML/CSS, SQL, PDO, работа с таблицами в БД, работа с формами, MVC, git, composer, JS, фреймворки, автоматизированное тестирование.

Надо переходить к более серьезным задачкам, которые научат тебя всему этому.

- для начала прочти урок https://github.com/codedokode/pasta/blob/master/soft/web-server.md
- установи Апач + PHP (советы выше и ниже) и читай туториал http://php.net/manual/ru/tutorial.php
- Учи HTML/CSS и SQL, PDO, хотя бы основы
- Далее простая, но полезная задача сделать список студентов, в ней много полезных советов: https://github.com/codedokode/pasta/blob/master/student-list.md
- Более сложная задача сделать файлообменник на микрофреймворке Slim: https://gist.github.com/codedokode/9424217
- Еще более сложная и долгая задача на Yii/Symfony: https://gist.github.com/codedokode/8733007
- После нее можно изучать автоматизированное тестирование https://gist.github.com/codedokode/a455bde7d0748c0a351a
- Если ты все решил, переходи к Symfony 3/Doctrine 2
- Почитать про паттерны http://designpatternsphp.readthedocs.org/ru/latest/README.html (если ты не изучил ни одного фреймворка, то это будет рановато), тут с примерами кода http://designpatternsphp.readthedocs.org/ru/latest/README.html . Имей в виду что без примеров использования их учить бесполезно - не поймешь, хочешь увидеть примеры использования паттернов - ковыряй исходники Симфони, например Symfony Forms. Не заучивай паттерны - смотри код и думай, зачем тут они использованы.

Чтобы делать эти задания, тебе надо установить Апач + PHP (можно заодно сразу и MySQL) на компьютер. Вот полезные инструкции:

https://github.com/codedokode/pasta/blob/master/soft/php-install.md
https://github.com/codedokode/pasta/blob/master/soft/apache-install.md

Может тебе понадобится пользоваться командной строкой, вот гайд https://github.com/codedokode/pasta/blob/master/soft/cli.md

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

Также, у нас есть задачи которые позволят тебе изучить или подтянуть до нормального уровня знания JS/HTML/CSS/SQL. Решай их параллельно с задачами выше.

- HTML/CSS: https://github.com/codedokode/pasta/blob/master/html/html.md
- JS: https://gist.github.com/codedokode/ce30e7a036f18f416ae0
- SPA (сложно): https://github.com/codedokode/pasta/blob/master/js/spa.md
- Проверялка решений на JS: http://dkab.github.io/jasmine-tests/
- MySQL: https://github.com/codedokode/pasta/blob/master/db/databases.md

Что почитать

- Мануал по PHP — http://www.php.net/manual/ru/langref.php
- Сайт phptherightway (перевод на русский: http://getjump.me/ru-php-the-right-way/ )
- По PHP: Профессиональное программирование на PHP Джордж Шлосснейгл
- По PHP: Мэтт Зандстра — PHP: Объекты, шаблоны, методики программирования
- JS: learn.javascript.ru
- Про Git: https://git-scm.com/book/ru/v1

Оформляй код аккуратно!!! — например пропусти через phpformatter.com . Также, если ты пользуешься IDE вроде PhpStorm, Netbeans, Eclipse, то в них эта опция встроена, подробнее: https://gist.github.com/codedokode/8759492

У ОПа нет аккаунтов и групп вконтакте, в фейсбуке, в твиттере, все "пхп-треды" там поддельные.

Платиновые вопросы

- Почему PHP? Потому что вакансий море, и учить легко.
- Сайт опять упал!!!!! — Не паникуй, а открой http://rghost.ru/6bfCY9lfl и получи личную немного устаревшую оффлайновую копию сайта (можно читать хоть на андроиде без интернета)
- Что надо знать чтобы найти работу - разработчику: PHP, SQL, HTML/CSS, JS, ООП, Git, композер, MVC, фреймворк. Верстальщику - HTML/CSS, JS, jQuery. У нас в треде были люди, которые практически с нуля учились и смогли найти работу.
- Что будут спрашивать на собеседовании если 0 опыта - гонять по теории, по официальному мануалу PHP, давать дурацкие задачки на переворачивание строк, гонять по SQL (транзакции, внешние ключи, напиши запрос), по JS (как сделать анимацию при нажатии кнопки), ну погугли, не ленись
- Можно подробнее про поиск работы, собеседования - нет, ОП писать не будет, но может кто из анонов захочет рассказать. Поищите тред перезвонивших, а также раздел /wrk/
- Сколько времени надо изучать все это? - все зависит от тебя, но не меньше 6-8 месяцев
- Нужен ли ООП, фреймворки, MVC, git, composer? — Да, однозначно. Посмотри любую вакансию.
56 Кб, 500x644
Оформление кода #2 #1082509
Код нужно писать не как попало, а аккуратно и по правилам. Почему? Потому, что на неакуратно написанный код не хочется даже смотреть.

Если тебе лень выравнивать код руками, закачай его на 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
#3 #1082512
Напомню себе, что надо проверить студентов из поста >>1074848

https://github.com/Qevg/Student-list
Анон, с лопающейся головой #4 #1082534
Продублирую из последнего треда.
Попробовал осилить палиндром.
Вот только на ideone видимо открутили mb модуль.
Нашел альтернативу: http://phpfiddle.org/
Но без понятия как линковать оттуда код, поэтому линк бросаю на ideone:
https://ideone.com/hlU88a
Может кому-то не лень будет копипастнуть оттуда код.
#5 #1082537
>>1082534

Вообще список алтьтернатив написан маленькими буквами в учебнике внизу:

> Ideone не работает!11 Ну так открой Гугл и найди сайты вроде https://repl.it/languages/php , http://phptester.net/ , http://sandbox.onlinephpfunctions.com/ , http://codepad.org/ или http://www.runphponline.com/



Ищутся по словам "run php online".

Эх ... никто не читает примечания.

> Прохожусь циклом по каждому элементу массива и удаляю из него пробелы;


Через str_replace удалить их в исходной строке гораздо проще .

> Конвертирую полученную строку в массив;


Ты забыл флаг PREG_SPLIT_NO_EMPTY, без него в массив добавляется 2 пустых строки (проверь через var_dump)

Если ты писал комментарии для себя, то это ок, а вообще совсем очевидные вещи (вроде "нахожу половину длины строки") обычно не комментируют. Но если ты это писал для себя, чтобы запомнить, то проблем нет.

Переменную $n наверно проще вычислить из $i чем считать в цикле.

Переменную $k лучше было назвать понятнее, например, $errors.

После нахождения первого несовпадения из цикла можно выходить - какой смысл проверять дальше?

А так, алгоритм вроде верный.
#6 #1082539
>>1082537
Спасибо. Поработаю над твоими замечаниями. Отдельное спасибо за доп. задачи в предыдущем топике. Ну прям реально спасибо.
#7 #1082541
>>1080981

>Если ты знаешь ООП.


К сожалению, еще не начал изучать.

> Ей передается содержимое склада и название, и она возвращает товары с таким названием (попробуй дописать).



Вот: https://ideone.com/XhydTt#stdin. Правильно ли дописал? А то может я неправильно понял. Если правильно, то можно было как-то лучше? Спасибо.

> Мы можем выразить критерий поиска в виде анонимной функции, которая получает на вход товар и возвращает true или false в зависимости от того, соответствует товар условию поиска или нет.



И что будет если вернется true ? false ?

что будет если искать товар с параметром false?

Я обязательно сейчас буду пытаться понять, просто кусочек написал, чтобы разбираться потихоньку
#8 #1082543
Есть один Апач. В htdocs создал директорию example с сайтом и кинул туда htaccess:
RewriteEngine On
RewriteRule ^(.)$ /public/index.php?$1 [L, QSA]
А в паблик кинул такой:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.
) index.php?$1 [L,QSA]
Хочу редиректить все запросы к localhost/example/ на индекс, но что-то совсем не выходит. В чем может быть проблема? Гугли почти весь день, но что-то не выходит ничего.
#9 #1082554
>>1082541

Ответил тут >>1082551 (только дальше лучше отвечать в этом новом треде).

>>1082543

Во-первых, 2 файла создают путаницу и я сам не понимаю, как они будут работаь.

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

статья https://habrahabr.ru/company/sprinthost/blog/129560/
#10 #1082572
Привет, ещенедостаточноночной.

Суть такова, имеется csv файл с заменами для страницы, на странице размещаются ссылки вида сайт/страница/залупакентавра, и по каждой из ссылок сайт выдает страницу с заменами блоков из csv со строки с id залупакентавра. Строк в csv минимум десяток.

Собсна я уже джва дня не могу вкурить как это делается, подскажите куда копать. Да, я дно.

Типа по идее еще и апач нужно напрягать, чтобы он конвертировал ссылки.
#11 #1082594
Какой дружелюбный оп пост.
Знающие аноны, я начал изучать js, после хотел html/css.
Все это для работы в вебе.
Возможно я сделал неверный (джихат) выбор.
Прошу объяснить, почему и как правильнее начать?
Почему с php и только после него js.
#12 #1082606
>>1082594
Для начала надо разобраться зачем это все нужно и чего ты хочешь. Html/css для веба надо знать всем. А вот про языки - пхп это бек-енд, язык на котором бишут движок сайта. А жс это фронтенд, вот разберись с этим и учи что тебе интересней.
#13 #1082611
>>1082594
Ладно, даже если это толстота, скажу тем кто невинно это прочитал.
Значит так любой язык (даже HTML с XML) - Самостоятелен и не является выходящим из другого, а лишь может служить дополнением. Это значит, что язык можно учить любой и в любом порядке. Хочешь учи CSS без HTML, хочешь наоборот, хочешь вместе - Решай сам. Тут нянек НЕТ и если ты не можешь разобраться даже в таких простых вещах, то не то, что программирование, но и любое другое дело точно не для тебя и зря ты за него взялся. Так же в ОП посте есть замечательная картинка в которой есть упоминание о таком замечательном ресурсе как Google.
Так-же в ОП посте есть ссылки и на HTML с CSS и на JS и на всё, представляешь!? Там ВСЁ написано! Невероятно!
Вернемся к теме о самодостаточности языков для тех кто не умеет пользоваться мозгом:
Для начала определим, зачем нам нужен тот или иной язык программирования(Определение которого я не буду давать, уж слишком смешно), но чтобы это сделать, нам нужно узнать зачем тот или иной нужен - берем и заходим сюда https://www.google.ru/ и вбиваем в строку поиска: Языки программирования для веба. Нам выдает результаты Языки для веб-разработки и о чудо! Полный список определений веб-разработчиков! Например:
Backend | Front-end | Full-stack
Читаем, что мы узнали? Что есть веб-разработчики серверной части, графической части ЮИ и гибрида того и другого.
А что нужно каждому из этих трех видов разработчиков, кроме последнего, который должен знать все? Правильно! Свои языки, которыми они будут программировать.
Для фронта нужны языки, которыми он сможет манипулировать с графическим интерфейсом пользователя, а для того, чтобы узнать какие языки для этого подходят, берем и снова гуглим Front-end разработчик и там будет описано всё, что нужно. А вкратце три языка - HTML&CSS&JS, как думаешь, в каком порядке лучше учить?
Тоже самое делаем и со всем последующим, а именно вот тебе схемка:
Вопрос -> Гугл -> Решение.
Кстати когда я загуглил нашел следующее:
https://habrahabr.ru/post/12778/
https://geekbrains.ru/posts/road_to_web_development
https://habrahabr.ru/post/306716/
Неужели так сложно думать?
И задавайте вопрос максимально конкретно и развернуто, на ваши блякания врятли кто ответит и если вы думаете, что данный вопрос точно сложный и относится к вопросу тематики треда - ДОБРО ПОЖАЛОВАТЬ
#13 #1082611
>>1082594
Ладно, даже если это толстота, скажу тем кто невинно это прочитал.
Значит так любой язык (даже HTML с XML) - Самостоятелен и не является выходящим из другого, а лишь может служить дополнением. Это значит, что язык можно учить любой и в любом порядке. Хочешь учи CSS без HTML, хочешь наоборот, хочешь вместе - Решай сам. Тут нянек НЕТ и если ты не можешь разобраться даже в таких простых вещах, то не то, что программирование, но и любое другое дело точно не для тебя и зря ты за него взялся. Так же в ОП посте есть замечательная картинка в которой есть упоминание о таком замечательном ресурсе как Google.
Так-же в ОП посте есть ссылки и на HTML с CSS и на JS и на всё, представляешь!? Там ВСЁ написано! Невероятно!
Вернемся к теме о самодостаточности языков для тех кто не умеет пользоваться мозгом:
Для начала определим, зачем нам нужен тот или иной язык программирования(Определение которого я не буду давать, уж слишком смешно), но чтобы это сделать, нам нужно узнать зачем тот или иной нужен - берем и заходим сюда https://www.google.ru/ и вбиваем в строку поиска: Языки программирования для веба. Нам выдает результаты Языки для веб-разработки и о чудо! Полный список определений веб-разработчиков! Например:
Backend | Front-end | Full-stack
Читаем, что мы узнали? Что есть веб-разработчики серверной части, графической части ЮИ и гибрида того и другого.
А что нужно каждому из этих трех видов разработчиков, кроме последнего, который должен знать все? Правильно! Свои языки, которыми они будут программировать.
Для фронта нужны языки, которыми он сможет манипулировать с графическим интерфейсом пользователя, а для того, чтобы узнать какие языки для этого подходят, берем и снова гуглим Front-end разработчик и там будет описано всё, что нужно. А вкратце три языка - HTML&CSS&JS, как думаешь, в каком порядке лучше учить?
Тоже самое делаем и со всем последующим, а именно вот тебе схемка:
Вопрос -> Гугл -> Решение.
Кстати когда я загуглил нашел следующее:
https://habrahabr.ru/post/12778/
https://geekbrains.ru/posts/road_to_web_development
https://habrahabr.ru/post/306716/
Неужели так сложно думать?
И задавайте вопрос максимально конкретно и развернуто, на ваши блякания врятли кто ответит и если вы думаете, что данный вопрос точно сложный и относится к вопросу тематики треда - ДОБРО ПОЖАЛОВАТЬ
#14 #1082612
>>1082611
Спасибо за развернутый ответ, добрый человек.
Очень информативно.
Согласен, пишу херню вместо того чтобы разобраться.
Частично оправдаю это тем, что туп, ленив и последние две недели живу только на кофе (работа+курсачи)
Покурю по больше о бэк и фронте, решу что больше подходит и ближе к диплома начну спокойно изучать.
Добра тебе.
#15 #1082613
>>1082606
И тебе добра.
#16 #1082615
>>1082612
Это тебе спасибо, теперь у нас есть паста для платины.
#17 #1082616
>>1082612
Чел, ты сквозишь неуверенностью в себе. Не надо оправдываться, мы совершаем глупости для того, чтобы их не повторять после. Продуктивной работы тебе
#18 #1082620
>>1082616
Только ты не всегда можешь знать, когда ты глупость совершаешь.
#19 #1082633
>>1082611
Ну js точно имеет смысл учить только после html/css, а в остальном ты прав.
#20 #1082636
Анчоусы, как внутри устроены индексы в MySQL?
#21 #1082786
>>1082594
Без разницы, какой язык учить на начальном этапе. Это тоже самое, что выбирать учить английский или немецкий, если вообще не имеешь понятия, как разговаривать даже на родном.
#22 #1083048
>>1082554

>1) допиши код findItems, чтобы все это работало


У меня не получается сделать задание. Одни ошибки и null'ы. https://ideone.com/rh7w82 . Код переделывал пару раз достаточно сильно.

Лучше читать мануал тогда по функциям?
#23 #1083049
>>1083048
Сам себе отвечаю.

> лучше читать мануал по функциям



Лучше! Все иду читать.
#24 #1083064
>>1083048

Ошибка тут:

> if($checkWeightLessThan100){ //если вес меньше 100 то



Во-первых, у переменной тут неудачное название. Можно подумать, что сюда можно передать только функцию, которая проверяет, что вес меньше 100 - но на самом деле сюда можно передать любую функцию и назвать переменную лучше было бы "проверятель условия". Для таких функций-"проверятелей", что объект соответствует каким-то условиям, есть устоявшееся название - предикат ($predicate).

(вот пример вопроса на английском и видно, что там в ответах часто используется это слово: https://stackoverflow.com/questions/122105/what-is-the-best-way-to-filter-a-java-collection )

Во-вторых, ты не вызываешь функцию. Ты пишешь

if ($check...)

что значит "если переменная $check... не пуста". Разумеется, она не пустая - мы передали в нее функцию и if всегда срабатывает.

Тебе нужно вызвать функцию-предикат (и передать в нее товар для проверки), а для этого после имени переменной надо использовать круглые скобки:

$checkResult = $predicate($item);

> как можно вернуть сразу несколько значений в виде массива?


Нужно завести пустой массив. Внутри цикла, если товар соответствует условию, надо добавить товар в массив.
#25 #1083065
>>1083048

Что касается ошибки на ideone, ты там неправильно написал имя переменной.
Движок статистики на бекенде #26 #1083085
Анон, посоветуй опен-сорс движок статистики на сервер.

Надо трекать количество некоторых событий - суммарно, за выбранный период, с фильтрацией по каким-то ключам или без фильтрации. Как я это представляю: я из php отправляю движку некое событие в стату, он записывает это в какую-то (любую) базу, и где-то у него есть интерфейс, где все это можно посмотреть.
85 Кб, 950x750
#27 #1083163
Привет, аноны, начал решать простые задачи по по пхп, которые в шапке есть и тут уже с трудностями столкнулся.
На первом пике задача, которую надо доработать, чтобы, остаток по кредиту в минус не уходил. Попытался запилить проверку условием, только какого то хуя, она не проходит и начинает код сразу, после if выполнять, под спойлером код сам код тащемта

<?php

error_reporting(-1);

$creditBalance = 40000; / Долг анона перед банком /
$percent = 1.03; / Банк начисляет 3% в месяц от суммы /
$servicePayment = 1000; / А также 1000 рублей в месяц комиссии за обслуживание счета /
$monthlyPayment = 5000; / Анон платит 5000 р в месяц, это все, что ему дает мама на завтраки /
$paymentTotal = 0; / Сколько всего отдал банку анон /

/ Посчитаем расходы 20 раз на 20 месяцев вперед /
for ($month = 1; $month <= 20; $month ++) {
$creditBalance = ( $creditBalance * $percent ) + $servicePayment;
echo "{$creditBalance}\n";
if($creditBalanc < 5000) { $paymentTotal = $paymentTotal - $creditBalance;
$creditBalanc % $monthlyPayment;
echo "{$month} месяц спутя: долг = {$creditBalance} руб, выплачено всего {$paymentTotal} руб. \n";
echo "С меня хватит!\n";
break;
}
else {
$creditBalance = $creditBalance - $monthlyPayment;
$paymentTotal = $paymentTotal + $monthlyPayment;
echo "{$month} месяц спустя: долг = {$creditBalance} руб, выплачено всего {$paymentTotal} руб. \n";
}
}

Помогите разобраться, чому так выходит?
85 Кб, 950x750
#27 #1083163
Привет, аноны, начал решать простые задачи по по пхп, которые в шапке есть и тут уже с трудностями столкнулся.
На первом пике задача, которую надо доработать, чтобы, остаток по кредиту в минус не уходил. Попытался запилить проверку условием, только какого то хуя, она не проходит и начинает код сразу, после if выполнять, под спойлером код сам код тащемта

<?php

error_reporting(-1);

$creditBalance = 40000; / Долг анона перед банком /
$percent = 1.03; / Банк начисляет 3% в месяц от суммы /
$servicePayment = 1000; / А также 1000 рублей в месяц комиссии за обслуживание счета /
$monthlyPayment = 5000; / Анон платит 5000 р в месяц, это все, что ему дает мама на завтраки /
$paymentTotal = 0; / Сколько всего отдал банку анон /

/ Посчитаем расходы 20 раз на 20 месяцев вперед /
for ($month = 1; $month <= 20; $month ++) {
$creditBalance = ( $creditBalance * $percent ) + $servicePayment;
echo "{$creditBalance}\n";
if($creditBalanc < 5000) { $paymentTotal = $paymentTotal - $creditBalance;
$creditBalanc % $monthlyPayment;
echo "{$month} месяц спутя: долг = {$creditBalance} руб, выплачено всего {$paymentTotal} руб. \n";
echo "С меня хватит!\n";
break;
}
else {
$creditBalance = $creditBalance - $monthlyPayment;
$paymentTotal = $paymentTotal + $monthlyPayment;
echo "{$month} месяц спустя: долг = {$creditBalance} руб, выплачено всего {$paymentTotal} руб. \n";
}
}

Помогите разобраться, чому так выходит?
78 Кб, 970x506
#28 #1083164
Уебищно получилось вставить.
#29 #1083183
>>1083163
имена переменных посмотри. Не $creditBalanc,а $creditBalance
#30 #1083186
А все, решил, просто руки из жопы.
#31 #1083187
>>1083183
Да я там с именами накосячил, да и вообще весь цикл через жёпу сделал.
#32 #1083197
>>1083164

Выработай себе привычку вывод делать с помощью printf(), а не интерполяцией:

echo "{$month} месяц спустя: долг = {$creditBalance} руб, выплачено всего {$paymentTotal} руб. \n";

printf("%d месяц спустя: долг = %0.2f руб, выплачено всего %0.2f руб. \n", $month, $creditBalance, $paymentTotal);
#33 #1083207
>>1083085
Нашел piwik, кто-нибудь работал с ним?
#34 #1083214
кто-нибудь зарабатывает на своем сайте? расскажите плес а то жрать нечего
#35 #1083399
>>1083207

Я работал. Немножко странновато, но ваще кошерно
#36 #1083428
>>1083214
ставь жс майнер и гони туда траф, если уж совсем голодный, лал
#37 #1083451
>>1083428
интересная тема кстати но чет хз)0 ты пробовал?
#38 #1083537
Что то какая то фигня с установкой mysql на винду. Просит либу плюсов 2013 года, которая у меня уже стоит. Похоже придется ручками все ставить, надеюсь гайд в шапке еще актуальный.
#39 #1083552
Решаю задачу из темы регулярные выражения. Суть задачи. Найти правильный номер и привести в общий порядок его.

Решил проверить как приводить в общий порядок и столкнулся с кое-чем интересным. https://ideone.com/DF6Vkq
Я понимаю, что это типичная ошибка и даже вижу из-за чего из-за того что повторение {10} вне скобок, но почему-то (из-за моей криворукости 100%) все равно не исправляется. Спасибо! Сейчас еще покопаюсь, может ошибку найду, тогда сразу сюда напишу, чтобы не отвечали.
#40 #1083554
>>1083552
Я понял. Я дебил. Извините меня. лол
#41 #1083576
>>1083554
>>1083552
Так. Я вернулся сюда)) Я сделал, возрадуюсь сам себе и попрошу проверить на верность решения и говнокод( и как от него можно исправиться)

https://ideone.com/JkLWm0#stdin
#42 #1083880
Попытался сделать вывод постов как на этой борде:
http://sqlfiddle.com/#!9/3a12a/1
Посты идут группами - первый пост + до 3-х последних. Группы между собой сортируются по дате последнего поста в треде (в моём случае - по ID).
На таблице с тысячей постов запрос работает очень медленно, порядка нескольких секунд. Не понимаю как учитывать бамп-лимит. Можно подсказку?
#43 #1083919
Percona или MariaDB?

Ответ обоснуйте
#44 #1083935
>>1083880
Сори, но разве на каждый тред не создается своя таблица?
18 Кб, 810x372
#45 #1084074
^\W[+7|8]\W[0-9]\W[0-9]\W[0-9]\W[0-9]\W[0-9]\W[0-9]\W[0-9]\W[0-9]\W[0-9]\W[0-9]\W$

Вот моя регулярка на номера https://regex101.com/r/qF7vT8/3.

Eсли я обозначил в регулярном выражении поиск только цифр и любого символа, кроме букв, цифр и знака подчёркивания, то почему он воспринимает Люсю?
#46 #1084088
>>1084074

> ^\W[+7|8]\W[0-9]\W[0-9]\W[0-9]\W[0-9]\W[0-9]\W[0-9]\W[0-9]\W[0-9]\W[0-9]\W[0-9]\W$


unicode поставь, смертный
#47 #1084100
>>1084088

Да, странно, что на regex101 надо включать этот флаг явно.

Надо справа поставить флаги mgu вместо mg (m - чтобы ^ и $ применялись к каждой строке, а не ко всему тексту, g - чтобы он не останавливался на первом совпадении, а искал все).
#48 #1084116
>>1083919
Вопрос обоснуй.
#49 #1084135
Как делается сортировка товаров по популярности? Неужели отдельное поле создается типа views и апдейтится при каждом просмотре страницы товара?
#50 #1084149
>>1084135
да, именно так
31 Кб, 787x667
#51 #1084176
Почему оно берёт и 7 и +8, если в выражении явно указано, что или +7 или 8?
31 Кб, 788x675
#52 #1084179
Вот что не так? Где я неверно написал выражение?
#53 #1084216
>>1084176

Что, по твоему значат квадратные скобки? Ну вот например, в чем разница между abc и [abc]? Или a|b и [a|b] ?
#54 #1084218
sup,
есть динамическая таблица которая генерирует name = val1; name = val2; name = val3 ... к новым созданым ячейкам (это всё делается в цикле)
Теперь эту таблицу нужно передать в mysql.
как это правильно сделать?
Могу я это сделать через
for ($i = 0; $i < count($_POST['val']); $i++)
а потом $Val = $_POST['val'][$i]; ?
я сделал так, на при нажатии на сабмит, выдает пустую страницу пхп файла (т.е что-то пошло не так)
у первого элемента name = val1;
у элемента под ним (элемента новой созданой строки таблицы) name = val2; и тд
#55 #1084232
Пытаюсь решить задачку на рекурсию от ОПа, которую он в прошлом треде постил:

>1) Дан список категорий товаров в виде такого массива:



>$categories = [


>// id, название, parentId, кол-во товаров


>[1, 'Бытовая техника', null, 0],


>[2, 'Телевизоры', 1, 0],


>[3, 'LCD-телевизоры', 2, 20],


>[4, 'Телевизоры с газоразрядным дисплеем', 16],


>[5, 'Стиральные машины', 1, 0],


>[6, 'Холодильники', 1, 0],


>...


>];



>Для каждого товара указан уникальный id категории, >название, id родительской категории или null, если ее >нет, количество товаров в этой категории без учета >категорий-детей. Используя эти данные:



>а) Напиши функцию, которая для любого переданной >id категории вернет массив, содержащий id этой >категории и всех ее предков, начиная от корня >дерева.



>Например, для категории 3 вернет массив [1, 2, 3] >(Бытовая техника -> Телевизоры -> LCD-телевизоры). А >для 1 - массив [1].



>б) Напиши функцию, которая для любой категории >вернет массив id ее потомков. Например для id = 2 >функция должна вернуть массив [3, 4]



>в) Напиши функцию, которая вернет массив >категорий-сестер (то есть категорий, имеющих того >же родителя). Для id = 2 функция должна вернуть >массив [5, 6]



>г) Напиши функцию, которая выведет список >категорий в виде дерева "лесенкой", с указанием >числа товаров с учетом дочерних категорий:



>Бытовая техника (36)


>- Телевизоры (36)


>-- LCD-телевизоры (20)


>-- Телевизоры с газоразрядным дисплеем (16)


>Стиральные машины


>Холодильники



Блядский врот, в прошлом треде увидел это и весь день пытаюсь решить. А в итоге что? А в итоге я тупо и нихуя не могу, хоть уже и с опытом работы овер год. Причем рекурсивная поебень 1 раз всего нужна была в работе, и в итоге тупо стаковерфлоу помог. Не попадайтесь в мою ловушку кароче, не тратьте время на это.
#55 #1084232
Пытаюсь решить задачку на рекурсию от ОПа, которую он в прошлом треде постил:

>1) Дан список категорий товаров в виде такого массива:



>$categories = [


>// id, название, parentId, кол-во товаров


>[1, 'Бытовая техника', null, 0],


>[2, 'Телевизоры', 1, 0],


>[3, 'LCD-телевизоры', 2, 20],


>[4, 'Телевизоры с газоразрядным дисплеем', 16],


>[5, 'Стиральные машины', 1, 0],


>[6, 'Холодильники', 1, 0],


>...


>];



>Для каждого товара указан уникальный id категории, >название, id родительской категории или null, если ее >нет, количество товаров в этой категории без учета >категорий-детей. Используя эти данные:



>а) Напиши функцию, которая для любого переданной >id категории вернет массив, содержащий id этой >категории и всех ее предков, начиная от корня >дерева.



>Например, для категории 3 вернет массив [1, 2, 3] >(Бытовая техника -> Телевизоры -> LCD-телевизоры). А >для 1 - массив [1].



>б) Напиши функцию, которая для любой категории >вернет массив id ее потомков. Например для id = 2 >функция должна вернуть массив [3, 4]



>в) Напиши функцию, которая вернет массив >категорий-сестер (то есть категорий, имеющих того >же родителя). Для id = 2 функция должна вернуть >массив [5, 6]



>г) Напиши функцию, которая выведет список >категорий в виде дерева "лесенкой", с указанием >числа товаров с учетом дочерних категорий:



>Бытовая техника (36)


>- Телевизоры (36)


>-- LCD-телевизоры (20)


>-- Телевизоры с газоразрядным дисплеем (16)


>Стиральные машины


>Холодильники



Блядский врот, в прошлом треде увидел это и весь день пытаюсь решить. А в итоге что? А в итоге я тупо и нихуя не могу, хоть уже и с опытом работы овер год. Причем рекурсивная поебень 1 раз всего нужна была в работе, и в итоге тупо стаковерфлоу помог. Не попадайтесь в мою ловушку кароче, не тратьте время на это.
#56 #1084256
>>1084232
А как такое решать? Может кто-нибудь подскажет в каком направлении думать?
#57 #1084349
Может кто-нибудь на пальцах объяснить, как в yii делается разграничение прав на доступ к страницам для разных групп пользователей?
#58 #1084378
>>1084349
как сам захочешь, так и делается
28 Кб, 777x694
#59 #1084433
Вот. Теперь она правильная?
#60 #1084435
>>1084433
Да ты просто гуру регулярок.
#61 #1084467
>>1084433
Можно сократить однотипные действия с помощью вот таких скобок {} пример https://regex101.com/r/YhQOfK/1/
#62 #1084474
>>1084467
>>1084433
Можешь так заменить 10 цифр после +7 или 8.
Регулярка станет красивее и более читаема.
#63 #1084516
>>1084433

Ты копипастишь одно и то же много раз:

\W*[0-9]\W*[0-9]\W*[0-9]

Так дела не делаются. В регулярках есть специальные конструкции для указания, что выражение должно повторяться сколько-то раз, надеюсь ты их знаешь:

- +, *, ?, {N}, {N,M}

Пример:

abc+ соответствует словам abc, abcc, abccc, abccc

Если мы добавим круглые скобки, действие квантификатора + начнет распространяться не на последний символ, а на все содержимое скобок:

(abc)+ соответствует словам abc, abcabc, abcabcabc
(abc){3} соответствует слову abcabcabc

Используй эту возможность.

Также, ты используешь \W - но ведь это включает все знаки, вроде % или $, которые в номерах вряд ли встретятся. Лучше перечислить конкретные символы, которые допустимы между цифрами номера.
#64 #1084558
#65 #1084627
Как разбить строку на слова, пробелы убрать и все это добавить в массив?
#66 #1084632
>>1084627
Пример:

$text = "Кот собака кит дельфин";

Из этого получить массив с 4 элементами
#67 #1084657
ОП любезно набросал мне задачек в прошлом треде:
-----

1) Дан список товаров на складе вида (название, вес), например:

ром, 50 кг
сахар, 100 кг
ром, 35 кг
сахар, 20 кг
болты, 200 кг

Как видно, некоторые товары повторяются. Напиши программу, которая принимает на вход список товаров (в каком виде - придумай сам) и выводит сгруппированный по товарам список, для примера выше это будет:

ром, 85 кг
сахар, 120 кг
болты, 200 кг

-----

2) Дан текст, найди в нем слова, которые встречаются больше 1 раза. Текст может содержать слова на русском языке, пробелы между ними и знаки препинания. Пример текста: "Ехал Грека через реку, видит Грека - в реке рак." (повторяется слово "Грека").

-----

3) Дан текст, найди в нем слова, в которых идет 3 или более согласных подряд.

-----
Пилю результат:
1) https://ideone.com/RQ1WDk
2) https://repl.it/N2om/0
3) https://repl.it/NXrw/1
Еще опчик как-то издавна загадал запилить таблицу умножения столбиками:
https://ideone.com/Ez74yF
#67 #1084657
ОП любезно набросал мне задачек в прошлом треде:
-----

1) Дан список товаров на складе вида (название, вес), например:

ром, 50 кг
сахар, 100 кг
ром, 35 кг
сахар, 20 кг
болты, 200 кг

Как видно, некоторые товары повторяются. Напиши программу, которая принимает на вход список товаров (в каком виде - придумай сам) и выводит сгруппированный по товарам список, для примера выше это будет:

ром, 85 кг
сахар, 120 кг
болты, 200 кг

-----

2) Дан текст, найди в нем слова, которые встречаются больше 1 раза. Текст может содержать слова на русском языке, пробелы между ними и знаки препинания. Пример текста: "Ехал Грека через реку, видит Грека - в реке рак." (повторяется слово "Грека").

-----

3) Дан текст, найди в нем слова, в которых идет 3 или более согласных подряд.

-----
Пилю результат:
1) https://ideone.com/RQ1WDk
2) https://repl.it/N2om/0
3) https://repl.it/NXrw/1
Еще опчик как-то издавна загадал запилить таблицу умножения столбиками:
https://ideone.com/Ez74yF
#68 #1084677
>>1084632
возьми для этого более подходящий инструмент
https://ideone.com/DTIAHh
28 Кб, 995x411
#69 #1084686
>>1083576
Оптимизировал твой говнокод своим https://ideone.com/WXhdvc
мимовкатывальщик
#70 #1084687
>>1084677
Это конечно хорошее решение, но мое непонимание подсказывает мне, что это не PHP, да? Но спасибо все равно
#71 #1084689
>>1084686
Да. У тебя красивее и читабельнее получилось. Молодец!
#72 #1084698
>>1084632
Сделал. Но как быть, если пробелов больше одного? https://ideone.com/Wp6UjX
Регулярками не получается потому что косожопый наверное
#73 #1084699
>>1084632
Антош, ты как уроки от ОПа читаешь, там же было про енто:
$text = "Кот собака кит дельфин";
$regExp = '/\s+/';
$a = preg_split($regExp, $text, -1, PREG_SPLIT_NO_EMPTY);
var_dump( $a);
#74 #1084702
>>1084699
Спасибо большое! Извиняюсь за свою косожопость и слепоту.
29 Кб, 805x715
#75 #1084752
>>1084516
Как тогда указать, что скобки, пробелы и тире может идти между цифрами?

И оно так не работает.

Почему оно на флажки жалуется? https://ideone.com/npYxHz
Я выставил те, что были в regexpe101.
#76 #1084753
https://ideone.com/oxrw9f

Оно нормально массив выводит?
Что за единичные 8 и +7?
Это совпадения или косяк?
#78 #1084756
>>1084755
Почему на g ругается, а на остальные нет?
#79 #1084760
Я не понимаю, как убрать одиночные цифры и оставить только номер.
https://ideone.com/sTy16m
#80 #1084765
>>1084516
указание конкретных символов он не видит.
#81 #1084768
>>1084765

Что-то у тебя пока слабо со знанием конструкций, из которых составляется регулярное выражение.

(\s[+]-[(][)]) значит "1 пробел, за ним 1 плюс, за ним один минус, за ним одна скобка и еще одна скобка"
#82 #1084772
>>1084765

Еще дополню.

Вот примитивные конструкции, из которых составляются регулярные выражения:

- привязка к краям строки ^ и $
- привязка к краю слова: \b
- один конкретный символ: a
- один любой символ: .
- один символ из определенной группы: \s, \d, \w
- один любой символ из набора [1234a-f]
- один любой символ, кроме указанных [^abc]
- одно из выражений: (X|Y|Z)
- повторение выражения указанное число раз: вопрос, звездочка, плюс, {N,M} в сочетании с круглыми скобками

Разумеется, ты должен знать все указанные выше конструкции наизусть.

Мануал по ним есть тут, увы, не самым понятным языком написан http://php.net/manual/ru/pcre.pattern.php

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

Если тебе что-то непонятно, то я готов ответить на какой-то конкретный вопрос.

Тебе нужно написать "один из символов: +, -, скобки, пробел" и дописать повторение этого выражения 0 или более раз. А ты написал что эти символы должны идти в определенной последовательности и присутствовать все сразу.
#82 #1084772
>>1084765

Еще дополню.

Вот примитивные конструкции, из которых составляются регулярные выражения:

- привязка к краям строки ^ и $
- привязка к краю слова: \b
- один конкретный символ: a
- один любой символ: .
- один символ из определенной группы: \s, \d, \w
- один любой символ из набора [1234a-f]
- один любой символ, кроме указанных [^abc]
- одно из выражений: (X|Y|Z)
- повторение выражения указанное число раз: вопрос, звездочка, плюс, {N,M} в сочетании с круглыми скобками

Разумеется, ты должен знать все указанные выше конструкции наизусть.

Мануал по ним есть тут, увы, не самым понятным языком написан http://php.net/manual/ru/pcre.pattern.php

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

Если тебе что-то непонятно, то я готов ответить на какой-то конкретный вопрос.

Тебе нужно написать "один из символов: +, -, скобки, пробел" и дописать повторение этого выражения 0 или более раз. А ты написал что эти символы должны идти в определенной последовательности и присутствовать все сразу.
796 Кб, 1920x1080
#83 #1084776
Раз уж тут SQL тоже, то у меня как у нуба следующий вопрос: как на время запроса добавить значение какому-то полю?

Вот задание:

Создать хранимую процедуру для быстрого получения списка машин, имеющих среднюю оценку за тест-драйв ниже средней оценки за тест-драйв по классу sport-car плюс 1 балл. Отсортировать по марке.

Задание я сделал, но надо добавить 1 балл. Собственно, я даже не понял куда чё добавлять. Описание, блять, 10 приступов шизофрении из 10. Ебал рот того, кто писал эту непонятную хуйню.

Собственно, мне нужен не UPDATE, а как-то добавить к столбцу ball +1 значение на время запроса. То есть, нужно примерно так: были оценки "14, 15, 16", а нужно чтобы оценки стали "15, 16, 17". Как это сделать, может кто показать на примере? Пытался гуглить - чет нихуя не нашёл подобного.
Спасибо, няши.
#84 #1084777
>>1084776

>как на время запроса добавить значение какому-то столбцу


фикс
#85 #1084779
>>1084776

Ты мыслишь непраивльно. Не надо ничего менять в самой таблице. Надо внимательно читать задачу:

найти машины, у которых балл < (средний балл + 1)

Ничего в таблице менять не надо. Надо просто написать WHERE ball < average_ball + 1
#86 #1084787
>>1084657
В продолжение себя, Кредиты через функцию:
https://ideone.com/pQQE9g
#87 #1084794
>>1084779
Короче, вот моя процедура:

CREATE PROCEDURE get_cars_list
AS
SELECT g.car_name
FROM garage g
JOIN test_drive td ON g.id_car = td.id_test_drive
GROUP BY g.car_name
HAVING AVG(td.ball) < (SELECT AVG(td.ball) FROM test_drive td JOIN classes c ON td.id_test_drive = c.id_sportcar)
ORDER BY g.car_name
GO
EXEC get_cars_list
GO

Я пытался сделать так, как ты говоришь, но у меня начали повторяться поля из-за +1. Походу я тебя как-то не так понял или у меня где-то косяк. Покажи где что менять, если не трудно. Спасибо.
1,9 Мб, 1600x900
#88 #1084810
>>1084779
Спасиб большое, анон, без тебя бы я не разобрался. Няк!
Ещё хотел уточнить, если после "HAVING (подзапрос, который выведет '4') < (подзапрос, который выведет '5')" потом выбираются поля, то я всё правильно решил? Просто слишком дохуя полей, под 500+ тех, которые попадают под условие "4 < 5". Думаю, может подвох где-то. Алсо, если связываю с другой таблицей, то поля дублируются чому-то.
#89 #1084827
>>1084760
https://ideone.com/VMeAy6
Сравни со своим кодом и разберись где у тебя ошибки
39 Кб, 450x403
#90 #1085025
Всем привет.

У меня вопрос по Dependency injection. У автора есть замечательный урок https://github.com/codedokode/pasta/blob/master/arch/di.md, который я много раз перечитывал, пока не понял наконец суть.

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

Во всех библиотеках, которые я смотрел, классы, которым нужны зависимости, создают их внутри конструктора, т.е. используют hidden dependencies. Пример (я не для АПИ инсты пишу, просто эта библиотека вроде как должна быть хорошо написана, она ведь популярная!1): https://github.com/mgp25/Instagram-API/blob/master/src/Instagram.php

А это расходится с идеей о DI. И так во всех билиотеках, которые я видел. Где-то в лоб создаются классы в конструкторе, где-то это завуалировано типа StaticFactory::buildConstructorArgs, но никто их снаружи не передает.

Короче, вопрос: как правильно в случае с библиотекой передавать зависимости? Или если вы видели примеры либ, где реализовано иначе, просьба скинуть сюда.
34 Кб, 604x453
#91 #1085028
В догонку к предыдущему посту еще пример:
https://github.com/guzzle/guzzle/blob/master/src/Client.php строки 65 и 75. Ну в общем в любую библиотеку зайдите, там везде в конструкторе классы создаются.
#92 #1085029
>>1084232
Какой же я тупой, почти 2 дня решал задачку, и это только пункт a)
https://ideone.com/Zsjf1a
#93 #1085047
Какой файл для конфига лучше использовать json или php?
#94 #1085103
Аноны, у меня вот такой вопрос: как в SQL посчитать количество полей, связанных с каждым полем? Бля, хуево объяснил.
Короче, в задаче нужно посчитать количество работ по каждой группе. Каждая группа - это поле в столбце групп.

То есть, нужно посчитать количество выполненных работ по каждому полю. Допустим, столбец "Имя группы" имеет поле "АИБ-12", а количество выполненных группой работ "9". Или столбец имеет поле "АИБ-22", а количество выполненных группой работ "2". Как это сделать? Я примерно прикинул, понял что и где связать, но сука как мне вот это реализовать? Пытался сам допереть - так и не дошло.
#95 #1085109
>>1085103
Group by. Дальше гугли
#96 #1085127
>>1085109
А, то есть делаю связь, потом COUNT, потом GROUP BY столбец Группы, столбец Домашние работы? Сейчас попробую, спасибо. Не знал, что GROUP BY может даже такую хуйню вытворять в запросе.
#97 #1085218
sup, есть вопрос касательно редактирования файлов с пхп кодом.
Например, у меня есть аккаунт на хостинге, а на моём компьютере сервера нету (т.е и нету пхп), тогда мне нужно каждый раз для просмотра написаного в окне браузера закидать этот файл на хостинг, или может есть какое-то другое решение?
#98 #1085224
>>1085218
Phpstorm
#99 #1085225
>>1085218
есть решения, например настроить deployment в шторме, а на локальной машине держать копию файлов, которая будет заливаться на сервер при изменениях. но если ты задаешь такой вопрос, то лучше не заморачивайся, делай как сам описал.
#100 #1085229
>>1085225
>>1085224
phpstorm платный же, а с торрентов скачать не могу :С
Сам саблайн использую.
А что, иначе никак?

> на локальной машине держать копию файлов, которая будет заливаться на сервер при изменениях


а что, этот процесс можно как-то автоматизировать?
#101 #1085261
>>1083067

> \\W*?


В самом начале и в самом конце это можно не писать

> *?


Здесь вопрос работает не так, как ты думаешь. Квантификаторы (плюс, звездочка, {N} и тд) нельзя ставить друг после друга (только если взять часть выражения в круглые скобки). Знак вопроса здесь влияет на "жадность" звездочки - мануал http://php.net/manual/ru/regexp.reference.repetition.php

Если ты не знал про это, то лучше исправить.

В остальном верно.
SomeApprentice #102 #1085268
#103 #1085278
>>1085229
в шторме есть раздел deployment, там указываешь реквизиты доступа к серверу, дальше жмешь "download from server", он выкачивает весь сайт оттуда, и потом в deployment configuration ставишь "деплоить при сохранении. т.е. он при каждом сохранении локального файла будет его отгружать на сервер.

а как в саблайме сделать - хз. я думаю там наверняка плагины есть для деплоя.
#104 #1085281
>>1085278
я нашёл плагин sftp для сублайма, пока он устраивает
#105 #1085286
>>1085218

Это называется "деплой" (развертывание). Деплой может включать в себя не только копирование файлов, но например, какие-то преобразования (оптимизация картинок например).

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

Ищи решения для автоматизации деплоя. Я например в простых случаях пишу bash скрипт с вызовом rsync, который закачивает измененные файлы куда нужно.

Есть деплой через git - на сервере делается копия репозитория и делается пуш туда, срабатывает хук и выкладывает файлыиз репозитория куда требуется. Идеально для простых проектов.

Для более сложных случаев (деплой на несколько серверов, выполнение других действий) есть например ansible (требует ssh-доступ).

Если тебе не нравятся скрипты для командной строки, то можно попробовать поискать какие-то GUI-программы, но я не уверен, что они существуют и что они удобные. Что это за программист, который не может автоматизировать свою работу через bash скрипт? Гайд по командной строке ждет тебя в ОП-посте.

Алсо погуглил за тебя:

- https://habrahabr.ru/post/211733/ (рекомендую и другим анонам почитать комментарии). Вот например человек из Badoo пишет про деплой: https://habrahabr.ru/post/211733/#comment_7287769
- https://www.google.ru/search?q=деплой+файлов+на+сервер&newwindow=1&dcr=0&gbv=1&sei=tur4WcaHLYjB6QT09pH4Dg

Если ты все равно хочешь править код на продакшене, и быть неквалифицированным кодером, то тут есть варианты:

- зайти на сервер по ssh и редактирвоать код на сервере консольным редактором
- подмонтировать папку с сервера по WebDAV/sftp/samba (нужны админские навыки) как внешний диск
- использовать редактор или плагин для синхронизации файлов

>>1085047

json имеет преимущество в том, что его можно читать и из других языков программирования. PHP мощнее и позволяет добавлять комментарии.

Также есть еще ini (есть функция чтения ini в PHP), XML, YAML и dotEnv.
#105 #1085286
>>1085218

Это называется "деплой" (развертывание). Деплой может включать в себя не только копирование файлов, но например, какие-то преобразования (оптимизация картинок например).

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

Ищи решения для автоматизации деплоя. Я например в простых случаях пишу bash скрипт с вызовом rsync, который закачивает измененные файлы куда нужно.

Есть деплой через git - на сервере делается копия репозитория и делается пуш туда, срабатывает хук и выкладывает файлыиз репозитория куда требуется. Идеально для простых проектов.

Для более сложных случаев (деплой на несколько серверов, выполнение других действий) есть например ansible (требует ssh-доступ).

Если тебе не нравятся скрипты для командной строки, то можно попробовать поискать какие-то GUI-программы, но я не уверен, что они существуют и что они удобные. Что это за программист, который не может автоматизировать свою работу через bash скрипт? Гайд по командной строке ждет тебя в ОП-посте.

Алсо погуглил за тебя:

- https://habrahabr.ru/post/211733/ (рекомендую и другим анонам почитать комментарии). Вот например человек из Badoo пишет про деплой: https://habrahabr.ru/post/211733/#comment_7287769
- https://www.google.ru/search?q=деплой+файлов+на+сервер&newwindow=1&dcr=0&gbv=1&sei=tur4WcaHLYjB6QT09pH4Dg

Если ты все равно хочешь править код на продакшене, и быть неквалифицированным кодером, то тут есть варианты:

- зайти на сервер по ssh и редактирвоать код на сервере консольным редактором
- подмонтировать папку с сервера по WebDAV/sftp/samba (нужны админские навыки) как внешний диск
- использовать редактор или плагин для синхронизации файлов

>>1085047

json имеет преимущество в том, что его можно читать и из других языков программирования. PHP мощнее и позволяет добавлять комментарии.

Также есть еще ini (есть функция чтения ini в PHP), XML, YAML и dotEnv.
#106 #1085287
>>1085025

> Сейчас пишу библиотеку для композера для работы с АПИ одним, и чем больше функционал, тем больше получается зависимостей.


Странно. Мне кажется, для работы с HTTP АПИ зависимость должна быть одна - HTTP-клиент (в идеале какой-нибудь PSR-интерфейс, а не конкретная библиотека).

> Но проблема в том, что это не MVC-приложение и что там как таковой контроллер - это не тот контроллер, который ты делаешь, а его пишет пользователь по твоим примерам.


А зачем там контроллер и вообще MVC?

> Пользователь делает очень простые штуки типа "передать логин и пароль от сайта, создать сущность, отправить сущность на сайт"


Для этого не нужно MVC. Смотри, как это красиво делается в ООП:

$apiClient = new MegaApiClient(зависимости, логин, пароль);

$entity = new SomeEntity();
$entity->setName('Иван');
$apiClient->createEntity($entity);

> я не для АПИ инсты пишу, просто эта библиотека вроде как должна быть хорошо написана, она ведь популярная


> Instagram's Private API


Не думаю, что она "хорошо" написана, если использует недокументированное АПИ.

> IMPORTANT: We do NOT throw any exception here for users who are


> // running the library via a webpage. Many webservers are configured


> // to hide all PHP errors, and would just give the user a totally


> // blank webpage with "Error 500"


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

Что касается DI:

> $this->account = new Request\Account($this);


Это "композиция" ( https://ru.wikipedia.org/wiki/Агрегирование_(программирование) ) - объект API содержит в себе под-объекты, которые независимо от него не используются. Логично потому их создавать в конструкторе. Подменить их на другие объекты нельзя, так как они по сути являются неотъемлемой частью текущего класса.

> $this->settings = Settings\Factory::createHandler(


> $this->client = new Client($this);


А вот это зависимости и тут стоило бы использовать DI.

Вообще, в библиотеках можно увидеть такие решения, как шаблон проектирования "фасад":

- http://dron.by/post/pattern-proektirovaniya-fasad-facade-na-php.html
- http://designpatternsphp.readthedocs.io/ru/latest/Structural/Facade/README.html (как всегда, бредовый код в примере)
- http://www.javenue.info/post/4

Что-то похожее есть в Доктрине: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/tutorials/getting-started.html#obtaining-the-entitymanager (смотри вызов Setup::createAnnotationMetadataConfiguration и EntityManager::create).

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

Паттерны Facade и Builder никак не мешают использованию DI и созданию нужных объектов вручную.

Библиотеки конечно могут не следовать принципу DI - но причины надо спрашивать у их авторов. Может в этом есть какая-то выгода? Ну не знаю, когда есть DI, например, можно сделать логгирование всех HTTP запросов, а без DI?

> Пример библиотек с DI



Вот:

- https://github.com/google/google-api-php-client (старенькая, но с DI)
- https://github.com/doctrine/doctrine2

>>1085028

Так-то да, handler - это по идее зависимость, но тут просто при отсутствии конфига она подбирается автоматически. Но опять же, никто не запрещает ее передать явно.
#106 #1085287
>>1085025

> Сейчас пишу библиотеку для композера для работы с АПИ одним, и чем больше функционал, тем больше получается зависимостей.


Странно. Мне кажется, для работы с HTTP АПИ зависимость должна быть одна - HTTP-клиент (в идеале какой-нибудь PSR-интерфейс, а не конкретная библиотека).

> Но проблема в том, что это не MVC-приложение и что там как таковой контроллер - это не тот контроллер, который ты делаешь, а его пишет пользователь по твоим примерам.


А зачем там контроллер и вообще MVC?

> Пользователь делает очень простые штуки типа "передать логин и пароль от сайта, создать сущность, отправить сущность на сайт"


Для этого не нужно MVC. Смотри, как это красиво делается в ООП:

$apiClient = new MegaApiClient(зависимости, логин, пароль);

$entity = new SomeEntity();
$entity->setName('Иван');
$apiClient->createEntity($entity);

> я не для АПИ инсты пишу, просто эта библиотека вроде как должна быть хорошо написана, она ведь популярная


> Instagram's Private API


Не думаю, что она "хорошо" написана, если использует недокументированное АПИ.

> IMPORTANT: We do NOT throw any exception here for users who are


> // running the library via a webpage. Many webservers are configured


> // to hide all PHP errors, and would just give the user a totally


> // blank webpage with "Error 500"


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

Что касается DI:

> $this->account = new Request\Account($this);


Это "композиция" ( https://ru.wikipedia.org/wiki/Агрегирование_(программирование) ) - объект API содержит в себе под-объекты, которые независимо от него не используются. Логично потому их создавать в конструкторе. Подменить их на другие объекты нельзя, так как они по сути являются неотъемлемой частью текущего класса.

> $this->settings = Settings\Factory::createHandler(


> $this->client = new Client($this);


А вот это зависимости и тут стоило бы использовать DI.

Вообще, в библиотеках можно увидеть такие решения, как шаблон проектирования "фасад":

- http://dron.by/post/pattern-proektirovaniya-fasad-facade-na-php.html
- http://designpatternsphp.readthedocs.io/ru/latest/Structural/Facade/README.html (как всегда, бредовый код в примере)
- http://www.javenue.info/post/4

Что-то похожее есть в Доктрине: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/tutorials/getting-started.html#obtaining-the-entitymanager (смотри вызов Setup::createAnnotationMetadataConfiguration и EntityManager::create).

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

Паттерны Facade и Builder никак не мешают использованию DI и созданию нужных объектов вручную.

Библиотеки конечно могут не следовать принципу DI - но причины надо спрашивать у их авторов. Может в этом есть какая-то выгода? Ну не знаю, когда есть DI, например, можно сделать логгирование всех HTTP запросов, а без DI?

> Пример библиотек с DI



Вот:

- https://github.com/google/google-api-php-client (старенькая, но с DI)
- https://github.com/doctrine/doctrine2

>>1085028

Так-то да, handler - это по идее зависимость, но тут просто при отсутствии конфига она подбирается автоматически. Но опять же, никто не запрещает ее передать явно.
#107 #1085294
>>1085025

>Пользователь делает очень простые штуки типа "передать логин и пароль от сайта, создать сущность, отправить сущность на сайт". И предлагать ему туда в этот контроллер передавать зависимости, о которых он вообще ничего не должен знать, - как-то не комильфо.



Передавай туда уже созданный и настроенный объект для работы с API.
58 Кб, 982x679
#108 #1085322
Вопросы по апачу. Я его распаковал, запустил. Больше ничего не устанавливал, так как запустился, хотя написано в гайде это: "На сайте apachelounge написано, а ты не прочел, что надо установить дополнительно библиотеку Visual C++ Redistributable for Visual Studio (не саму Visual Studio) с сайта майкрософт. Вернись и найди ссылку". Стоит ли качать, если ошибки никакой не было при запуске?

Зашел в распакованные файлы и открыл по адресу ../Apache24/bin/ApacheMonitor.exe
Запустилось. Но не работает. Я как понимаю, ничего мне качать дополнительно не нужно, а просто настроить конфиг?
#109 #1085328
>>1085322
Я установил Visual C++ Redistributable for Visual Studio(рис 1). Вот как выглядел распакованный апач на диске D(рис 2). Но так как в readme(рис 3) написана директория, то я заново распаковал, но уже на диск C:(рис 4), но все также запускается и не работает. По ссылке http://localhost/
ничего не отображается(Не удается получить доступ к сайту
Сайт localhost не позволяет установить соединение.)
#110 #1085330
>>1085328
Также пишет no service installed я прописал httpd.exe -k install
#111 #1085331
>>1085330
Также пишет no service installed я прописал httpd.exe -k install но все равно не работает*. Я исправил прошлый пост.

Это запуск был через ApacheMonitor.exe

Но сейчас запустил через httpd.exe и все заработало: мне написало It works. Тогда почему же через монитор не работает и пишет no service installed ?

Очень сильно извиняюсь за спам. Я не хотел наспамить.
28 Кб, 1200x630
#112 #1085363
Привет, котоны. Настраиваю веб-сервер на centos 6.9, нужно установить phpmyadmin, который работал бы под php7. Как это сделать? В репозиториях epel и remi такого нет.
#113 #1085375
>>1085363
А, все, разобрался.
#114 #1085380
>>1085375
Теперь у меня другая проблема. Залил свой проект Laravel на сервер под апачем, главную страницу в браузере видно, но при переходе по ссылкам такая ерунда:
The requested URL /catalog was not found on this server.
Что делать чтобы это исправить?
#115 #1085404
>>1085380
Ладно, с этим тоже сам разобрался.
#116 #1085430
>>1085404
Если будут проблемы, то еще обращайся!
#117 #1085432
>>1082507 (OP)
Пацаны, помогите, я сейчас на стенку полезу. Сделал запись с помощью php функции shmop, в разделяемую память, попытался считать её с С++, и вместо передоваемой переменной получил какоето большое десятичное число. Как это пофиксить?
#118 #1085440
Блять, бесполезные уёбки, какую кодировку использует php по умолчанию?
#119 #1085457
>>1085440
По умолчанию использую твою сестру, про кодировку не знаю нихуя.
#120 #1085472
>>1085457
У меня нет сестры, ты даже этого не знаешь.
#121 #1085513
>>1085287

Спасибо! Копаю библиотеку Доктрины. Моей ошибкой было думать, что зависимость - это любой посторонний класс.

> А зачем там контроллер и вообще MVC?


Он не нужен, я имел в виду, что в случае с MVC я примерно понимал, как реализуется DI, а в случае с библиотекой - нет.

> Смотри, как это красиво делается в ООП:


У меня сейчас примерно так получается:
$credentials = new CredentialsManager(login, password);

$settings = new Settings(); // создаем, только если надо что-то поменять
$settings->setOptionalSetting('true');

$client = new Client($credentials, $settings);
...

А если не создавать Settings и не менять там настройки, то Client создастся с настройками по умолчанию:

class Client
{
private $settings;
public function __construct(CredentialsManager $credentials, Settings $settings = null)
{
$this->settings = isset($settings) ?? new Settings();
}
}

Но это получается и не DI, и не Builder.
Такое вообще корректно? Не засмеют при приеме на работу меня, когда я им покажу такой код в кач-ве портфолио?
#121 #1085513
>>1085287

Спасибо! Копаю библиотеку Доктрины. Моей ошибкой было думать, что зависимость - это любой посторонний класс.

> А зачем там контроллер и вообще MVC?


Он не нужен, я имел в виду, что в случае с MVC я примерно понимал, как реализуется DI, а в случае с библиотекой - нет.

> Смотри, как это красиво делается в ООП:


У меня сейчас примерно так получается:
$credentials = new CredentialsManager(login, password);

$settings = new Settings(); // создаем, только если надо что-то поменять
$settings->setOptionalSetting('true');

$client = new Client($credentials, $settings);
...

А если не создавать Settings и не менять там настройки, то Client создастся с настройками по умолчанию:

class Client
{
private $settings;
public function __construct(CredentialsManager $credentials, Settings $settings = null)
{
$this->settings = isset($settings) ?? new Settings();
}
}

Но это получается и не DI, и не Builder.
Такое вообще корректно? Не засмеют при приеме на работу меня, когда я им покажу такой код в кач-ве портфолио?
#122 #1085520
Yii.
Как воспользоваться во вью результатом поиска по связанным страницам?
Есть таблица flight с полем id. И таблица photo с полями id, n_flight. К одному id таблицы flight могут относится несколько одинаковых n_flight.
В модели:
public function getPhoto() {
return $this->hasMany(Photo::className(), ['n_flight' => 'id']);
}
В контроллере:
$query = "SELECT * FROM flight WHERE data_vyezda between :date1 and :date2";
$listFlight = flight::findBySql($query, [':date1' => $date1, ':date2' => $date2])->with('photo')->asArray()->all();
return $this->render('manager', compact('model', 'listFlight'));
Во вью:
echo count($listFlight->photo);

И в результате выводит "0", хотя там их больше нуля. Если распечатать $listFlight, то там будут в том числе и данные из связанных страниц. Но как ими воспользоваться?
#123 #1085527
>>1085440
Которая указана в default_charset php.ini
#124 #1085546
>>1085527
Спасибо
#125 #1085556
Дилемма: есть несколько родственных сущностей (есть одинаковые свойства, но есть и уникальные свойства) и тут встает вопрос хранения в БД всего этого добра.
Либо заводить под каждую сущность отдельную таблицу (в итоге их будет 4) либо хранить в одной таблице, но поля которые уникальные для некоторых сущностей делать по умолчанию NULL. Из плюсов - если что-то поменяется в сущностях - достаточно задействовать существующее уже поле, из минусов: при поиске и выборках всегда придется джоинить эту таблицу на ту (категории) в которой хранится тип сущности (одной категории может соответствовать несколько сущностей). Общая таблица - будет по размеру как 4 таблицы каждой сущности - соответственно поиск будет медленее чем по 4 отдельным таблицам.
Алсо, всё это на Yii2, поэтому тут оба варианта реализуются легко, просто в варианте где общая таблица - опишу для каждой модели сущности свои уникальные правила.

На данный момент если я вместо одной таблицы - заведу 4, это будет малая кровь, так как пока ещё нет реальных данных, но через месяц - придется уже делать помимо изменения структуры ещё и миграцию.
26 Кб, 1220x221
#126 #1085559
Алсо, пикрелейтед - если хранить всё в одной таблице
#127 #1085565
>>1085559
>>1085556
Наверное всё же нормализую данные и заведу 4 таблицы, будет потом путаница если в одной, плюс жирнющие индексы
#128 #1085612
>>1085331
Добавлю к еще одной проблеме. Скрипт не отображается. Запускал через httpd.exe( он пишет кстати в консоли AH00558: httpd.exe: Could not reliably determine the server's fully qualified domain name Set the 'ServerName' directive globally to suppress this message
#129 #1085657
>>1085612

Скрипт не выполняется, так как в конфиг Апача не прописано, что надо выполнять PHP скрипты с помощью модуля mod_php.

Тебе надо прописать в конфиге Апача директивы LoadModule и SetHandler как описано тут: http://php.net/manual/ru/install.unix.apache2.php (тебе нужно только то, что касается этих директив, остальное не нужно).

> ould not reliably determine the server's fully qualified domain name Set the 'ServerName' directive globally to suppress this message


Ну тут же написано, какую директиву надо прописать (ServerName), чтобы убрать предупреждение. Документацию по ней можно найти на офоциальном сайте Апача на англ.

>>1085556

Это называется наследование таблиц. Тут есть 3 стандартных паттерна: Class TI, Concrete TI, STI: https://www.google.ru/search?q=паттерны+наследования+таблиц&btnG=Поиск&newwindow=1&dcr=0&gbv=1

Однозначного ответа, что лучше, нету. Я бы позаботился о том, чтбы работали внешние ключи.

Также есть еще подход EAV (Entity-Attribute-Value) для случаев, когда есть много необязательных атрибутов (вроде свойств разных товаров или объявлений).

> Общая таблица - будет по размеру как 4 таблицы каждой сущности - соответственно поиск будет медленее чем по 4 отдельным таблицам.


Это если нет индексов.

>>1085520

Ты прочел документацию по моделям в Юи и по настройке связей (отношений) между ними?

Алсо, поле this->photo вообще существует и доступно ли снаружи?

>>1085513

Зачем CredentialsManager? Там что-то сложное? Я бы просто их передавал напрямую в конструктор. Также, настройки - они точно нужны? Не проще ли в отдельных функциях сделать дополнительный аргумент?

> isset($settings) ?? new Settings();


Это неправильное использование ??

> Но это получается и не DI, и не Builder.


Странно что у тебя HTTP клиент не является зависимостью.
#129 #1085657
>>1085612

Скрипт не выполняется, так как в конфиг Апача не прописано, что надо выполнять PHP скрипты с помощью модуля mod_php.

Тебе надо прописать в конфиге Апача директивы LoadModule и SetHandler как описано тут: http://php.net/manual/ru/install.unix.apache2.php (тебе нужно только то, что касается этих директив, остальное не нужно).

> ould not reliably determine the server's fully qualified domain name Set the 'ServerName' directive globally to suppress this message


Ну тут же написано, какую директиву надо прописать (ServerName), чтобы убрать предупреждение. Документацию по ней можно найти на офоциальном сайте Апача на англ.

>>1085556

Это называется наследование таблиц. Тут есть 3 стандартных паттерна: Class TI, Concrete TI, STI: https://www.google.ru/search?q=паттерны+наследования+таблиц&btnG=Поиск&newwindow=1&dcr=0&gbv=1

Однозначного ответа, что лучше, нету. Я бы позаботился о том, чтбы работали внешние ключи.

Также есть еще подход EAV (Entity-Attribute-Value) для случаев, когда есть много необязательных атрибутов (вроде свойств разных товаров или объявлений).

> Общая таблица - будет по размеру как 4 таблицы каждой сущности - соответственно поиск будет медленее чем по 4 отдельным таблицам.


Это если нет индексов.

>>1085520

Ты прочел документацию по моделям в Юи и по настройке связей (отношений) между ними?

Алсо, поле this->photo вообще существует и доступно ли снаружи?

>>1085513

Зачем CredentialsManager? Там что-то сложное? Я бы просто их передавал напрямую в конструктор. Также, настройки - они точно нужны? Не проще ли в отдельных функциях сделать дополнительный аргумент?

> isset($settings) ?? new Settings();


Это неправильное использование ??

> Но это получается и не DI, и не Builder.


Странно что у тебя HTTP клиент не является зависимостью.
#130 #1085658
>>1085432

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

>>1085363

Его можно вручную скачать, создать виртуальный хост и установить.

>>1085322

Если все работает, то ставить VC++ Redist не требуется.

> Зашел в распакованные файлы и открыл по адресу ../Apache24/bin/ApacheMonitor.exe


Это не сам Апач, а программа для управления им (остановка/запуск). Если Апач установить как сервис (службу, то есть программу, работающую в фоновом режиме), и если у ApacheMonitor есть достаточно прав, то он может управлять запуском/остановкой Апача. Более того, можно будет сделать автозапуск службы Апача. Но это все можно делать и без монитора, в стандартной программе для управления службами, которая встроена в Windows (services.msc).

Также, можно не устанавливать Апач как службу, а просто запускать вручную из консоли.

> Запустилось. Но не работает


На скриншоте я вижу, что никакого сервиса там нет.

> Также пишет no service installed я прописал httpd.exe -k install


Эта команда сработала успешно? Ей нужны права администратора, чтобы добавить Апач в список служб Windows.

> Но сейчас запустил через httpd.exe и все заработало: мне написало It works.


Так и дложно быть. Ты просто запусакешь веб-сервер вручную.

> Тогда почему же через монитор не работает и пишет no service installed ?


Потому что служба не установлена. Открой services.msc (пуск -> выполнить) и проверь, что там нет Апача.
#130 #1085658
>>1085432

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

>>1085363

Его можно вручную скачать, создать виртуальный хост и установить.

>>1085322

Если все работает, то ставить VC++ Redist не требуется.

> Зашел в распакованные файлы и открыл по адресу ../Apache24/bin/ApacheMonitor.exe


Это не сам Апач, а программа для управления им (остановка/запуск). Если Апач установить как сервис (службу, то есть программу, работающую в фоновом режиме), и если у ApacheMonitor есть достаточно прав, то он может управлять запуском/остановкой Апача. Более того, можно будет сделать автозапуск службы Апача. Но это все можно делать и без монитора, в стандартной программе для управления службами, которая встроена в Windows (services.msc).

Также, можно не устанавливать Апач как службу, а просто запускать вручную из консоли.

> Запустилось. Но не работает


На скриншоте я вижу, что никакого сервиса там нет.

> Также пишет no service installed я прописал httpd.exe -k install


Эта команда сработала успешно? Ей нужны права администратора, чтобы добавить Апач в список служб Windows.

> Но сейчас запустил через httpd.exe и все заработало: мне написало It works.


Так и дложно быть. Ты просто запусакешь веб-сервер вручную.

> Тогда почему же через монитор не работает и пишет no service installed ?


Потому что служба не установлена. Открой services.msc (пуск -> выполнить) и проверь, что там нет Апача.
#131 #1085690
>>1085657

> Зачем CredentialsManager? Там что-то сложное?


Там будут еще пароли от БД. А пока он собирает валидирует данные и, в принципе, все. Так-то уже не знаю, может правда уберу его.

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

> Это неправильное использование ??


Сорри, $settings ?? new Settings() конечно же

> Странно что у тебя HTTP клиент не является зависимостью


Да, буду его через аргумент конструктора передавать. Это недоработочка
#132 #1085749
Парни, вот такая тема, недавно начал изучать, некоторые задачи вообще не представляю как делать, ну т.е. вообще полный 0. Понимание придёт с практикой? Нужно больше задач решать? Или как тут быть? Может почитать чего?
#133 #1085756
И еще вдогонку есть ООП, есть классы, свойства, методы, объекты, наследование и т.п. Я не понимаю как писать код на нём, если без ООП я могу что-то написать, то ООП это вообще как дремучий лес, что делать?
#134 #1085771
>>1085749
не ссы, все придет. главное - изучать хорошие материалы (сайт ОПа, например) и писать много кода.

не забегай вперед, не старайся сразу все изучить.
#136 #1085789
>>1085029

null не надо добавлять в массив, так как это не категория.

Поиск категории по id я бы рекомендовал сделать отдельной функцией - она еще пригодится.

> if ($goods[0] == $id) {


Это очень неудачный код, так как глядя на эту строчку, не понять, что значит $goods[0] ? Первый товар в списке товаров? Лучше было бы $category['id'] == $id.

В твоем коде никак не обрабатывается ситуация, когда передан неверный id категории - надо либо сообщать об ошибке, либо возвращать пустой массив.

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

>>1084810

> Алсо, если связываю с другой таблицей, то поля дублируются чому-то.


Почему бы не начать с теории и с изучения джойнов?

> Ещё хотел уточнить, если после "HAVING (подзапрос, который выведет '4') < (подзапрос, который выведет '5')" потом выбираются поля, то я всё правильно решил?


Скорее всего нет, так как 2 позапроса в HAVING это странно.

>>1084787

Почему надписи в echo транслитом? Кириллица должна по идее работать. Или у тебя что-то не работает? Неудобно читать.

Имена переменных тоже не стоит называть транслитом.

Также, ты неудачно выбрал тип возвращаемых данных. Давай посмотрим на твою функцию, что она получает на вход и что дает на выходе:

- на вход - получает параметры кредита в виде чисел
- на выходе - выдает текстовую строку

Как дальше работать с этой строкой? Как например найти самый выгодный кредит?

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

Также, в коде я вижу еще одну проблему:

for (...) {
if (...) {
$result = "Vsego bilo viplacheno ...";
}
}

return $result;

Тут видно, что переменная $result создается только если цикл выполнится хотя бы раз, и если if сработает, а что, если нет? Будет попытка вернуть значение несуществующей переменной. Это неправильно. Ты пишешь код, который так и просит сделать в нем ошибку. Лучше было сделать return "Vsego bilo..." и тогда проблемы бы не было.

То есть вот такой ерунды не должно быть:

if (...) {
$x = 100;
}

return $x;

так как здесь нет гарантий что переменная $x будет создана.
#136 #1085789
>>1085029

null не надо добавлять в массив, так как это не категория.

Поиск категории по id я бы рекомендовал сделать отдельной функцией - она еще пригодится.

> if ($goods[0] == $id) {


Это очень неудачный код, так как глядя на эту строчку, не понять, что значит $goods[0] ? Первый товар в списке товаров? Лучше было бы $category['id'] == $id.

В твоем коде никак не обрабатывается ситуация, когда передан неверный id категории - надо либо сообщать об ошибке, либо возвращать пустой массив.

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

>>1084810

> Алсо, если связываю с другой таблицей, то поля дублируются чому-то.


Почему бы не начать с теории и с изучения джойнов?

> Ещё хотел уточнить, если после "HAVING (подзапрос, который выведет '4') < (подзапрос, который выведет '5')" потом выбираются поля, то я всё правильно решил?


Скорее всего нет, так как 2 позапроса в HAVING это странно.

>>1084787

Почему надписи в echo транслитом? Кириллица должна по идее работать. Или у тебя что-то не работает? Неудобно читать.

Имена переменных тоже не стоит называть транслитом.

Также, ты неудачно выбрал тип возвращаемых данных. Давай посмотрим на твою функцию, что она получает на вход и что дает на выходе:

- на вход - получает параметры кредита в виде чисел
- на выходе - выдает текстовую строку

Как дальше работать с этой строкой? Как например найти самый выгодный кредит?

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

Также, в коде я вижу еще одну проблему:

for (...) {
if (...) {
$result = "Vsego bilo viplacheno ...";
}
}

return $result;

Тут видно, что переменная $result создается только если цикл выполнится хотя бы раз, и если if сработает, а что, если нет? Будет попытка вернуть значение несуществующей переменной. Это неправильно. Ты пишешь код, который так и просит сделать в нем ошибку. Лучше было сделать return "Vsego bilo..." и тогда проблемы бы не было.

То есть вот такой ерунды не должно быть:

if (...) {
$x = 100;
}

return $x;

так как здесь нет гарантий что переменная $x будет создана.
#137 #1085790
>>1085787

Одна группа квадратных скобок лишняя.
#138 #1085791
>>1084760

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

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

>>1084753

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

>>1084756

Потому что флаг g используется только на regex101 (искать все совпадения с регуляркой, а не только первое), в PHP он не используется.

>>1084752

Флаг g не работает в PHP.

> Как тогда указать, что скобки, пробелы и тире может идти между цифрами?



- написать выражение "одна скобка, пробел или тире"
- сделать из него "любое число скобок, пробелов или тире"
- сделать из него "любое число скобок, пробелов или тире, за ними ровно 1 цифра"
- сделать, чтоыб предыдущее выражение повторялось ровно 10 раз

>>1084698

Пройтись по массиву циклом и перенести во второй массив только не-пустые элементы.

>>1084686

\W соответствует вообще любым символами вроде % или @, которых не должно быть в номере телефона.
#138 #1085791
>>1084760

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

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

>>1084753

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

>>1084756

Потому что флаг g используется только на regex101 (искать все совпадения с регуляркой, а не только первое), в PHP он не используется.

>>1084752

Флаг g не работает в PHP.

> Как тогда указать, что скобки, пробелы и тире может идти между цифрами?



- написать выражение "одна скобка, пробел или тире"
- сделать из него "любое число скобок, пробелов или тире"
- сделать из него "любое число скобок, пробелов или тире, за ними ровно 1 цифра"
- сделать, чтоыб предыдущее выражение повторялось ровно 10 раз

>>1084698

Пройтись по массиву циклом и перенести во второй массив только не-пустые элементы.

>>1084686

\W соответствует вообще любым символами вроде % или @, которых не должно быть в номере телефона.
#139 #1085792
>>1084657

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

- индексы должны быть уникальными и не могут повторяться
- индекс может быть только числом или строкой
- поиск элемента по индексу в массиве очень быстрый

Если у тебя маленький массив (десятки элементов), особой разницы между in_array и array_key_exists нет, но на больших массивах (тысячи элементов) разница становится заметна - in_array медленнее, особенно если вызывать его много раз.

То есть индекс это что-то вроде "идентификатора", по которому можно быстро найти элемент. Если ты работаешь с большими массивами, надо это учитывать.

Группировка товаров 1) https://ideone.com/RQ1WDk

Формат массива выбран неудачно. Из-за него ты делаешь лишний цикл, чтобы извлечь данные. Лучше было сделать так:

['ром', 100],
['ром', 50]

Или так:

['name' => 'Ром', 'weight' => 100],
...

Имена переменных выбраны не очень удачно:

$db -> $items
$result -> $itemsWeight

Алгоритм выбран верно.

Повтор слов 2) https://repl.it/N2om/0

Разделение текста на слова можно было сделать так (без регулярок, которые ты скоро изучишь):

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

Названия переменных плохие и код тяжело читать. Сравни:

foreach ($arr as $slovo1)
foreach ($words as $word)

Алгоритм переусложнен. Тут есть такие варианты:

- обойдя массив слов в цикле, найти число повторов с помощью count и array_intersect
- обойдя массив слов в цикле, построить массив вида [слово => число повторов] и далее на его основе делать выводы
- сделать то же самое с помощью стандартной функции array_count_values

Тебе надо стараться использовать стандартные функции, где возможно, а не писать циклы лишний раз. Список функций: http://php.net/manual/ru/ref.array.php

Слова с согласными 3) https://repl.it/NXrw/1

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

Не надо использовать arr в названии переменной, используй множественное число: words, letters (буквы), sentences.

Названия i, j, k вообще ничего не говорят.

Код выровнен не по рекомендации PSR, посмотри пример: http://www.php-fig.org/psr/psr-2/#11-example особенно, расстановку фигурных скобок около else.

Таблица умножения https://ideone.com/Ez74yF

Перевод строки можно было сделать в разы проще:

for () {
for () {
....
}
echo "\n"; // перевод строки
}

А так, логика правильная.
#139 #1085792
>>1084657

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

- индексы должны быть уникальными и не могут повторяться
- индекс может быть только числом или строкой
- поиск элемента по индексу в массиве очень быстрый

Если у тебя маленький массив (десятки элементов), особой разницы между in_array и array_key_exists нет, но на больших массивах (тысячи элементов) разница становится заметна - in_array медленнее, особенно если вызывать его много раз.

То есть индекс это что-то вроде "идентификатора", по которому можно быстро найти элемент. Если ты работаешь с большими массивами, надо это учитывать.

Группировка товаров 1) https://ideone.com/RQ1WDk

Формат массива выбран неудачно. Из-за него ты делаешь лишний цикл, чтобы извлечь данные. Лучше было сделать так:

['ром', 100],
['ром', 50]

Или так:

['name' => 'Ром', 'weight' => 100],
...

Имена переменных выбраны не очень удачно:

$db -> $items
$result -> $itemsWeight

Алгоритм выбран верно.

Повтор слов 2) https://repl.it/N2om/0

Разделение текста на слова можно было сделать так (без регулярок, которые ты скоро изучишь):

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

Названия переменных плохие и код тяжело читать. Сравни:

foreach ($arr as $slovo1)
foreach ($words as $word)

Алгоритм переусложнен. Тут есть такие варианты:

- обойдя массив слов в цикле, найти число повторов с помощью count и array_intersect
- обойдя массив слов в цикле, построить массив вида [слово => число повторов] и далее на его основе делать выводы
- сделать то же самое с помощью стандартной функции array_count_values

Тебе надо стараться использовать стандартные функции, где возможно, а не писать циклы лишний раз. Список функций: http://php.net/manual/ru/ref.array.php

Слова с согласными 3) https://repl.it/NXrw/1

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

Не надо использовать arr в названии переменной, используй множественное число: words, letters (буквы), sentences.

Названия i, j, k вообще ничего не говорят.

Код выровнен не по рекомендации PSR, посмотри пример: http://www.php-fig.org/psr/psr-2/#11-example особенно, расстановку фигурных скобок около else.

Таблица умножения https://ideone.com/Ez74yF

Перевод строки можно было сделать в разы проще:

for () {
for () {
....
}
echo "\n"; // перевод строки
}

А так, логика правильная.
#140 #1085793
>>1084558

Так-то неплохо, но в слове "разделал медведя на части" заменит "з" на "с", что не требуется.

Также, обрати внимание, в мануале написано, что можно передать массив строк для поиска и массив выражений для замены: http://php.net/manual/ru/function.preg-replace.php

>>1084256

Если ты прошел урок на массивы и на строки из учебника в ОП-посте (или любого другого учебника), то вообще должен уметь решать. В первой задаче нужно завести массив вида [название товара => суммарный вес]. Затем обойти в цикле массив товаров, и для каждого товара увеличивать вес в массиве.

А так, задавай более конкретные вопросы, что непонятно.

>>1084232

Плохо, если не можешь, ведь задача не такая и сложная.

>>1084218

Я не очень понял вопрос.

> есть динамическая таблица которая генерирует name = val1; name = val2; name = val3 ... к новым созданым ячейкам


Что за динамическая таблица? SQL-таблица? HTML-таблица? Как она что-то генерирует?

> Теперь эту таблицу нужно передать в mysql.


Что значит "передать в MySQL"?

> выдает пустую страницу пхп файла (т.е что-то пошло не так)


Ну так посмотри в логе ошибок Апача (если ты используешь mod_php в Апаче), в чем дело.

>>1084179

Ты неправильно используешь квадратные скобки.
#140 #1085793
>>1084558

Так-то неплохо, но в слове "разделал медведя на части" заменит "з" на "с", что не требуется.

Также, обрати внимание, в мануале написано, что можно передать массив строк для поиска и массив выражений для замены: http://php.net/manual/ru/function.preg-replace.php

>>1084256

Если ты прошел урок на массивы и на строки из учебника в ОП-посте (или любого другого учебника), то вообще должен уметь решать. В первой задаче нужно завести массив вида [название товара => суммарный вес]. Затем обойти в цикле массив товаров, и для каждого товара увеличивать вес в массиве.

А так, задавай более конкретные вопросы, что непонятно.

>>1084232

Плохо, если не можешь, ведь задача не такая и сложная.

>>1084218

Я не очень понял вопрос.

> есть динамическая таблица которая генерирует name = val1; name = val2; name = val3 ... к новым созданым ячейкам


Что за динамическая таблица? SQL-таблица? HTML-таблица? Как она что-то генерирует?

> Теперь эту таблицу нужно передать в mysql.


Что значит "передать в MySQL"?

> выдает пустую страницу пхп файла (т.е что-то пошло не так)


Ну так посмотри в логе ошибок Апача (если ты используешь mod_php в Апаче), в чем дело.

>>1084179

Ты неправильно используешь квадратные скобки.
#141 #1085795
>>1084135

Если сайт высокопосещаемый, придется городить оптимизацию обновлений, например

- https://web.archive.org/web/20151025152301/https://habrahabr.ru/company/mailru/blog/206494/ (нынешняя версия на хабре сломана инвалидами)

>>1083935

Нет конечно. Зачем городить огромное количество одинаковых таблиц? И как потом с ними работать? Как например выбрать 3 последних поста из любых тредов? Как получить 3 самых старых треда?

>>1083880

У тебя конечно не хватает внешних ключей.

Тормоза при джойне у тебя могут быть из-за отстутвия индексов по полям, по которым производится джойн (теория https://ruhighload.com/post/Работа+с+индексами+в+MySQL )

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

Для учета бамп-лимита его надо как-то сформулировать. Пусть у нас у постов есть поле added. Что такое бамп-лимит? Он значит, что дата бампа поста определяется так:

- дата добавления 500-го поста, если постов >= 500
- или дата добавления последнего поста, если постов < 500

Нужно это как-то записать в виде SQL условий, и это будет сложно. Попробуем написать запрос для получения даты бампа одного треда (не используя LIMIT, так как он не пригодится в джойне).

Для этого мы выберем все посты в треде. К каждому посту мы приджойним список постов того же треда, добавленных ранее (earlier) и список постов, добавленных позже (later). Затем сгруппируем все это в одну группу и таким образом, мы можем для каждого поста p получить количество постов до и после него в треде. Мы используем COUNT(DISTINCT) так как просто COUNT будет выдавать неверные цифры из-за 2 джойнов.

Какой пост нам нужен? Нам нужен либо 500-й пост (то есть пост, перед которым идет 499 других постов), либо если его нет, последний пост (то есть пост, после которого идет 0 постов).

- выбираем все посты 1 треда (p)
- приджойниваем к каждому p все остальные посты, которые написаны раньше (earlier)
- приджойниваем все посты, написанные позже (later)
- группируем по p.id (то есть получаем группу с later и earlier на каждый исходный пост)
- выбираем (HAVING) группу, у которой COUNT(DISTINCT earlier) = 499 ИЛИ (COUNT(DISTINCT later) = 0 и COUNT(DISTINCT earlier) < 499)

Тут мы используем 2 джойна (к посту приджойниваются все посты того же треда 2 раза), чтобы получить earlier и later. Но если подумать, то earlier и later - это ведь сущности одного типа (другие посты треда), которые отличаются только датой добавления - позже или раньше.

Значит, можно сделать один джойн - приджойнить к посту все другие посты треда. Затем после группировки, мы можем найти число постов раньше/позже текущего просто посчитав число постов у которых other.added < p.added или наоборот:

- выбираем все посты одного треда (p)
- приджойниваем к каждому p все остальные посты треда (other)
- группируем по p.id
- выбираем группу, которая соответствует 500-му или последнему посту, то есть HAVING SUM(other.added < p.added) = 499 OR (SUM(other.added > p.added) = 0 AND SUM(other.added < p.added) < 499)

Так мы получим таблицу вида

ОП-пост | дата бампа

Отсортировав эту таблицу по дате бампа, мы получим последовательность тредов. Остается только приджойнить сюда 3 последние поста и ОП-пост, взяв исходную таблицу в скобки:

SELECT FROM (SELECT ...) AS threads t JOIN posts p ...

Сложные джойны с подзапросами удобно писать с использованием слова WITH, которого нет в MySQL, но есть в postgres и вроде бы в стандарте SQL: https://www.postgresql.org/docs/9.1/static/queries-with.html

Теперь про оптимизацию

У тебя скорее всего проблема в отсутствии индексов. Добавим индексы, увеличим число постов до 100 000 и снова порассуждаем о дальнейшей оптимизации.

Вообще, выбрать 3 последних поста из одного треда довольно легко:

SELECT ... WHERE thread_id = ? ORDER BY added DESC LIMIT 3

Если есть индекс по (thread_id, added), то это очень быстро.

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

SELECT t.id, fp.text AS first_text,
(SELECT p.text FROM post p WHERE p.thread_id = t.id ORDER BY p.id DESC LIMIT 1) AS last_text
FROM thread t
JOIN post fp ON fp.id = t.id ;

Демо: http://sqlfiddle.com/#!9/3a12a/5

Хотя MySQL не позволит использовать LIMIT в некоторых подзапросах ( https://dev.mysql.com/doc/refman/5.7/en/subquery-restrictions.html ), тут это сработает. Аналогично можно добавить подзапросы для выборки 2-го и 3-го с конца треда постов.

Правда, этот запрос выбирает первый и последний пост как колонки, но не как строчки. Это обходится либо с помощью UNION:

(
выбрать все ОП-посты
UNION
выбрать все последние посты
UNION
выбрать все предпоследние посты
UNION
выбрать все 3-и с конца посты
)
отстортировать и удалить дубликаты

Либо с помощью выбора 4 постов в виде колонок и затем джойна на искуственную таблицу из 4 строк:

выбрать ОП-пост и последние 3 поста как 4 колонки
сджойнив на таблицу из 4 строк
так, что каждой строке соответствует 1 колонка

Этот запрос (в теории) эффективней, так как джойн таблицы на себя требует обхода N x N строк, а в запросе с UNION мы обходим N + N + (N x 2) + (N x 3) строк, если я ничего не путаю.

Было бы хорошо, если бы ты протестировал на большой таблице с индексами разные варианты и сравнил время.

Увы, тут я не учел бамп-лимит. Чтобы учесть бамп-лимит даже с помощью подзапросов, нам надо будет обходить порядка 500 постов (чтобы найти пост, из которого берется дата бампа), и это убьет всю оптимизацию. Нельзя быстро получить результат, если мы обходим сотни тысяч строк.

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

Первое, что приходит в голову - сделать дату бампа треда полем в таблице тредов. При добавлении нового поста мы смотрим, если в треде менее 500 постов, то обновляем дату бампа треда. Тогда выборка например первых 10 тредов получается простой ии быстрой:

SELECT t.id, t.bump_date
FROM threads t
ORDER BY t.bump_date DESC
LIMIT 10

Что касается выборки последних 3 постов, можно попробовать сделать ее добавлением избыточных ссылок на эти посты. Например:

- сделать таблицу top_posts, связывающую тред, ОП пост и 3 последних поста
- сделать в таблице тредов поля post1_id, post2_id и post3_id или одно поле last_posts (тогда мы делаем выборку в 2 шага: выбираем треды, извлекаем id последних постов и делаем новый запрос с WHERE id IN (список id))

Можешь попробовать сделать все эти варианты.
#141 #1085795
>>1084135

Если сайт высокопосещаемый, придется городить оптимизацию обновлений, например

- https://web.archive.org/web/20151025152301/https://habrahabr.ru/company/mailru/blog/206494/ (нынешняя версия на хабре сломана инвалидами)

>>1083935

Нет конечно. Зачем городить огромное количество одинаковых таблиц? И как потом с ними работать? Как например выбрать 3 последних поста из любых тредов? Как получить 3 самых старых треда?

>>1083880

У тебя конечно не хватает внешних ключей.

Тормоза при джойне у тебя могут быть из-за отстутвия индексов по полям, по которым производится джойн (теория https://ruhighload.com/post/Работа+с+индексами+в+MySQL )

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

Для учета бамп-лимита его надо как-то сформулировать. Пусть у нас у постов есть поле added. Что такое бамп-лимит? Он значит, что дата бампа поста определяется так:

- дата добавления 500-го поста, если постов >= 500
- или дата добавления последнего поста, если постов < 500

Нужно это как-то записать в виде SQL условий, и это будет сложно. Попробуем написать запрос для получения даты бампа одного треда (не используя LIMIT, так как он не пригодится в джойне).

Для этого мы выберем все посты в треде. К каждому посту мы приджойним список постов того же треда, добавленных ранее (earlier) и список постов, добавленных позже (later). Затем сгруппируем все это в одну группу и таким образом, мы можем для каждого поста p получить количество постов до и после него в треде. Мы используем COUNT(DISTINCT) так как просто COUNT будет выдавать неверные цифры из-за 2 джойнов.

Какой пост нам нужен? Нам нужен либо 500-й пост (то есть пост, перед которым идет 499 других постов), либо если его нет, последний пост (то есть пост, после которого идет 0 постов).

- выбираем все посты 1 треда (p)
- приджойниваем к каждому p все остальные посты, которые написаны раньше (earlier)
- приджойниваем все посты, написанные позже (later)
- группируем по p.id (то есть получаем группу с later и earlier на каждый исходный пост)
- выбираем (HAVING) группу, у которой COUNT(DISTINCT earlier) = 499 ИЛИ (COUNT(DISTINCT later) = 0 и COUNT(DISTINCT earlier) < 499)

Тут мы используем 2 джойна (к посту приджойниваются все посты того же треда 2 раза), чтобы получить earlier и later. Но если подумать, то earlier и later - это ведь сущности одного типа (другие посты треда), которые отличаются только датой добавления - позже или раньше.

Значит, можно сделать один джойн - приджойнить к посту все другие посты треда. Затем после группировки, мы можем найти число постов раньше/позже текущего просто посчитав число постов у которых other.added < p.added или наоборот:

- выбираем все посты одного треда (p)
- приджойниваем к каждому p все остальные посты треда (other)
- группируем по p.id
- выбираем группу, которая соответствует 500-му или последнему посту, то есть HAVING SUM(other.added < p.added) = 499 OR (SUM(other.added > p.added) = 0 AND SUM(other.added < p.added) < 499)

Так мы получим таблицу вида

ОП-пост | дата бампа

Отсортировав эту таблицу по дате бампа, мы получим последовательность тредов. Остается только приджойнить сюда 3 последние поста и ОП-пост, взяв исходную таблицу в скобки:

SELECT FROM (SELECT ...) AS threads t JOIN posts p ...

Сложные джойны с подзапросами удобно писать с использованием слова WITH, которого нет в MySQL, но есть в postgres и вроде бы в стандарте SQL: https://www.postgresql.org/docs/9.1/static/queries-with.html

Теперь про оптимизацию

У тебя скорее всего проблема в отсутствии индексов. Добавим индексы, увеличим число постов до 100 000 и снова порассуждаем о дальнейшей оптимизации.

Вообще, выбрать 3 последних поста из одного треда довольно легко:

SELECT ... WHERE thread_id = ? ORDER BY added DESC LIMIT 3

Если есть индекс по (thread_id, added), то это очень быстро.

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

SELECT t.id, fp.text AS first_text,
(SELECT p.text FROM post p WHERE p.thread_id = t.id ORDER BY p.id DESC LIMIT 1) AS last_text
FROM thread t
JOIN post fp ON fp.id = t.id ;

Демо: http://sqlfiddle.com/#!9/3a12a/5

Хотя MySQL не позволит использовать LIMIT в некоторых подзапросах ( https://dev.mysql.com/doc/refman/5.7/en/subquery-restrictions.html ), тут это сработает. Аналогично можно добавить подзапросы для выборки 2-го и 3-го с конца треда постов.

Правда, этот запрос выбирает первый и последний пост как колонки, но не как строчки. Это обходится либо с помощью UNION:

(
выбрать все ОП-посты
UNION
выбрать все последние посты
UNION
выбрать все предпоследние посты
UNION
выбрать все 3-и с конца посты
)
отстортировать и удалить дубликаты

Либо с помощью выбора 4 постов в виде колонок и затем джойна на искуственную таблицу из 4 строк:

выбрать ОП-пост и последние 3 поста как 4 колонки
сджойнив на таблицу из 4 строк
так, что каждой строке соответствует 1 колонка

Этот запрос (в теории) эффективней, так как джойн таблицы на себя требует обхода N x N строк, а в запросе с UNION мы обходим N + N + (N x 2) + (N x 3) строк, если я ничего не путаю.

Было бы хорошо, если бы ты протестировал на большой таблице с индексами разные варианты и сравнил время.

Увы, тут я не учел бамп-лимит. Чтобы учесть бамп-лимит даже с помощью подзапросов, нам надо будет обходить порядка 500 постов (чтобы найти пост, из которого берется дата бампа), и это убьет всю оптимизацию. Нельзя быстро получить результат, если мы обходим сотни тысяч строк.

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

Первое, что приходит в голову - сделать дату бампа треда полем в таблице тредов. При добавлении нового поста мы смотрим, если в треде менее 500 постов, то обновляем дату бампа треда. Тогда выборка например первых 10 тредов получается простой ии быстрой:

SELECT t.id, t.bump_date
FROM threads t
ORDER BY t.bump_date DESC
LIMIT 10

Что касается выборки последних 3 постов, можно попробовать сделать ее добавлением избыточных ссылок на эти посты. Например:

- сделать таблицу top_posts, связывающую тред, ОП пост и 3 последних поста
- сделать в таблице тредов поля post1_id, post2_id и post3_id или одно поле last_posts (тогда мы делаем выборку в 2 шага: выбираем треды, извлекаем id последних постов и делаем новый запрос с WHERE id IN (список id))

Можешь попробовать сделать все эти варианты.
#142 #1085797
>>1085795

> Он значит, что дата бампа поста определяется так:


Дата бампа треда конечно же.
19 Кб, 658x280
#143 #1085802
>>1085657

>Тебе надо прописать в конфиге Апача директивы LoadModule и SetHandler как описано тут: http://php.net/manual/ru/install.unix.apache2.php (тебе нужно только то, что касается этих директив, остальное не нужно).



Посмотри, правильно ли я указал LoadModule? Я добавил символ решетки, чтобы как другие параметры былоКуда указывать SetHandler? У меня Apache на диске С, в то время как PHP на диске D, ничего страшного?
#144 #1085809
>>1085802

Ты не пробовал прочесть документацию по директивам (увы, все на англ., кто бы перевел?):

https://httpd.apache.org/docs/2.4/handler.html
https://httpd.apache.org/docs/2.2/ru/handler.html
https://httpd.apache.org/docs/2.4/mod/core.html#sethandler

https://httpd.apache.org/docs/2.4/mod/mod_so.html#loadmodule

В общем про конфиги: https://httpd.apache.org/docs/2.4/configuring.html#syntax

Решетка обозначает комментарий.

В директивах должны быть указаны корретные пути к файлам.
#145 #1085811
>>1085802

Также обрати внимание на замечание тут

https://httpd.apache.org/docs/2.4/platform/windows.html

> The directives that accept filenames as arguments must use Windows filenames instead of Unix ones. However, because Apache may interpret backslashes as an "escape character" sequence, you should consistently use forward slashes in path names, not backslashes.

46 Кб, 272x220
#146 #1085844
https://ideone.com/VY5DOT

Задача на номера верно решена?
#147 #1085898
518 Кб, 1700x1734
#148 #1085899
>>1085844
>>1085898
https://ideone.com/ME8bwY

А так вообще прекрасно.
#149 #1085951
>>1085809
>>1085811
Я почитал. Более-менее начал понимать, но что-то настроить пока не получалось. Загуглил гайд на хабрахаре https://habrahabr.ru/post/203012/#anchor01 и попробвал также сделать, только со своей директорий. В итоге у меня не находит ни info.php, ни index.html, лол. Зато появляется надпись "Index of /

localhost/" где localhost являеется гипер ссылкой. Дальше они пустые все
#151 #1085966
>>1085951
а зачем апач, если есть nginx? интересно просто
https://it-e.ru/blogs/administrirovanie/nginx-php-na-windows-za-5-minut
#152 #1085980
>>1085953
Короче. Я решил заново поставить апач, а то я в конфиге много чего переделал. Ничего не добился, только время потратил, лол.
#153 #1085988
>>1085980
Так. Я настроил. Оп не отвечай, я насторил.
#154 #1086030
>>1085657

>


>Тут есть 3 стандартных паттерна: Class TI, Concrete TI, STI:


Спасибо! А такой вопрос: есть ли в yii2 "из коробки" возможность сохранять релейшны из формы или для каждой формы придется делать каскадное сохранение/удаление/редактирование потомков?
194 Кб, 388x475
#155 #1086040
Вспомнил про openshift, что можно нахаляву себе что-нибудь поставить.
А там какие-то пресеты для php: PHP, CakePHP + Mysql, Laravel + Mysql
и нужно ссылки еще на гитхаб давать, чтобы оно само там приложение билдило.

Поэтому вопрос CakePHP или Laravel - нормальные фреймворки? Популярные?
#156 #1086173
Господа ГУРУ, ньюфагодебил просит совета. Встала у меня задачка реализовать простую динамическую страничку, собственно вот как задумал я:

Сервер: windows, apache, php, mysql

Скрипт: крутится php-скрипт, отсылающий JSON запросы и получающий JSON ответы. полученные данные обрабатывает и результаты помещает в БД.

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

Макс. нагрузка: до 5 пользователей одновременно. И наш сервер, и сервера, на которые идут запросы находятся в VPN, т.е. вопрос безопасности не ставится.

Подскажите, где я сосну и почему я такой уродился?
P.S. Познания в php,html,css чуть выше, чем "Hello world".
#157 #1086177
>>1086173
Ах да, данные обновляются раз в 5 секунд. Объем одного "тика" обновления - ~ 1000 символов.
#158 #1086259
>>1086173
Майскуль - говно, ставь тырпрайзную бд: оракл, мсскуль, постгре.
#159 #1086266
>>1086259

Как убедительно аргументировано.
#160 #1086274
>>1086266
Наступай на все грабли сам, че ты как не июнь?
#161 #1086302
>>1086173
давай я дополню. винда говно, и апач тоже говно. ставь линукс, нжинкс и постгрес.

а вообще неясно в чем твой вопрос и что значит "скрипт крутится". php в контексте веб-сервера работает по запросу, он "крутится" только если сервер очередей настроен или если это просто клишный скрипт.
#162 #1086303
>>1086173
давай я дополню. винда говно, и апач тоже говно. ставь линукс, нжинкс и постгрес.

а вообще неясно в чем твой вопрос и что значит "скрипт крутится". php в контексте веб-сервера работает по запросу, он "крутится" только если сервер очередей настроен или если это просто клишный скрипт.
#163 #1086320
>>1086173
давай я дополню. винда говно, и апач тоже говно. ставь линукс, нжинкс и постгрес.

а вообще неясно в чем твой вопрос и что значит "скрипт крутится". php в контексте веб-сервера работает по запросу, он "крутится" только если сервер очередей настроен или если это просто клишный скрипт.
#164 #1086325
>>1086302
Я думал запускать php скрипт на самом сервере средствами ос. Видимо да, это CLI.
Вопрос собственно:
1) корректно ли для получения данных не по запросу пользователя использовать пхп, или это забивание гвоздей микроскопом? Можно ведь использовать bash или powershell какой-либо, но это же еще в этом разбираться придется...
2) правильно ли засовывать эти постоянно (раз в 5 секунд) обновляющиеся данные в БД и оттуда вытаскивать их на страницу, или есть смысл избавиться от внешнего скрипта и выполнять запросы непосредственно когда открыта страничка ("по запросу").

Как делают большие дяди? Просто если пользователей больше одного, буду гонять траффик впустую. Да и потом эти данные из бд можно анализировать (вдруг?)
#165 #1086334
>>1086259
>>1086302
Поясните, почему майскуль - говно?
тоже ньюфаг
#166 #1086339
>>1086325
Не правильно. Реляционка сдохнет от такой хуйни, если утебя хотя бы больше 10 мил.строк.

Если нужно быстро - пиши в монгу. Или делай быстрый кэш на редисе и по тайму обработчиком забирай данные в редис и клади в реляционку.

Майскуль говно потому что не отвечает энерпрайзным стандартам. Для проекта уровня гостевухи - похуй, какая бд.
#167 #1086344
>>1086325
если все приложение написано на php, то использовать кли-скрипт, который является частью приложения - это самый корректный вариант. он может пользоваться существующими эксепшнами, логгером, который там определен, классами бд и т.д. php в 100 раз лучше баша умеет работать с бд, json и всем вот этим. баш для работы с бекендом я не видел, чтоб использовался. он нужен для автоматизации работы одного пользователя, грубо говоря.

по твоей задаче я не очень понял, что тебе в итоге нужно, просто могу сказать, что в моей бывшей конторе (она достаточно крупна) подобные задачи решались запуском кли-скриптов по крону и сервером очередей (хотя в твоем случае это был бы крон). не исключаю, что это дедовский способ и, возможно, есть что-то посовременнее.
#168 #1086351
>>1086334
mysql не говно, она работает быстро и корректно на базах данных небольших объемов. плюс там есть стрикт-режим, который решает много проблем с безопасностью. поэтому для гостевух и интернет-магазинов она вполне ок. но если проект вырастет, надо будет или сильно изъебываться, или менять ее на тот же постгрес.
#169 #1086507
Чтобы начать работать с гитхабом достаточно скачать клиент по ссылке: https://desktop.github.com/ ?
#170 #1086511
>>1086507

Нужно освоить гит - систему управления версиями. Начинать лучше с клиента для командной строки, гайд, как пользоваться командной строкой, есть в ОП-посте.

Гит можно изучить по книге https://git-scm.com/book/ru/v2 (все изучать не надо)

Github Desktop - безсполезен, если ты не понимаешь, как работает гит, и не умеешь с ним работать через командную строку.
#171 #1086512
>>1086511
Благодарю!
#172 #1086537
Анон, объясни SOLID на пальцах.
#173 #1086677
>>1086537
Никто на пальцах тебе не объяснит, вникать нужно долго и основательно, параллельно решая задачи и анализируя свой код. Начни с этой статьи: http://blog.byndyu.ru/2009/10/solid.html
Задачи есть в ОП-посте. Я бы ещё добавил какую-нибудь игру консольную - например шахматы.
#174 #1086700
>>1086351
Дык блядь, нахуя изъебываться, если можно взять сразу нормальную бд?
#175 #1086735
>>1086537
S - The Single Responsibility Principle - Принцип единственности ответственности
Класс отвечает за какую-то одну конкретную задачу или область ответственности и не засирается. Например, не должен один класс отвечать за работу с БД и отправкой имейла.

O - The Open Closed Principle - Принцип открытости/закрытости
Если тебе требуется изменить какой-то класс из-за изменившихся требований к этому классу, то не подобает менять еще 100500 классов, которые с этим классом работают, т.к. это не их ответственность. Для того, чтобы соблюсти это условие ты:
1 - не должен урезать интерфейс этого класса таким образом, чтобы тот код, который УЖЕ с ним работает менялся
2 - выстраивать между классами такие отношения, чтобы они не были в курсе внутренней работы друг друга

L - The Liskov Substitution Principle - Принцип замещения Лисков
Если у тебя есть некий родительский класс, который можно отправить аргументом в функцию или метод другого класса, то значит туда же можно безболезненно и не ломая логику отправить все классы, который от этого родительского класса наследуются.

I - The Interface Segregation Principle - Принцип разделения интерфейса
Наследники твоего родительского класса или классы реализующие какой-либо интерфейс не должны делать слишком дохера ненужной для их функционирования работы. Т.е. родитель или интерфейс не должны требовать лишнего от потомков/реализаций.

D - The Dependency Inversion Principle - Принцип инверсии зависимости
Обычный принцип инверсии зависимостей. С него, кстати, я и советую начать разбираться в солид, т.к. это один из самых, на мой взгляд, главных принципов в ООП. Если на пальцах, у тебя есть класс, который работает с 20 другими классами. У этих 20 классов свои конструкторы, свои зависимости и пр. Т.е. просто так взять и создать экземпляры всех этих классов не так-то просто, нужно знать их поднаготную, что подавать в конструктор и какие конкретно экземпляры классов для корректной работы им нужны. Представь, что тебе надо создать объект, а внутри него должны быть еще 20 объектов, у которых есть свои зависимости. С ума можно сойти. В идеале твоем главному объекту вообще должно быть похер как эти 20 объектов, с которыми он работает создаются и откуда они берутся. Для этого и нужен Dependency Injection

Это тебе на пальцах. И этого, конечно, недостаточно, чтобы полноценно следовать принципам SOLID. Их надо дрочить помногу раз, чтобы понять. А еще лучше, не соблюдая эти принципы, пару раз обжечься в достаточно большом проекте.
#175 #1086735
>>1086537
S - The Single Responsibility Principle - Принцип единственности ответственности
Класс отвечает за какую-то одну конкретную задачу или область ответственности и не засирается. Например, не должен один класс отвечать за работу с БД и отправкой имейла.

O - The Open Closed Principle - Принцип открытости/закрытости
Если тебе требуется изменить какой-то класс из-за изменившихся требований к этому классу, то не подобает менять еще 100500 классов, которые с этим классом работают, т.к. это не их ответственность. Для того, чтобы соблюсти это условие ты:
1 - не должен урезать интерфейс этого класса таким образом, чтобы тот код, который УЖЕ с ним работает менялся
2 - выстраивать между классами такие отношения, чтобы они не были в курсе внутренней работы друг друга

L - The Liskov Substitution Principle - Принцип замещения Лисков
Если у тебя есть некий родительский класс, который можно отправить аргументом в функцию или метод другого класса, то значит туда же можно безболезненно и не ломая логику отправить все классы, который от этого родительского класса наследуются.

I - The Interface Segregation Principle - Принцип разделения интерфейса
Наследники твоего родительского класса или классы реализующие какой-либо интерфейс не должны делать слишком дохера ненужной для их функционирования работы. Т.е. родитель или интерфейс не должны требовать лишнего от потомков/реализаций.

D - The Dependency Inversion Principle - Принцип инверсии зависимости
Обычный принцип инверсии зависимостей. С него, кстати, я и советую начать разбираться в солид, т.к. это один из самых, на мой взгляд, главных принципов в ООП. Если на пальцах, у тебя есть класс, который работает с 20 другими классами. У этих 20 классов свои конструкторы, свои зависимости и пр. Т.е. просто так взять и создать экземпляры всех этих классов не так-то просто, нужно знать их поднаготную, что подавать в конструктор и какие конкретно экземпляры классов для корректной работы им нужны. Представь, что тебе надо создать объект, а внутри него должны быть еще 20 объектов, у которых есть свои зависимости. С ума можно сойти. В идеале твоем главному объекту вообще должно быть похер как эти 20 объектов, с которыми он работает создаются и откуда они берутся. Для этого и нужен Dependency Injection

Это тебе на пальцах. И этого, конечно, недостаточно, чтобы полноценно следовать принципам SOLID. Их надо дрочить помногу раз, чтобы понять. А еще лучше, не соблюдая эти принципы, пару раз обжечься в достаточно большом проекте.
#176 #1086737
>>1086735

>т.к. это один из самых, на мой взгляд, главных принципов в ООП


т.к. это крайне полезный принцип и вызывающий наименьшее кол-во споров вокруг себя
fixed
#177 #1086782
Что из математики надо знать для веба? И где про это можно почитать?
#178 #1086785
>>1086782

>Что из математики надо знать для веба?


Сложение, вычитание, умножение, деление, а так же проценты.
#179 #1086786
>>1086735
Спасибо, друг.

Смотри, такой пример:

class Shaverma
{
public function __construct(Cat $cat) {...}
}

class Cat
{
public function __construct(Shaverma $shaverma) {...}
}

$shaverma = new Shaverma(new Cat(...бесконечная рекурсия...));

Как быть в таком случае рекурсивной зависимости?
#180 #1086802
>>1086700
для маленьких неамбиционзых проектов смысл есть. например, на всех хостингах есть мускул. дешевле и быстрее найти разработчиков для поддержки. очевидно, что если ты решишь сделать сайт шиномонтажа на постгресе, тебя заказчик пошлет нахуй.

>>1086786
ну такого не должно быть, это ошибка в проектировании. какие данные классу cat могут понадобиться от shaverma?
#181 #1086908
Надо ли в php скрипте писать тег <!DOCTYPE HTML>
?
#182 #1086923
>>1086908

><!DOCTYPE HTML>


Это не php, а html скрипт. Писать его нужно, так как иначе могут появится на странице в разных браузерах разные неожиданные баги.
#183 #1086944
>>1086923
Спасибо.
#184 #1086956
На гитхабе php-скрипты не работают, верно? Зачем тогда туда нужно заливать задачу про студентов?
#185 #1086990
>>1086956
На гитхабе вообще ни один ЯП не работает, он не для этого сделан.
#186 #1086992
Чому многие не любят верстку? По мне интересное занятие.
#187 #1086999
>>1086992
Глючная она, много гемора предоставляет если заниматься вплотную. Впрочем если верстать под один браузер вполне интересно.
#188 #1087002
>>1086992
Поработай версталой год. Неблагодарный труд.
#189 #1087051
ОП, проверь, пожалуйста, задачу про "Вектор".

https://3v4l.org/AKB4J
#190 #1087055
>>1087002
а верстальщики щас вообще существуют как профессия кроме как в дизайн-студиях? у нас в конторе, например, верстальщиков вообще нет, есть только фронты. и такой типичной версткой занимается джуниор-фронт
#191 #1087072
>>1086992

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

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

>>1087051

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

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

Также, метод CalculationOfInformation сделан очень неудачно. Он берет и удаляет старые значения свойств и записывает туда новые. А что, если я его не вызову? А что, если вызову 2 раза? Зачем он нужен, почему объект сам не может поддерживать данные в актуальном состоянии? Такие "сложные" в использовании объекты провоцируют появление ошибок.

Также, имена методов должны начинаться с глагола, сделайЧтоТо. А не с существительного.

В данном случае, поскольку итоговая зарплата вычисляется из базовой ставки, ранга, статуса босса, имеет смысл для нее вообще не делать свойства, а сделать метод, который ее вычисляет. Тогда этот метод будет всегда возвращать актуальное значение. Если же ты делаешь свойство, тебе придется его обновлять каждый раз, когда меняется какое-то исходное свойство (например, ранг), от которого оно зависит.

> public function getInformation($value){


> return $value;


Это неправильный метод. Во-первых, его название ни о чем ни говорит ("получить информацию" - но в программе любая переменная хранит какую-то информацию), во-вторых, он ничего полезного не делает.

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

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

> public function addWorkers(AbstractWorker $worker){


> $worker->CalculationOfInformation($worker->rank, $worker->isBoss);



Откуда ты знаешь, что в переданном тебе работнике не была вызывана эта функция раньше? Нигде не написано и не проверяется, что можно передавать только работников, у которых еще не выполнен расчет.

> $worker->getInformation($worker->count);


Что мешает написать просто $worker->count?

> $informarion = array($this->name, 0, 0, 0, 0, 0);


Неудачно выбран формат, в котором возвращаются данные - массив с числовыми индексами. Как понять, что хранится в 2-м или 4-м элементе? И зачем вообще нужно возвращать массив? Этот метод нужен только для одного случая - для вывода одной конкретной таблицы и он не пригодится нигде больше. Значит, не надо его вообще в Департамент добавлять (а надо добавить туда, где будет вывод таблицы). Лучше сделать обычные методы, считающие например среднюю зарплату и итд. Которые можно использовать где-то еще и которые не заточены именно под вывод единственной таблицы.

> class Company{


> public function printInformationOfDepartment(){


Вывод отчета стоит сделать отдельно. Компания должна отвечать только за управление списком департаментов и точно не должна генерировать отчеты. Если мы в нее будем все включть, что к ней отдаленно относится, то получим God Object: https://ru.wikipedia.org/wiki/Божественный_объект

Тебе надо разделить код на части:

- отдельно объектная модель компании, которая представляет компанию, департаменты и сотрудников в виде набора связанных объектов (графа объектов)
- отдельно код, который берет эту модель, и строит на ее основании отчет
- (это будет во второй части задачи) код, который делает какие-то изменения объектной модели

Так код будет гораздо аккуратнее.

Если тебе интересен ООП, и захочется после этой задачи попрактиковаться еще, там в учебнике есть задача про кошек-мышек, и можешь решить еще такую задачу (довольно простая имхо):

------

Есть Гостиница, в ней есть Номера. Для каждого Номера известен его номер, количество Гостей, которое в него влезет, а также цена за сутки. В Гостиницу приезжают Гости. Нужно сделать объектную модель Гостиницы с такими возможностями (методами):

- получить список свободных номеров на определенную дату
- получить список свободных номеров, которые будут свободны в определенный диапазон дат (от A до B)
- дан список Гостей и диапазон дат, в которые они хотели бы заселиться. Необходимо подобрать им самый дешевый (а среди номеров с одинаковой ценой - самый маленький) Номер, который их вместит и который свободен в это время.
- то же самое, но при отстутствии одного подходящего номера для Гостей разрешается заселить их в несколько номеров, опять же, начиная с самых дешевых. Например, приехало 3 Гостя, но все 3-местные номера заняты и мы выделяем 2 2-местных, или 3 1-местных или 1-местный + 2-местный.
- зарегистрировать проживание данных Гостей в данных Номерах на данный период
- получить историю заселения Номера (кто в нем когда жил)
- получить историю заселения Гостя (в каких номерах он жил)
- получить статистику доходов Гостиницы за данный диапазон дат (в день A отдель заработал X тугриков, в день B - Y тугриков и так далее)

----
#191 #1087072
>>1086992

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

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

>>1087051

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

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

Также, метод CalculationOfInformation сделан очень неудачно. Он берет и удаляет старые значения свойств и записывает туда новые. А что, если я его не вызову? А что, если вызову 2 раза? Зачем он нужен, почему объект сам не может поддерживать данные в актуальном состоянии? Такие "сложные" в использовании объекты провоцируют появление ошибок.

Также, имена методов должны начинаться с глагола, сделайЧтоТо. А не с существительного.

В данном случае, поскольку итоговая зарплата вычисляется из базовой ставки, ранга, статуса босса, имеет смысл для нее вообще не делать свойства, а сделать метод, который ее вычисляет. Тогда этот метод будет всегда возвращать актуальное значение. Если же ты делаешь свойство, тебе придется его обновлять каждый раз, когда меняется какое-то исходное свойство (например, ранг), от которого оно зависит.

> public function getInformation($value){


> return $value;


Это неправильный метод. Во-первых, его название ни о чем ни говорит ("получить информацию" - но в программе любая переменная хранит какую-то информацию), во-вторых, он ничего полезного не делает.

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

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

> public function addWorkers(AbstractWorker $worker){


> $worker->CalculationOfInformation($worker->rank, $worker->isBoss);



Откуда ты знаешь, что в переданном тебе работнике не была вызывана эта функция раньше? Нигде не написано и не проверяется, что можно передавать только работников, у которых еще не выполнен расчет.

> $worker->getInformation($worker->count);


Что мешает написать просто $worker->count?

> $informarion = array($this->name, 0, 0, 0, 0, 0);


Неудачно выбран формат, в котором возвращаются данные - массив с числовыми индексами. Как понять, что хранится в 2-м или 4-м элементе? И зачем вообще нужно возвращать массив? Этот метод нужен только для одного случая - для вывода одной конкретной таблицы и он не пригодится нигде больше. Значит, не надо его вообще в Департамент добавлять (а надо добавить туда, где будет вывод таблицы). Лучше сделать обычные методы, считающие например среднюю зарплату и итд. Которые можно использовать где-то еще и которые не заточены именно под вывод единственной таблицы.

> class Company{


> public function printInformationOfDepartment(){


Вывод отчета стоит сделать отдельно. Компания должна отвечать только за управление списком департаментов и точно не должна генерировать отчеты. Если мы в нее будем все включть, что к ней отдаленно относится, то получим God Object: https://ru.wikipedia.org/wiki/Божественный_объект

Тебе надо разделить код на части:

- отдельно объектная модель компании, которая представляет компанию, департаменты и сотрудников в виде набора связанных объектов (графа объектов)
- отдельно код, который берет эту модель, и строит на ее основании отчет
- (это будет во второй части задачи) код, который делает какие-то изменения объектной модели

Так код будет гораздо аккуратнее.

Если тебе интересен ООП, и захочется после этой задачи попрактиковаться еще, там в учебнике есть задача про кошек-мышек, и можешь решить еще такую задачу (довольно простая имхо):

------

Есть Гостиница, в ней есть Номера. Для каждого Номера известен его номер, количество Гостей, которое в него влезет, а также цена за сутки. В Гостиницу приезжают Гости. Нужно сделать объектную модель Гостиницы с такими возможностями (методами):

- получить список свободных номеров на определенную дату
- получить список свободных номеров, которые будут свободны в определенный диапазон дат (от A до B)
- дан список Гостей и диапазон дат, в которые они хотели бы заселиться. Необходимо подобрать им самый дешевый (а среди номеров с одинаковой ценой - самый маленький) Номер, который их вместит и который свободен в это время.
- то же самое, но при отстутствии одного подходящего номера для Гостей разрешается заселить их в несколько номеров, опять же, начиная с самых дешевых. Например, приехало 3 Гостя, но все 3-местные номера заняты и мы выделяем 2 2-местных, или 3 1-местных или 1-местный + 2-местный.
- зарегистрировать проживание данных Гостей в данных Номерах на данный период
- получить историю заселения Номера (кто в нем когда жил)
- получить историю заселения Гостя (в каких номерах он жил)
- получить статистику доходов Гостиницы за данный диапазон дат (в день A отдель заработал X тугриков, в день B - Y тугриков и так далее)

----
61 Кб, 795x631
#192 #1087075
Есть каталог кроватей: некоторые модели бывают разного цвета (одна модель, например, "Кровать А" в двух цветовых вариантах: цвет белый, 3 фотографии и цвет черный, 3 фотографии) и далее несколько размеров и цен, соответственно. У меня получается пока как-так, но кажется, что что-то не так. Использую Симфони и, выходит, Доктрину. Что и как можно улучшить?
#193 #1087084
>>1086956

Чтобы любой мог просмотреть код решения, скачать его себе. А ты мог просмотреть историю изменений.

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

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

>>1086908

В HTML доктайп говорит браузеру о том, что страницу нужно отображать в соответствии с современным и стандартами, а не в Quirks mode (режиме совместимости со старыми сайтами, сделанными до 2000 года).

>>1086786

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

Давай я дам другой пример. Например, рассмотрим дерево категорий (это такая структура, где у узлов может быть 1 родитель и 1 или более детей). Мы хотим допустим, сделать категорию "Бытовая техника", а внутрь нее добавить категории "Телевизоры" и "Холодильники". Каждую категорию бы сделаем объектом, и каждая категория должна "знать" список дочерних и родительскую категорию.

То есть "Бытовая техника" содержит в себе ссылку на "Телевизоры", и наоборот.

class Category
{
private $parent;
private $children = [];

public function addChild(Category $child)
{
if ($child->parent) {
// ошибка: эта категория уже добавлена кому-то в качестве дочерней
throw new Exception("This category already has a parent");
}

$this->children[] = $child;
$child->parent = $this;
}
}

$tech = new Category('Бытовая техника');
$tvs = new Category('Телевизоры');
// Добавляем дочернюю категорию
$tech->addChild($tvs);
$fridges = new Category('Холодильники');
$tech->addChild($fridges);

Мы получили граф связанных между собой объектов, каждая категория знает про родителя и своих детей. Вот примерно так это и делается.

Если нужен пример связи между разными объектами, пожалуйста. Допустим, есть Карта и на ней есть Магазины, между которыми нужно сделать двустороннюю связь (Карта знает про Магазины на ней, а Магазин содержит ссылку на карту):

class Map
{
public function addShop(Shop $shop)
{
$this->shops[] = $shop;
$shop->setMap($this);
}
}

class Shop
{
public function setMap(Map $map)
{
if ($this->map) {
// ошибка
}
$this->map = $map;
}
}

Если ты не очень хорошо понимаешь ООП (судя по странным примерам кода), советую порешать задачи на ООП из учебника в ОП посте или задачу про Гостиницу отсюда: >>1087072
#193 #1087084
>>1086956

Чтобы любой мог просмотреть код решения, скачать его себе. А ты мог просмотреть историю изменений.

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

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

>>1086908

В HTML доктайп говорит браузеру о том, что страницу нужно отображать в соответствии с современным и стандартами, а не в Quirks mode (режиме совместимости со старыми сайтами, сделанными до 2000 года).

>>1086786

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

Давай я дам другой пример. Например, рассмотрим дерево категорий (это такая структура, где у узлов может быть 1 родитель и 1 или более детей). Мы хотим допустим, сделать категорию "Бытовая техника", а внутрь нее добавить категории "Телевизоры" и "Холодильники". Каждую категорию бы сделаем объектом, и каждая категория должна "знать" список дочерних и родительскую категорию.

То есть "Бытовая техника" содержит в себе ссылку на "Телевизоры", и наоборот.

class Category
{
private $parent;
private $children = [];

public function addChild(Category $child)
{
if ($child->parent) {
// ошибка: эта категория уже добавлена кому-то в качестве дочерней
throw new Exception("This category already has a parent");
}

$this->children[] = $child;
$child->parent = $this;
}
}

$tech = new Category('Бытовая техника');
$tvs = new Category('Телевизоры');
// Добавляем дочернюю категорию
$tech->addChild($tvs);
$fridges = new Category('Холодильники');
$tech->addChild($fridges);

Мы получили граф связанных между собой объектов, каждая категория знает про родителя и своих детей. Вот примерно так это и делается.

Если нужен пример связи между разными объектами, пожалуйста. Допустим, есть Карта и на ней есть Магазины, между которыми нужно сделать двустороннюю связь (Карта знает про Магазины на ней, а Магазин содержит ссылку на карту):

class Map
{
public function addShop(Shop $shop)
{
$this->shops[] = $shop;
$shop->setMap($this);
}
}

class Shop
{
public function setMap(Map $map)
{
if ($this->map) {
// ошибка
}
$this->map = $map;
}
}

Если ты не очень хорошо понимаешь ООП (судя по странным примерам кода), советую порешать задачи на ООП из учебника в ОП посте или задачу про Гостиницу отсюда: >>1087072
#194 #1087085
>>1086802

Для больших тоже может быть. MySQL использовался при разработке Facebook и википедии (а также была статья про переход Uber с постгреса на mysql: https://habrahabr.ru/company/southbridge/blog/322624/ ). Я не говорю, что постгрес чем-то плох, это хорошая СУБД, но аргументация там у анона полностью отсуствует, я думаю, он и сам не знает, в чем именно разница, а пересказывает увиденное где-то мнение. Таких анонов нужно сразу слать подальше.

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

>>1086537

Сомневаюсь, что совсем на пальцах это получится объяснить. Это надо читать статьи по каждой букве из SOLID, и писать или изучать примеры кода (например, могу посоветовать расковырять Symfony Forms, если хочешь пример сложной ООП-библиотеки и если ты знаком с HTML-формами). Проектирование - это такая вещь, которую только в теории может быть сложно понять.

Раз уж тебя интересуют аббревиатуры из ООП, познакомлю тебя еще с YAGNI: https://habrahabr.ru/post/153225/

Если ты хотел быстро заучить ответ на вопрос к собеседованию, извини, заучить не получится, нужно разобраться и понять.

Если есть вопросы по ООП, могу попробовать ответить.

>>1086339

"Эксперты" подтянулись. Где написано что MySQL не рассчитана на 10 млн. строк в таблице (я работал с такими таблицами) и что такого особенного в mongoDB, что она лучше для этого подходит? Я могу сказать (аргументированно, в отличие от тебя), что монга рассчитана на какие-то специальные сценарии использования, в ней нет внешних ключей, схемы и транзакций, а это значит что в типичном приложении она превратится в свалку из данных с нарушенными ссылками.

> не отвечает энерпрайзным стандартам.


Это каким?

>>1086325

Если получение данных выполняется быстро, то конечно проще их получать, когда они понадобятся. Чтобы усложнять схему работы, нужны какие-то причины.

Если ты хочешь что-то кешировать, для этого лучше использовать кеш, а не БД.

>>1086040

CakePHP по моему очень старый.

>>1086030

Не знаю.

>>1085966

В случае с нгинксом надо отдельно запускать нгинкс, а отдельно php-fpm. В случае с Апачом - только Апач. Где ж тут проще?

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

Хотя конечно статику нгинкс раздает лучше и быстрее.

>>1085844

Регулярка верная.

> "/7|8/";


> preg_replace($firstNum,'+7',$plusSeven, 1);


Неудачно сделано, так как в регулярке не сказано, что 7 или 8 должны быть именно в начале номера.

> foreach ($withoutAll as $plusSeven) {


Не надо было тут заводить новые переменные, лучше просто использовать те же самые $correctNumbers и $number.

Код еще оформлен не очень удачно (отступы перед фигурными скобками), установи себе IDE или редактор кода, если ты пишешь прямо в окошке ideone, там наверно неудобно большой объем кода писать.
#194 #1087085
>>1086802

Для больших тоже может быть. MySQL использовался при разработке Facebook и википедии (а также была статья про переход Uber с постгреса на mysql: https://habrahabr.ru/company/southbridge/blog/322624/ ). Я не говорю, что постгрес чем-то плох, это хорошая СУБД, но аргументация там у анона полностью отсуствует, я думаю, он и сам не знает, в чем именно разница, а пересказывает увиденное где-то мнение. Таких анонов нужно сразу слать подальше.

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

>>1086537

Сомневаюсь, что совсем на пальцах это получится объяснить. Это надо читать статьи по каждой букве из SOLID, и писать или изучать примеры кода (например, могу посоветовать расковырять Symfony Forms, если хочешь пример сложной ООП-библиотеки и если ты знаком с HTML-формами). Проектирование - это такая вещь, которую только в теории может быть сложно понять.

Раз уж тебя интересуют аббревиатуры из ООП, познакомлю тебя еще с YAGNI: https://habrahabr.ru/post/153225/

Если ты хотел быстро заучить ответ на вопрос к собеседованию, извини, заучить не получится, нужно разобраться и понять.

Если есть вопросы по ООП, могу попробовать ответить.

>>1086339

"Эксперты" подтянулись. Где написано что MySQL не рассчитана на 10 млн. строк в таблице (я работал с такими таблицами) и что такого особенного в mongoDB, что она лучше для этого подходит? Я могу сказать (аргументированно, в отличие от тебя), что монга рассчитана на какие-то специальные сценарии использования, в ней нет внешних ключей, схемы и транзакций, а это значит что в типичном приложении она превратится в свалку из данных с нарушенными ссылками.

> не отвечает энерпрайзным стандартам.


Это каким?

>>1086325

Если получение данных выполняется быстро, то конечно проще их получать, когда они понадобятся. Чтобы усложнять схему работы, нужны какие-то причины.

Если ты хочешь что-то кешировать, для этого лучше использовать кеш, а не БД.

>>1086040

CakePHP по моему очень старый.

>>1086030

Не знаю.

>>1085966

В случае с нгинксом надо отдельно запускать нгинкс, а отдельно php-fpm. В случае с Апачом - только Апач. Где ж тут проще?

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

Хотя конечно статику нгинкс раздает лучше и быстрее.

>>1085844

Регулярка верная.

> "/7|8/";


> preg_replace($firstNum,'+7',$plusSeven, 1);


Неудачно сделано, так как в регулярке не сказано, что 7 или 8 должны быть именно в начале номера.

> foreach ($withoutAll as $plusSeven) {


Не надо было тут заводить новые переменные, лучше просто использовать те же самые $correctNumbers и $number.

Код еще оформлен не очень удачно (отступы перед фигурными скобками), установи себе IDE или редактор кода, если ты пишешь прямо в окошке ideone, там наверно неудобно большой объем кода писать.
#195 #1087092
>>1087075

Мне кажется, если обобщить, можно сделать так:

- Кровать (название, производитель, материал)
- ВариантКровати (цена, цвет, размер, ссылка на внешний вид) - конкретная конфигурация
- ВнешнийВидКровати (представляет собой все варианты, которые выглядят одинаково, содержит несколько изображений)
- Изображение

Если смотреть на твою схему,то получается:

Кровать = BedModel
ВариантКровати = Bed
ВнешнийВидКровати = BedColorModel
Изображение = Image

В общем, примерно то же самое, просто мне кажется, у тебя названия выбраны неудачно и трудно понять с ходу, что они значат.
#196 #1087093
>>1087075

Ну и ссылку я чуть-чуть поменял, у меня ВариантКровати напрямую ссылается на Кровать, а у тебя Bed ссылается на BedColorModel.
#197 #1087107
Как в ActiveRecord сделать следующее:
Есть Главная модель, у которое есть в релейшинах hasMany Модель 2, у Модели 2 есть в релейшинах hasMany Модель 3.
Как будет звучать соединение в одном ActiveQuery всех трёх релейшинов? С двумя всё просто:
Model::search()->innerJoinWith('model2 m2') ... ->andWhere(['m2.attr' => 4]);
как добавить сюда Модель 3 которая в релейшинах с Моделью 2?
#198 #1087108
>>1087107

>::search()


::find()
*selffix
#199 #1087117
>>1087002
Согласен.
#200 #1087119
>>1087072
Я тоже так думаю, все вроде понятно и с практикой просто. Может не каждому дано.
#201 #1087133
>>1087092
>>1087093
Хорошо, а что лучше для админки взять, я выбрал Easy Admin? Но как-то в нем все муторно с поиском и сортировкой из-за большой вложенности сущностей, или это я что-то не так делаю?
18 Кб, 792x574
#202 #1087242
Почему не заменяет?

https://ideone.com/LtV4Yw

Регулярка верная же.
18 Кб, 798x575
#203 #1087244
Оно не работает без флажка g, но и с ним не работает, пишет ошибку preg_replace(): Unknown modifier 'g'.
#204 #1087245
А в интернете пишут, что g уже в preg_replace есть. Что-то тут не чисто. Опять жиды воду мутят.
#205 #1087307
Так. Настроил локальный сервер. Немного умею работать с гитом. Знаю основные теги html и немного css. Чтобы решить студентов нужно еще mysql изучить? Спасибо за ответ!
#206 #1087341
>>1087242

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

>>1087244

В PHP нет флага g. Он нужен только на regex101.
someApprentice #207 #1087406
>>1085268

>>https://github.com/someApprentice/chat/blob/master/public/js/conversation.js#L53


>>


>>+offset + +1


>Немного странное место. Не многовато ли знаков "плюс"?


Что поделать если js при сложении не преобразует данные в число? Приходиться делать это самому.

>Также, мне кажется, что у тебя в контроллере находится код, относящийся ко view: вызовы jQuery вроде if ($(that.view.moremessages).length) стоило бы перенести во view и писать вместо этого if (that.view.hasMoreMessagesButton()), а еще лучше - if (this.canShowMoreMessages()), так как это довольно коряво, проверять наличие новых сообщений по наличию кнопки на экране. Должно ведь быть наоборот - модель/viewModel сама знает, есть ли новые сообщения.


Всегда нужно пользоваться только высстананвленными наружу методами, даже если код займет одну строку?

>Должно ведь быть наоборот - модель/viewModel сама знает, есть ли новые сообщения.


Должно быть свойство модели/viewModel, например this.canShowMoreMessages = true/false?

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


Разве контроллер не должен "дирижировать" всем этим?

>Также, твой Crypter является по сути оберткой над openpgp, ничего от себя не добавляя. Непонятно, в чем смысл его существования. Смысл можно добавить, если Crypter начнет например работать не с абстрактными "сообщениями", а с объектами сообщений. Ты ведь скорее всего в будущем захочешь шифровать не только текст, но и метаданные сообщения, и тут удобно сделать 2 сущности - зашифрованное и расшифрованное сообщение.


>Также, твой Crypter является по сути оберткой над openpgp, ничего от себя не добавляя. Непонятно, в чем смысл его существовани


Вы выше делали замечание что нужно делать обёртку. Я запутан.

>Если ты не готов делать локальное хранилище, то наверно тебе подойдет первый вариант с ручной обработкой ошибок.


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

>Ой-ой, изучил ли ты внимательно принцип работы промисов?


Я старался внимательно подойти к промисам, т.к. у меня проблемы с ними, но я оперался только на документацию mdn, а не на спецификацию PromiseA+. Похоже, это большая ошибка. Буду исправлять. Читая ваши замечания, я нахожу ошибки в своем предстовлении о них.

>Я вижу такие пути:


>


>1. явно обрабатывать reject, примерно так:


>


>backend.getData().then(function (data) {


> displayData();


> }, function (error) {


> displayError();


> });


В омем предстовлении backend занимается только получением данных с API, т.е. с бэкенда сервера. Не будет ли вывод данных нарушением инкапсуляции в таком случае?
someApprentice #207 #1087406
>>1085268

>>https://github.com/someApprentice/chat/blob/master/public/js/conversation.js#L53


>>


>>+offset + +1


>Немного странное место. Не многовато ли знаков "плюс"?


Что поделать если js при сложении не преобразует данные в число? Приходиться делать это самому.

>Также, мне кажется, что у тебя в контроллере находится код, относящийся ко view: вызовы jQuery вроде if ($(that.view.moremessages).length) стоило бы перенести во view и писать вместо этого if (that.view.hasMoreMessagesButton()), а еще лучше - if (this.canShowMoreMessages()), так как это довольно коряво, проверять наличие новых сообщений по наличию кнопки на экране. Должно ведь быть наоборот - модель/viewModel сама знает, есть ли новые сообщения.


Всегда нужно пользоваться только высстананвленными наружу методами, даже если код займет одну строку?

>Должно ведь быть наоборот - модель/viewModel сама знает, есть ли новые сообщения.


Должно быть свойство модели/viewModel, например this.canShowMoreMessages = true/false?

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


Разве контроллер не должен "дирижировать" всем этим?

>Также, твой Crypter является по сути оберткой над openpgp, ничего от себя не добавляя. Непонятно, в чем смысл его существования. Смысл можно добавить, если Crypter начнет например работать не с абстрактными "сообщениями", а с объектами сообщений. Ты ведь скорее всего в будущем захочешь шифровать не только текст, но и метаданные сообщения, и тут удобно сделать 2 сущности - зашифрованное и расшифрованное сообщение.


>Также, твой Crypter является по сути оберткой над openpgp, ничего от себя не добавляя. Непонятно, в чем смысл его существовани


Вы выше делали замечание что нужно делать обёртку. Я запутан.

>Если ты не готов делать локальное хранилище, то наверно тебе подойдет первый вариант с ручной обработкой ошибок.


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

>Ой-ой, изучил ли ты внимательно принцип работы промисов?


Я старался внимательно подойти к промисам, т.к. у меня проблемы с ними, но я оперался только на документацию mdn, а не на спецификацию PromiseA+. Похоже, это большая ошибка. Буду исправлять. Читая ваши замечания, я нахожу ошибки в своем предстовлении о них.

>Я вижу такие пути:


>


>1. явно обрабатывать reject, примерно так:


>


>backend.getData().then(function (data) {


> displayData();


> }, function (error) {


> displayError();


> });


В омем предстовлении backend занимается только получением данных с API, т.е. с бэкенда сервера. Не будет ли вывод данных нарушением инкапсуляции в таком случае?
4 Кб, 575x122
#208 #1087446
Привет, ОП, привет, аноны.

Вопрос по doctrine:migrations

Сделал я doctrine:migration:diff, он создал файл миграции,
я запустил (migration:migrate), он вывалил ошибку и не выполнил миграцию. Тут я понял, что мне эта миграция не нужна и ее нужно удалить. Мне просто взять и удалить файл Version20171105082042.php ? Потому что doctrine:migrations:version 20171105082042 --delete не работает, ведь он удаляет только те миграции, которые уже занеслись в таблицу миграций.

Еще вопрос. Была у меня миграция 1, я создал миграцию 2. Там создание новой таблицы и создание связи между таблицами. Первое он сделал, на втором вывалил ошибку.
Смотрю migration:status - текущая миграция 1. Смотрю БД - таблица из миграции 2 создана. Почему он не выполнил down(), чтобы вернуть всё на прежние места? И как мне его правильно вызвать?
#209 #1087584
Начали в универе учить PHP. Не первым языком, потому я немного скучаю и усложняю себе задания как могу. В связи с чем сталкиваюсь с недостатком знаний о том, как этот язык работает вообще

СУТЬ: абстрактно и в вакууме есть массив, в который запихиваются значения из формы ввода. Я хочу чтоб они засовывались туда несколько раз. Ну, т.е. сначала запихнули A,B,C=>нажали на кнопку подтверждения=>Страница обновилась, показала текущий массив=>Запихнули D,E,F=>Страница обновилась и показала новый, дополненный массив. Так до тех пр пока не заебёт и ты не нажмешь на другую кнопку, которая позволит перейти к другой части задания, где будут проводиться действия с этим массивом.

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

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

Что я делаю не так?

https://pastebin.com/HXDjHPRw
#210 #1087600
>>1087584
Новая страница - новые данные.
Сохраняй данные не в PHP.
Например, кода соединил массив сохраняй его в:
- в сессию
- в текстовый фал
- в базу данных
, а при инициализации данных доставай их, потом что- то делай и завого сохраняй.
#211 #1087602
>>1087600
Хм. Окей, допустим. А для чего тогда все эти суперглобальные штуки нужны, если данные в них обнуляются?
#212 #1087603
>>1087600

> инициализации данных


При инициализации скрипта.

И в форме используй метод POST.
#213 #1087606
>>1087602
Для, того для чего нужны и в других языках.
В суперглобальных пременных, хранятся данные полученные от клиента.
А просто глобальные переменные нужны, чтобы данные были доступны из разных скриптов (плохая практика их использовать).
Обнуляются они потому-что скрипт заканчивает свою работу и высвобождает память, как и любая программа если ее завешить.
#214 #1087608
>>1087606
Хм. Окей, да. Видимо, меня сбило наличие у меня проекта, объединяющего файлы. И я по привычке, ну, как с пространством имён и джавовыми package.

Так-с, значит, я могу все де использовать глобальную переменную и её значение не исчезнет, так? Или нет? Я понял, что лучше через файл, но все же мне интересно.
#215 #1087609
>>1087603
А разница? Кроме того, что аргументы передадутся не в адресной строке?
#216 #1087620
>>1087608
Сук, я же написал, что перменные "обнуляются" при завершении скрипта.
Новый запрос -> новый запуск скрипта -> новые данные. -> скрипт обработал данные -> скрипт завешился -> память освободилась
>>1087608

> использовать глобальную переменную


Почитай про глобальные и суперглобальные переменные в пыхе.

>>1087609

>аргументы


Да, гет параметры имеют ограниченный лимит, так что если хочешь что-то сохраниль надо использовать пут
#217 #1087635
>>1087446

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


>>1087446

> Почему он не выполнил down()



а down() не пустой?
39 Кб, 884x446
#218 #1087640
>>1087635
не пустой
#219 #1087646
>>1087640
Хммм, хуй знает.
Вообще миграции немного косячно сделаны, так что если нету в таблице миграций этой миграции можешь просто удалить сам файл миграции и таблицу которую он создал.
#220 #1087650
#221 #1087685
>>1087646
так в итоге и поступил.
И ошибку которая выпадала тоже исправил. Но почему он не делает down(), если какой-то запрос ошибочный - так и не понял.

Ошибка заключалась в том, что в таблице genus создалась sub_family_id со значениями 0. Потом создалась сама таблица sub_family, пустая. А когда попытался связать их - вылезла ошибка. Означает: у меня тут sub_family_id=0, но в sub_family нету записи с таким значением. Решил добавлением 3 и 4 строчек
#222 #1087725
>>1087685

> down()


Он работает только если ты down, миграция нормально прошла.
И down и delete migration это разные вещи
#223 #1087756
https://ideone.com/MTucMz

Что за 1? Что он пишет? Он ебанутый?
#224 #1087758
https://ideone.com/HYYh2z

Он показывает количество совпадений что-ли?
Числа прописью #226 #1087764
Доброаноны, проверьте, пожалуйста, задачу: https://repl.it/NiJx/15
#227 #1087765
https://ideone.com/4IRNDa

Как сделать, чтобы при замене preg_replace не удалялся символ?
Нужно добавить пробел между запятой и буквой, но он удаляет и запятую и букву.
#228 #1087771
>>1087765
У ОПа написано в мануале. Оттуда:
Если попытаться разбить строку на предложения с помощью preg_split, то знаки в конце предложения потеряются, так как preg_split вырезает из строки захваченные регуляркой (соответствующие ей) символы. Для борьбы с этим можно использовать утверждения в регулярках, которые не захватывают символ, а только проверяют его наличие перед или после определенного места. Например: preg_split("/(?<=\d)/u", "12abc3") разобьет строку по всем позициям, перед которыми стоит цифра; это даст массив ['1', '2', 'abc3', '']. Последний элемент массива появился из-за того что регулярка сработала после цифры 3, а так как за ней символов нет, получилась пустая строка. Избавиться от нее можно с помощью флага PREG_SPLIT_NO_EMPTY, подробности в мануале.
#229 #1087774
>>1087765
>>1087771
Пардон, не то написал. Проверь регулярное выражение. $1 в preg_replace представляет символы, заключенные в первые круглые скобки в регулярном выражении. У тебя же скобок нет.
#230 #1087831
>>1087093
а если напрямую ссылаться на Кровать, то как из ВариантаКровати доставать цвет и изображение?
#231 #1087865
Заинтересовало как в сосденем треде обсуждают то, как с помощью картинки отслеживать открытия писем.
https://2ch.hk/pr/res/1087462.html (М)

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

Когда все урлы вида:
http://my-srv.ua/emailback/HAEX2ZOH.jpg
http://my-srv.ua/emailback/NAE2BAL3.jpg
http://my-srv.ua/emailback/MAMHAKER.jpg

обрабатываешь, собираешь вот этот вот код "HAEX2ZOH"
и отдаешь картинку.
#232 #1087888
>>1087756

>preg_match() возвращает 1


Когда научитесь читать ёбана?
#233 #1087927
>>1087888
Я читаю, но забываю некоторые моменты.
#234 #1087928
>>1087865
Какой ещё подмены картинки?
#235 #1087972
Как в Symfony с помощью CollectionType сделать так, чтобы можно было либо выбрать из коллекции сущностей, например, размеры уже имеющиеся или создать новый размер в этой же форме?
#236 #1087973
>>1087972
ой, не Collection, а EntityType
#237 #1087976
#238 #1088366
Какие паттерны лучше изучать первыми начинающему?
#239 #1088651
Опыч, ты видел это?
https://drafts.csswg.org/css-egg-1/
#240 #1088653
>>1088651

>1 April 2015


>1 April

#241 #1088654
>>1088653
Они за 2 года не убрали?
#242 #1088661
>>1088653
Вот видите, целую страницу сделали как шутку. А вы, проКАСТинаторы!
#243 #1088673
Сап.
Есть цель создать div или табличку с рамочкой, и от рамочки провести линию к другой такой рамочке. Что-то типа пикрила только не такое красочное. Линии будут идти либо вниз, либо в сторону, либо вниз, потом поворачивать под углом 90 градусов в сторону.
Как лучше сделать? Второй пик примерно то, что я хочу в итоге получить.
Вопрос именно в генерации линий и есть ли возможнось их так строить?
#244 #1088717
>>1088673
Тебе для чего? Для сайта, в общем веба? Мне на ум пришел GraphML. Это язык написания графов в XML.
Можно сделать и в HTML с CSS но рисовать каждый раз с помощью блоков и делать трансформ тебе надоест, если ты не такой поехавший верстальщик как я.
Еще можно использовать SVG для этого, но проще все же ссылки ниже.
http://sigmajs.org/
http://fperucic.github.io/treant-js/
http://arborjs.org/
https://d3js.org/
648 Кб, 750x500
#245 #1088748
Вопрос по архитектуре приложения: использовать ли логику в SQL или только как тупое хранилище данных?

Есть два стула: https://pastebin.com/hJSzwBNx

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

Передаю 2 параметра: дату начала месяца и дату для которой получаем номера.

На выходе от PDO массив:

[
'employee' => 'invoiceNumber',
...
]

Хорошо, быстро, удобно.

Но! если я захочу что-то поменять в будущем (например имена переменных), мне придется править всё с самого дна, начиная с TDG.

Можно использовать второй вариант: выбирать ВСЕ записи за интересующий промежуток времени и рассчитывать уже специальным сервисом в PHP, который опять же будет возвращать тот же массив.

Но теперь, если надо поменять логику, я не лезу в TDG, а лезу в сервис ("сервис" это я имею в виду может быть методом сущности "накладная" например. Там, где эти данные и нужны). Код всегда под рукой.

Надеюсь понятно объяснил. И таких ситуаций полно: когда можно сделать больше SQL кода, но меньше PHP.

Так использовать логику в SQL или это тупое животное —
хранилище данных?
648 Кб, 750x500
#245 #1088748
Вопрос по архитектуре приложения: использовать ли логику в SQL или только как тупое хранилище данных?

Есть два стула: https://pastebin.com/hJSzwBNx

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

Передаю 2 параметра: дату начала месяца и дату для которой получаем номера.

На выходе от PDO массив:

[
'employee' => 'invoiceNumber',
...
]

Хорошо, быстро, удобно.

Но! если я захочу что-то поменять в будущем (например имена переменных), мне придется править всё с самого дна, начиная с TDG.

Можно использовать второй вариант: выбирать ВСЕ записи за интересующий промежуток времени и рассчитывать уже специальным сервисом в PHP, который опять же будет возвращать тот же массив.

Но теперь, если надо поменять логику, я не лезу в TDG, а лезу в сервис ("сервис" это я имею в виду может быть методом сущности "накладная" например. Там, где эти данные и нужны). Код всегда под рукой.

Надеюсь понятно объяснил. И таких ситуаций полно: когда можно сделать больше SQL кода, но меньше PHP.

Так использовать логику в SQL или это тупое животное —
хранилище данных?
#246 #1088769
>>1088673
Graphviz -> svg -> profit
#247 #1088794
Сейчас делал прогу по заданию с палиндромом, обосрался от удивления, когда все сразу, с первого раза заработало. Попытался вводить разные значения - всегда верно определяет, где палиндром, а где нет. С трудом верю в то, что так просто написал эту прогу, поэтому прошу найти очевидные ошибки, если таковые имеются и различные замечания: https://ideone.com/GSEBqe

(ссылку дал на идеон, чтобы вы видели код, но на идеоне он не включается, из-за ошибки с mb_internal_encoding("UTF-8");, на phptester.net все работает.)
#248 #1088798
>>1088794

>Сейчас делал прогу


25 строк?
#249 #1088801
>>1088798
Ну не цепляйся к словам. Сделал задание.
#250 #1088817
>>1088801

> Сделал задание.



software architect уже
#251 #1088819
>>1088801

>Сделал задание


25 строк исполняется прямо в мозгу, можно на бумаге писать
#252 #1088844
Как быть: есть товары с разными размерами фотографий, но надо расположить их в каталоге в одинаковых размеров блоках. Пока в голову пришло только сделать белый блок, внутри которого уже изображения, тогда пропорции сохраняются и размер не превышает этот блок. Примерно так на Ebay сделано, как я понял, так как пользователи разных размеров фото заливают. Как это сделали на Авито? Я так понял, просто при заливе фото, они создают версию с разрешением 208x156, но почему-то пропорции не выглядит похеренными, или это из-за маленького размера так?
#253 #1088921
Аноны, хочу научиться верстать, верхов html, css и js нахватался, посмотрел пару видео по теме, но все же не пойму откуда начинать. Подскажите дебилу, плз, разобраться в этой теме.
#254 #1088953
>>1088921

>не пойму откуда начинать



с левого верхнего угла
#255 #1089016
>>1088748
вот хороший вопрос. это я так понимаю простой пример, но более интересно в контексте высоконагруженных проектов.

плюсы использования ЯП понятны, а вот какие есть плюсы у логики в sql-запросах?
#256 #1089025
>>1088794
очевидная ошибка в слове length. форматирование довольно странное тоже.

плюс по семантике правильнее делать так:

$initialData = ...;

$someReferenceData = // тут вычисления всякие
if ($initialData !== $someReferenceData) {
echo 'false':
} else {
echo 'true';
}

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

Вот я бы как решил, если предположить, что нельзя использовать функции:

$text = "А роза упала на лапу Азора";

$text = str_replace(" ","", $text);
$text = mb_strtolower($text);
$reverse = implode('', array_reverse(preg_split("//u", $text, -1, PREG_SPLIT_NO_EMPTY)));

if ($text !== $reverse) {
echo "Не палиндром";
}
else {
echo "палиндром";
}

можно было бы вместо преобразования в массив и обратно использовать strrev, если бы она поддерживала многобайтную кодировку, но увы.
#256 #1089025
>>1088794
очевидная ошибка в слове length. форматирование довольно странное тоже.

плюс по семантике правильнее делать так:

$initialData = ...;

$someReferenceData = // тут вычисления всякие
if ($initialData !== $someReferenceData) {
echo 'false':
} else {
echo 'true';
}

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

Вот я бы как решил, если предположить, что нельзя использовать функции:

$text = "А роза упала на лапу Азора";

$text = str_replace(" ","", $text);
$text = mb_strtolower($text);
$reverse = implode('', array_reverse(preg_split("//u", $text, -1, PREG_SPLIT_NO_EMPTY)));

if ($text !== $reverse) {
echo "Не палиндром";
}
else {
echo "палиндром";
}

можно было бы вместо преобразования в массив и обратно использовать strrev, если бы она поддерживала многобайтную кодировку, но увы.
#257 #1089200
>>1089025
Да, твое решение получилось гораздо более разумным и логичным, но выходящим, на данный момент, за рамки моих знаний.

>$reverse = implode('', array_reverse(preg_split("//u", $text, -1, PREG_SPLIT_NO_EMPTY)));


Сейчас нужно будет хорошенько разобраться и понять эту строчку.
Спасибо за ответ.
#258 #1089202
>>1088748

В данном случае стоит завести колонку с названием "номер", дополнительно можно попробовать сделать уникальный ключ, гарантирующий уникальность номеров в пределах месяца. Это если месяц-год записан тоже в виде отдельной колонки, так как mysql не позволяет делать индексы по выражениям.

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

Твой подход имеет недостаток:

- при удалении документа номера всех идущих далее изменятся
- запрос с подзапросами переусложненный и неэффективный, там джойны какие-то, которые совсем не нужны (переменную проще было создать через SET @x = 0).

> Но! если я захочу что-то поменять в будущем (например имена переменных), мне придется править всё с самого дна, начиная с TDG.


Это в любом случае придется делать.

> Можно использовать второй вариант: выбирать ВСЕ записи за интересующий промежуток времени и рассчитывать уже специальным сервисом в PHP, который опять же будет возвращать тот же массив.


Довольно неэффективно, брать кучу записей и откидывать большую часть.

> выбирать ВСЕ записи за интересующий промежуток времени и рассчитывать уже специальным сервисом в PHP, который опять же будет возвращать тот же массив.


Вообще-то нет. Выбирать все записи за месяц не надо, достаточно узнать номер первой выбранной записи с начала месяца с помощью запроса SELECT COUNT.
#259 #1089218
>>1088921

В ОП посте есть задачи по HTML/CSS, начиная с совсем простых, и заканчивая полноценной версткой.

>>1088844

На практике эту задачу удобнее решать средствами CSS. Там есть такие возможности для ограничения размера изображений: max-width, max-height. Обрати внимание, что width/height при этом надо выставлять в auto, иначе возможна ситуация, когда пропорции изображения будут искажены.

Увеличивать растровые изображения (если они очень маленькие) не надо, так как они мылятся, можно только уменьшать.

Если пропорции картинки не соответствуют пропорциям окошка, ее надо в нем отцентрировать, чтобы это аккуратно смотрелось. Есть 2 варианта:

1) уменьшить картинку так, что в одном из измерений она соответствует окошку, а в другом больше, и отрезать выступающую часть
2) уменьшить картинку так, что в одном из измерений она соответствует окошку, а в другом меньше, и появляются поля

(еще есть вариант сделать размеры окошка не фиксированными, а меняющимися от X до Y, что позволит в большинстве случаев показать картинку целиком).

Для центрирования есть несколько методов:

- выводить картинку как фоновую с помощью background, ограничить размеры с помощью background-size
- использовать translate
- использовать translate 2 раза
- использовать object-fit
- использовать display table-cell
- может быть, flexbox ?

Для каждого варианта нужно сделать пример верстки (с картинками разных пропорций), изучить достоинства и недостатки (например в случае фоновой картинки она может не индексироваться поисковиками), проверить по caniuse, с какого года метод поддерживается в браузерах, при желании проверить еще через modern.ie/browsershots, проверить, поддерживается ли srcset с этим методом. Уверен, что проделанная работа не только поможет тебе в изучении CSS, но и не раз пригодится в верстке.

Поговорим еще про размеры картинок и превьюшек. Если пользователь загружает большую картинку, какого размера превьюшки надо делать? Какую из них использовать?

Это конечно зависит от верстки. В идеале, мы бы хотели делать превьюшки только тех размеров, которые используются в дизайне. Но на практике это сложно по 2 причинам:

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

Размер превьюшки в идеале должен точно соответствовать размеру "окошка" под картинку, чтобы не было масштабирования и связанных с ним искажений. Если это невозможно (размер окошка жестко не задан), то нужно иметь набор превьюшек таких размеров, чтобы не требовалось слишком сильное уменьшение (так как иначе придется скачивать слишком большую картинку, и она займет больше памяти).

Потому обычно превьюшки делаются как геометрическая прогрессия. Ну например, где каждая картинка в 2 раза меньше: 1024, 512, 256, 128. Можно использовать и другой шаг прогрессии. Размеры конечно можно подправить, чтобы они были ближе к используемым в дизайне (если у тебя например есть окошко размером 400px, то и превьюшки стоит делать такими же). При этом используя атрибут srcset, ты можешь указать ссылки на все имеющиеся превьюшки и браузер сам выберет подходящую в зависимости от требуемого разрешения. Советую изучить и использовать этот атрибут, он незаменим при адаптивной верстке. Обрати внимание, что srcset не будет работать с фоновыми картинками, только с тегом img.
#259 #1089218
>>1088921

В ОП посте есть задачи по HTML/CSS, начиная с совсем простых, и заканчивая полноценной версткой.

>>1088844

На практике эту задачу удобнее решать средствами CSS. Там есть такие возможности для ограничения размера изображений: max-width, max-height. Обрати внимание, что width/height при этом надо выставлять в auto, иначе возможна ситуация, когда пропорции изображения будут искажены.

Увеличивать растровые изображения (если они очень маленькие) не надо, так как они мылятся, можно только уменьшать.

Если пропорции картинки не соответствуют пропорциям окошка, ее надо в нем отцентрировать, чтобы это аккуратно смотрелось. Есть 2 варианта:

1) уменьшить картинку так, что в одном из измерений она соответствует окошку, а в другом больше, и отрезать выступающую часть
2) уменьшить картинку так, что в одном из измерений она соответствует окошку, а в другом меньше, и появляются поля

(еще есть вариант сделать размеры окошка не фиксированными, а меняющимися от X до Y, что позволит в большинстве случаев показать картинку целиком).

Для центрирования есть несколько методов:

- выводить картинку как фоновую с помощью background, ограничить размеры с помощью background-size
- использовать translate
- использовать translate 2 раза
- использовать object-fit
- использовать display table-cell
- может быть, flexbox ?

Для каждого варианта нужно сделать пример верстки (с картинками разных пропорций), изучить достоинства и недостатки (например в случае фоновой картинки она может не индексироваться поисковиками), проверить по caniuse, с какого года метод поддерживается в браузерах, при желании проверить еще через modern.ie/browsershots, проверить, поддерживается ли srcset с этим методом. Уверен, что проделанная работа не только поможет тебе в изучении CSS, но и не раз пригодится в верстке.

Поговорим еще про размеры картинок и превьюшек. Если пользователь загружает большую картинку, какого размера превьюшки надо делать? Какую из них использовать?

Это конечно зависит от верстки. В идеале, мы бы хотели делать превьюшки только тех размеров, которые используются в дизайне. Но на практике это сложно по 2 причинам:

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

Размер превьюшки в идеале должен точно соответствовать размеру "окошка" под картинку, чтобы не было масштабирования и связанных с ним искажений. Если это невозможно (размер окошка жестко не задан), то нужно иметь набор превьюшек таких размеров, чтобы не требовалось слишком сильное уменьшение (так как иначе придется скачивать слишком большую картинку, и она займет больше памяти).

Потому обычно превьюшки делаются как геометрическая прогрессия. Ну например, где каждая картинка в 2 раза меньше: 1024, 512, 256, 128. Можно использовать и другой шаг прогрессии. Размеры конечно можно подправить, чтобы они были ближе к используемым в дизайне (если у тебя например есть окошко размером 400px, то и превьюшки стоит делать такими же). При этом используя атрибут srcset, ты можешь указать ссылки на все имеющиеся превьюшки и браузер сам выберет подходящую в зависимости от требуемого разрешения. Советую изучить и использовать этот атрибут, он незаменим при адаптивной верстке. Обрати внимание, что srcset не будет работать с фоновыми картинками, только с тегом img.
#260 #1089287
Анон, помоги, как вставить recaptcha в эту гребаную форму? Чтобы при нажатии на саммит, если не введена каптча, ничего не отправлялось?

Вот код:

require_once __DIR__ . '/recaptchalib.php';
// Введите свой секретный ключ
$secret = "6LfEpcUAAAAAEQiimHo_Q2eaVrtbJ5-jcLi1a";
// пустой ответ каптчи
$response = null;
// Проверка вашего секретного ключа
$reCaptcha = new ReCaptcha($secret);
if ($_POST["g-recaptcha-response"]) {
$response = $reCaptcha->verifyResponse(
$_SERVER["REMOTE_ADDR"],
$_POST["g-recaptcha-response"]
);
}

$mail_to = 'mTBgailANUSm SjailPUNCTUMrn6?u';

if(isset($_POST['name'])){$name ='Имя: '.$_POST['name'].';';}
if(isset($_POST['Phone'])){$Phone = 'Телефон: '.$_POST['Phone'].';';}
if(isset($_POST['Email'])){$Email = 'Email: '.$_POST['Email'].';';}
if(isset($_POST['Text'])){$Text = 'Сообщение:'.$_POST['Text'].';';}

$thm = "Новая заявка с сайта sibstrop.ru";
$msg = $name." \r\n".$Phone." \r\n".$Email." \r\n".$Text ;
$picture = "";

// Если поле выбора вложения не пустое - закачиваем его на сервер
if (!empty($_FILES['file']['tmp_name']))
{
// Закачиваем файл
$path = $_FILES['file']['name'];
if (copy($_FILES['file']['tmp_name'], $path)) $picture = $path;
}

// Отправляем почтовое сообщение
if(empty($picture)) mail($mail_to, $thm, $msg);
else send_mail($mail_to, $thm, $msg, $picture);

// Вспомогательная функция для отправки почтового сообщения с вложением (Trianon)
function send_mail($mail_to, $thema, $html, $path)
{ if ($path) {
$fp = fopen($path,"rb");
if (!$fp)
{ print "Cannot open file";
exit();
}
$file = fread($fp, filesize($path));
move_uploaded_file($path, "/upload");
fclose($fp);
}
$name = $path; // в этой переменной надо сформировать имя файла (без всякого пути)
$EOL = "\r\n"; // ограничитель строк, некоторые почтовые сервера требуют \n - подобрать опытным путём
$boundary = "--".md5(uniqid(time())); // любая строка, которой не будет ниже в потоке данных.
$headers = "MIME-Version: 1.0;$EOL";
$headers .= "Content-Type: multipart/mixed; boundary=\"$boundary\"$EOL";
$headers .= "From: 8=z:768787ANUSratio.timewef3RbPUNCTUMrE8Cu";

$multipart = "--$boundary$EOL";
$multipart .= "Content-Type: text/html; charset=utf-8$EOL";
$multipart .= "Content-Transfer-Encoding: base64$EOL";
$multipart .= $EOL; // раздел между заголовками и телом html-части
$multipart .= chunk_split(base64_encode($html));

$multipart .= "$EOL--$boundary$EOL";
$multipart .= "Content-Type: application/octet-stream; name=\"$name\"$EOL";
$multipart .= "Content-Transfer-Encoding: base64$EOL";
$multipart .= "Content-Disposition: attachment; filename=\"$name\"$EOL";
$multipart .= $EOL; // раздел между заголовками и телом прикрепленного файла
$multipart .= chunk_split(base64_encode($file));

$multipart .= "$EOL--$boundary--$EOL";

if(!mail($mail_to, $thema, $multipart, $headers, $response))

{return False; //если не письмо не отправлено
}
else { //// если письмо отправлено
return True;
}
exit;
}
unlink ($path);
header("Location: kontakti.html");

?>
#260 #1089287
Анон, помоги, как вставить recaptcha в эту гребаную форму? Чтобы при нажатии на саммит, если не введена каптча, ничего не отправлялось?

Вот код:

require_once __DIR__ . '/recaptchalib.php';
// Введите свой секретный ключ
$secret = "6LfEpcUAAAAAEQiimHo_Q2eaVrtbJ5-jcLi1a";
// пустой ответ каптчи
$response = null;
// Проверка вашего секретного ключа
$reCaptcha = new ReCaptcha($secret);
if ($_POST["g-recaptcha-response"]) {
$response = $reCaptcha->verifyResponse(
$_SERVER["REMOTE_ADDR"],
$_POST["g-recaptcha-response"]
);
}

$mail_to = 'mTBgailANUSm SjailPUNCTUMrn6?u';

if(isset($_POST['name'])){$name ='Имя: '.$_POST['name'].';';}
if(isset($_POST['Phone'])){$Phone = 'Телефон: '.$_POST['Phone'].';';}
if(isset($_POST['Email'])){$Email = 'Email: '.$_POST['Email'].';';}
if(isset($_POST['Text'])){$Text = 'Сообщение:'.$_POST['Text'].';';}

$thm = "Новая заявка с сайта sibstrop.ru";
$msg = $name." \r\n".$Phone." \r\n".$Email." \r\n".$Text ;
$picture = "";

// Если поле выбора вложения не пустое - закачиваем его на сервер
if (!empty($_FILES['file']['tmp_name']))
{
// Закачиваем файл
$path = $_FILES['file']['name'];
if (copy($_FILES['file']['tmp_name'], $path)) $picture = $path;
}

// Отправляем почтовое сообщение
if(empty($picture)) mail($mail_to, $thm, $msg);
else send_mail($mail_to, $thm, $msg, $picture);

// Вспомогательная функция для отправки почтового сообщения с вложением (Trianon)
function send_mail($mail_to, $thema, $html, $path)
{ if ($path) {
$fp = fopen($path,"rb");
if (!$fp)
{ print "Cannot open file";
exit();
}
$file = fread($fp, filesize($path));
move_uploaded_file($path, "/upload");
fclose($fp);
}
$name = $path; // в этой переменной надо сформировать имя файла (без всякого пути)
$EOL = "\r\n"; // ограничитель строк, некоторые почтовые сервера требуют \n - подобрать опытным путём
$boundary = "--".md5(uniqid(time())); // любая строка, которой не будет ниже в потоке данных.
$headers = "MIME-Version: 1.0;$EOL";
$headers .= "Content-Type: multipart/mixed; boundary=\"$boundary\"$EOL";
$headers .= "From: 8=z:768787ANUSratio.timewef3RbPUNCTUMrE8Cu";

$multipart = "--$boundary$EOL";
$multipart .= "Content-Type: text/html; charset=utf-8$EOL";
$multipart .= "Content-Transfer-Encoding: base64$EOL";
$multipart .= $EOL; // раздел между заголовками и телом html-части
$multipart .= chunk_split(base64_encode($html));

$multipart .= "$EOL--$boundary$EOL";
$multipart .= "Content-Type: application/octet-stream; name=\"$name\"$EOL";
$multipart .= "Content-Transfer-Encoding: base64$EOL";
$multipart .= "Content-Disposition: attachment; filename=\"$name\"$EOL";
$multipart .= $EOL; // раздел между заголовками и телом прикрепленного файла
$multipart .= chunk_split(base64_encode($file));

$multipart .= "$EOL--$boundary--$EOL";

if(!mail($mail_to, $thema, $multipart, $headers, $response))

{return False; //если не письмо не отправлено
}
else { //// если письмо отправлено
return True;
}
exit;
}
unlink ($path);
header("Location: kontakti.html");

?>
#261 #1089288
Ищу готовую библиотеку для визуального редактирования содержимого таблиц в бд. Под ларавел или стандалон. Гугол не помогает.
Что-нибудь типа Voyager, или простихоспади phpmyadmin, только очень лайтовое. Чтобы никаких операций со стурктурой бд и таблиц, никаких пользователей с миллионом отдельных прав для редактрования каждой запятой, никаких html-редакторов страничек.
Просто морда и контроллер для crud операций с таблицей, в идеале поставил библиотеку, указал ей в какой базе какие таблицы какие поля нужно трогать, и всё. Есть такое? Вроде обыденная задача, а готовых решений без персонального массажиста и психоаналитика в комплекте найти не могу.
#262 #1089306
>>1089287

Ты мануал по recaptcha или по используемой библиотеке читал? Там нет ответа?
#263 #1089308
>>1088817

Не надо оставлять такие бессмысленные комментарии, да еще и несколько раз. Троллить иди в другой тред.

>>1088794

Тут наверно нет смысла укорачивать строку после каждой буквы:

> $text = mb_substr ($text, 1);



Лучше просто в начале цикла брать i-ю по счету букву из строки. А так, работает верно.

>>1088673

Проще всего генерировать SVG, он поддерживается очень давно, и если что, конвертируется в обычный PNG.

Впрочем, можно и на дивах сделать при очень большом желании.

>>1088651

Шутки шутками, но обратите внимание на довольно выразительную HTML-разметку в примере:

> <div class=celestial-body id=mercury data-color=lightgray


data-radius=0.0081ls data-semimajor-axis=193ls data-orbital-period=6.278ftn></div>

> animation: orbit linear infinite attr(data-orbital-period time, 0);



Видите, как можно представлять информацию о каких-то сущностях с помощью атрибутов. Разумеется, эти атрибуты можно далее использовать и в CSS, и в JS коде.

>>1088366

Паттерны сами по себе в вакууме начинающий вряд ли поймет. Какой смысл использовать фабрику, если можно просто использовать new?

Паттерны наверно лучше изучать на примерах использования. Возьми справочник паттернов, возьми какой-нибудь компонент Симфони (например Symfony Forms, учти, что они сложные) и поищи там используемые паттерны. И попробуй ответить, зачем тут использован паттерн вместо более простого кода.

Алсо, статья https://habrahabr.ru/post/153225/
#263 #1089308
>>1088817

Не надо оставлять такие бессмысленные комментарии, да еще и несколько раз. Троллить иди в другой тред.

>>1088794

Тут наверно нет смысла укорачивать строку после каждой буквы:

> $text = mb_substr ($text, 1);



Лучше просто в начале цикла брать i-ю по счету букву из строки. А так, работает верно.

>>1088673

Проще всего генерировать SVG, он поддерживается очень давно, и если что, конвертируется в обычный PNG.

Впрочем, можно и на дивах сделать при очень большом желании.

>>1088651

Шутки шутками, но обратите внимание на довольно выразительную HTML-разметку в примере:

> <div class=celestial-body id=mercury data-color=lightgray


data-radius=0.0081ls data-semimajor-axis=193ls data-orbital-period=6.278ftn></div>

> animation: orbit linear infinite attr(data-orbital-period time, 0);



Видите, как можно представлять информацию о каких-то сущностях с помощью атрибутов. Разумеется, эти атрибуты можно далее использовать и в CSS, и в JS коде.

>>1088366

Паттерны сами по себе в вакууме начинающий вряд ли поймет. Какой смысл использовать фабрику, если можно просто использовать new?

Паттерны наверно лучше изучать на примерах использования. Возьми справочник паттернов, возьми какой-нибудь компонент Симфони (например Symfony Forms, учти, что они сложные) и поищи там используемые паттерны. И попробуй ответить, зачем тут использован паттерн вместо более простого кода.

Алсо, статья https://habrahabr.ru/post/153225/
#264 #1089310
>>1087972

В документации информации нету? https://symfony.com/doc/current/reference/forms/types/collection.html

>>1087756

preg_match возвращает число совпадений с регуляркой в строке, но он останавливается на первом совпадении, потому может вернуть только 0 или 1, или false, если регулярка или строка некорректная.

> $mail[] =


Тут тоже ошибка, ты зачем-то создаешь пустой массив и первым элементом в него добавляешь результат функции. Нужно было писать просто $result = ....

Тебе нужна preg_match_all, и надо прочесть официальный мануал по ней. Там можно передать в функцию пустой массив, и она его заполнит информацией о совпадениях (согласен, очень неинтуитивно сделано).

>>1087865

"механизм подмены картинки" заключается в настройке сервера так, чтобы при обращении по определенному URL вызывался PHP скрипт.

>>1087831

У меня ВариантКровати содержит информацию о цвете, размере и содержит ссылку на ВнешнийВид (который ссылается на изображения). А вообще, связи в доктрине можно делать двухсторонними, так что связанные сущности получить не проблема.

>>1087764

> if (($number1 == 1) && ($number2 != 1)){


> $word = $word1;


Можно сразу было писать return $word1;

> $second = $spelling[$second];


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

> unset($numbers[2]);


Этот код легко сломать, если в массиве выше добавить лишний элемент. Лучше делать по-другому, примерно так:

Если (в числе есть сотни) {
добавить в массив слово для сотен;
}

Если (число кончается на 11-19) {
добавить соответствующее слово;
}

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

> if ($number == 'рублей'){


> $number = 'ноль рублей';


Здесь тоже не очень удачно сделано, ты зря анализируешь строку, лучше сравнивать числа. Достаточно регистр букв поменять или пробел добавить, и проверка не сработает. Можно просто в начале функции написать:

Если (число == 0) {
вернуть 'ноль рублей';
}

В остальном, верно.
#264 #1089310
>>1087972

В документации информации нету? https://symfony.com/doc/current/reference/forms/types/collection.html

>>1087756

preg_match возвращает число совпадений с регуляркой в строке, но он останавливается на первом совпадении, потому может вернуть только 0 или 1, или false, если регулярка или строка некорректная.

> $mail[] =


Тут тоже ошибка, ты зачем-то создаешь пустой массив и первым элементом в него добавляешь результат функции. Нужно было писать просто $result = ....

Тебе нужна preg_match_all, и надо прочесть официальный мануал по ней. Там можно передать в функцию пустой массив, и она его заполнит информацией о совпадениях (согласен, очень неинтуитивно сделано).

>>1087865

"механизм подмены картинки" заключается в настройке сервера так, чтобы при обращении по определенному URL вызывался PHP скрипт.

>>1087831

У меня ВариантКровати содержит информацию о цвете, размере и содержит ссылку на ВнешнийВид (который ссылается на изображения). А вообще, связи в доктрине можно делать двухсторонними, так что связанные сущности получить не проблема.

>>1087764

> if (($number1 == 1) && ($number2 != 1)){


> $word = $word1;


Можно сразу было писать return $word1;

> $second = $spelling[$second];


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

> unset($numbers[2]);


Этот код легко сломать, если в массиве выше добавить лишний элемент. Лучше делать по-другому, примерно так:

Если (в числе есть сотни) {
добавить в массив слово для сотен;
}

Если (число кончается на 11-19) {
добавить соответствующее слово;
}

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

> if ($number == 'рублей'){


> $number = 'ноль рублей';


Здесь тоже не очень удачно сделано, ты зря анализируешь строку, лучше сравнивать числа. Достаточно регистр букв поменять или пробел добавить, и проверка не сработает. Можно просто в начале функции написать:

Если (число == 0) {
вернуть 'ноль рублей';
}

В остальном, верно.
#265 #1089311
>>1087759

> foreach ($mail as $m) {


> print_r($m);


Ты разобрался с форматом массива $mail? Проверь мануал, это довольно важно. Например, в твоем случае не нужно использовать цикл, а нужно было написать $mail[0].

Алсо, твоя регулярка не ищет email с минусом, например iv99@an-da-maryaANUSex5bJamplePUNCTUMcoHGqm

Также, не ищутся email c длинными доменами:

iqHtvanANUSabc.de@{4f.ghiPUNCTUMcKhcom
ivaN8znANUSaK11bc-def-ghiPUNCTUMcou{ m

Погугли, какие символы допустимы в имени домена.

> \w{2,5}


Есть TLD (домен верхнего уровня) .museum, и по моему, еще более длинные:

- https://ru.wikipedia.org/wiki/Домен_верхнего_уровня
- (список) http://www.iana.org/domains/root/db

>>1087758

Да, посмотри внимательно мануал http://php.net/manual/ru/function.preg-match-all.php

>>1087446

В теории, миграция должна либо быть выполнена целиком (и это зафиксировано в таблице миграций), либо не выполнена. То есть при ошибке в середине миграции в теории изменения должны отмениться. Но! MySQL не поддерживает транзакции для DDL (data definition language) запросов (вроде ALTER TABLE), потому с mysql, если миграция упала посередине, то база останется в поломанном состоянии и ты должен самостоятельно, вручную откатить изменения. (пруф в мануале https://dev.mysql.com/doc/refman/5.7/en/implicit-commit.html )

Кстати, другие СУБД вроде Postgres поддерживают транзакции для DDL: https://wiki.postgresql.org/wiki/Transactional_DDL_in_PostgreSQL:_A_Competitive_Analysis

Соответственно, в твоем случае откатывать изменения надо руками или восстанавливать из бекапа. Либо переделать систему миграций, чтобы она как-то фиксировала каждый выполненный запрос и потом могла их по одному откатывать.

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

> Почему он не выполнил down(), чтобы вернуть всё на прежние места?


Потому что down() можно вызывать, только если up() успешно выполнилась. Она ведь не может сама понять, какую часть запросов надо выполнять.

> Мне просто взять и удалить файл Version20171105082042.php ?


Либо удалить либо исправить в нем косяки.

> Ошибка заключалась в том, что в таблице genus создалась sub_family_id со значениями 0


Это странно, а не логичнее там было разрешить значение NULL, если для сущности не указана sub_family? Потом, если надо, можно заименить NULL на реальные значения и поменять тип на NOT NULL. То есть не стоило тут полагаться на автогенерацию (которая как я понимаю, дропнула колонку, не перенеся значения в новую колонку сначала), а стоило проверить и подправить код руками.

В любом случае, не надо вместо NULL использовать 0 и создавать несуществующую сущность с id = 0.
#265 #1089311
>>1087759

> foreach ($mail as $m) {


> print_r($m);


Ты разобрался с форматом массива $mail? Проверь мануал, это довольно важно. Например, в твоем случае не нужно использовать цикл, а нужно было написать $mail[0].

Алсо, твоя регулярка не ищет email с минусом, например iv99@an-da-maryaANUSex5bJamplePUNCTUMcoHGqm

Также, не ищутся email c длинными доменами:

iqHtvanANUSabc.de@{4f.ghiPUNCTUMcKhcom
ivaN8znANUSaK11bc-def-ghiPUNCTUMcou{ m

Погугли, какие символы допустимы в имени домена.

> \w{2,5}


Есть TLD (домен верхнего уровня) .museum, и по моему, еще более длинные:

- https://ru.wikipedia.org/wiki/Домен_верхнего_уровня
- (список) http://www.iana.org/domains/root/db

>>1087758

Да, посмотри внимательно мануал http://php.net/manual/ru/function.preg-match-all.php

>>1087446

В теории, миграция должна либо быть выполнена целиком (и это зафиксировано в таблице миграций), либо не выполнена. То есть при ошибке в середине миграции в теории изменения должны отмениться. Но! MySQL не поддерживает транзакции для DDL (data definition language) запросов (вроде ALTER TABLE), потому с mysql, если миграция упала посередине, то база останется в поломанном состоянии и ты должен самостоятельно, вручную откатить изменения. (пруф в мануале https://dev.mysql.com/doc/refman/5.7/en/implicit-commit.html )

Кстати, другие СУБД вроде Postgres поддерживают транзакции для DDL: https://wiki.postgresql.org/wiki/Transactional_DDL_in_PostgreSQL:_A_Competitive_Analysis

Соответственно, в твоем случае откатывать изменения надо руками или восстанавливать из бекапа. Либо переделать систему миграций, чтобы она как-то фиксировала каждый выполненный запрос и потом могла их по одному откатывать.

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

> Почему он не выполнил down(), чтобы вернуть всё на прежние места?


Потому что down() можно вызывать, только если up() успешно выполнилась. Она ведь не может сама понять, какую часть запросов надо выполнять.

> Мне просто взять и удалить файл Version20171105082042.php ?


Либо удалить либо исправить в нем косяки.

> Ошибка заключалась в том, что в таблице genus создалась sub_family_id со значениями 0


Это странно, а не логичнее там было разрешить значение NULL, если для сущности не указана sub_family? Потом, если надо, можно заименить NULL на реальные значения и поменять тип на NOT NULL. То есть не стоило тут полагаться на автогенерацию (которая как я понимаю, дропнула колонку, не перенеся значения в новую колонку сначала), а стоило проверить и подправить код руками.

В любом случае, не надо вместо NULL использовать 0 и создавать несуществующую сущность с id = 0.
#266 #1089312
>>1087650

> избавьте нас от Мор ов!


Наверно, не надо было пробелы с краев захватывать.

> \W\s


Вообще-то \W включает в себя пробельные символы и \s не нужен

> [АаAa][Ии]


Тут лучше было написать "А или И", а не "А, за ней И"

В остальном верно.

>>1087584

Для начала я бы советовал почитать, как вообще взаимодействуют браузер, веб-сервер и интерпретатор PHP: https://github.com/codedokode/pasta/blob/master/soft/web-server.md

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

Соответственно, если ты хочешь сохранить данные между запусками, то надо использовать: параметры в URL, скрытые поля в форме, куки, сессии, файлы, базу данных, в зависимости от задачи.

Также, советую прочесть про протокол HTTP: https://github.com/codedokode/pasta/blob/master/network/http.md

>>1087609

Погугли, в чем разница между POST и GET. Ну как вообще можно браться что-то делать, не изучив основы сначала. GET запрос не должен менять ничего на сервере.

>>1087307

Да, надо изучить основы SQL.

>>1087245

В preg-функциях флага g нету. Он есть только на regex101 и в других языках, вроде JS.
#266 #1089312
>>1087650

> избавьте нас от Мор ов!


Наверно, не надо было пробелы с краев захватывать.

> \W\s


Вообще-то \W включает в себя пробельные символы и \s не нужен

> [АаAa][Ии]


Тут лучше было написать "А или И", а не "А, за ней И"

В остальном верно.

>>1087584

Для начала я бы советовал почитать, как вообще взаимодействуют браузер, веб-сервер и интерпретатор PHP: https://github.com/codedokode/pasta/blob/master/soft/web-server.md

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

Соответственно, если ты хочешь сохранить данные между запусками, то надо использовать: параметры в URL, скрытые поля в форме, куки, сессии, файлы, базу данных, в зависимости от задачи.

Также, советую прочесть про протокол HTTP: https://github.com/codedokode/pasta/blob/master/network/http.md

>>1087609

Погугли, в чем разница между POST и GET. Ну как вообще можно браться что-то делать, не изучив основы сначала. GET запрос не должен менять ничего на сервере.

>>1087307

Да, надо изучить основы SQL.

>>1087245

В preg-функциях флага g нету. Он есть только на regex101 и в других языках, вроде JS.
#267 #1089330
Скок анон потратил на прохождения гайда?
#268 #1089339
>>1089288
Бамп. Ковыряю эти ларавеловские убожества, и какие же они убогие, нахуя их так много наклепали, абсолютно все однотипные, абсолютно все используют AdminLTE, абсолютно все стараются втиснуть в своё убожество как можно больше свистелок.
#269 #1089340
>>1089287
Бамп
#270 #1089343
>>1089339
попизди мне тут. За свистоперделки и плотют.

мимо Lavarel-senior architect
#271 #1089403
>>1089306
Читал, но не понимаю ничего. Помогите!
#272 #1089430
>>1089343
Да пущай плотють, что мне, жалко штоле. Я интересуюсь, может есть готовое решение без них. Для моих задач не нужны все эти конструкторы конструкторов админки, риалтаймовые графики нагрузки на сервер и прочие редактирование самих таблиц-столбцов с морды человек который может работать с бд только с веб-морды вообще не должен туда лезть.
392 Кб, 1000x708
#273 #1089439
>>1089202
Идея как раз в том, чтобы не создавать излишние поля типа "таймштамп дата день месяц год век эра ..." только для того, чтобы делать по ним выборку. А как выбирать? Алгоритмы? Возможно, Вы мыслите в плане больших нагруженных проектов, где каждая миллисекунда имеет смысл.

По поводу вопроса. Как я понял Ваш ответ — "нужны быстрые простые запросы, затрагивающие как можно меньше строк"?


По поводу кода:
1) Мне это число не нужно хранить, оно вообще нигде не используется кроме вью на печать. Придется как-то генерировать его,

>гарантировать уникальность номера



2) Что сделать с уже существующими данными? Мне придется как-то добавить им всем их номера.

3)

>при удалении документа номера всех идущих далее изменятся



Правда Ваша. По счастью мы перед печатью закрываем день, так что данные нельзя далее изменять.
#274 #1089464
>>1082507 (OP)
двач, как я могу объединить второй и третий запрос в один?

$sql ="INSERT INTO `vers_kopf` (`user`, `department`, `date`, `salesarea`, `materialtype`, `status`, `reason`, `bemerkung`, `transportschnr`, `qmauftragsnr`, `qmmeldungsnr`, `gesamtkosten`)
VALUES ('$Usr','$Dep', '$Dat','$Sal','$Mat','$Sta','$Rea','$Bem','$Tra','$Qma', '$Qmm', '$Ges');";

$sql .= "INSERT INTO `vers_pos` (`id_kopfdaten`, `materialnr`, `index`, `benennung`, `menge`, `preiseinheit`, `wert`, `fertigungskonto`, `sapbeleg`, `kostenstelle`)
VALUES ( '$material', '$index', '$benennung', '$menge', '$preispr, '$wert', '$fertigkonto', '$sapBeleg', '$kostenstelle');";

$sql .="INSERT INTO `vers_pos` (`id_kopf`) SElECT `id` FROM `vers_kopf`";
это мульти квери, если что. И всё остальное работает, нужно только вот это объединить
#275 #1089481
Решаю задачу про палиндром .Чо не так?
https://ideone.com/Np6Gkl
#276 #1089522
Задачи про основы ООП из ОП гайда. У меня есть абстрактный класс Сотрудник, у него есть метод ПолучитьЗП и конструктор, всё это дело в моей голове наследуется дочерними классами типа Манагер, Инженер этц, то есть в итоге я создаю новый объект вроде ma2 = new Manager(2); и ранк этого объекта-менеджера переопределяется, всё круто. Но когда я вызываю метод ma2->получитьЗп() то оно не работает, а точнее возвращает 0. Сам метод я не переопределял, но у меня такое ощущение как-будто он обращается не к полям манагера, а полям абстрактного класса, хоть это по идее и невозможно. Надеюсь на помощь анона.
#277 #1089529
>>1089522
Если я дублирую(переопределяю) метод в дочернем классе, то всё работает. Но ведь по логике даже если я не буду определять его в дочернем классе, то он по дефолту там есть невидимый и точно такой же как в абстрактном?
#278 #1089577
>>1089522
код бы скинул целиком, хз как с такой картинкой работать.
#279 #1089578
>>1089522
>>1089529
По аналогии с твоим ОПИСАНИЕМ у меня всё работает.
https://ideone.com/iVPhZj
#280 #1089593
>>1089578
>>1089577
Буквально сейчас пока писал простыню, увидел что поля то к разным классам относятся, я еще думал мол как моя приватная переменная из абстрактного класса может общаться с приватной переменной из дочернего, ну я protected ебанул И ОНО ЗАРАБОТАЛО. Я просто изначально немного иначе представлял это наследование, но теперь всё вроде бы ок.
#281 #1089604
>>1089578
https://ideone.com/hxGC9G
Я пытался сделать что-то в таком духе, как же я ошибался.
#282 #1089625
>>1089308

>Алсо, статья https://habrahabr.ru/post/153225/


очень смеялся, когда читал. я сейчас нахожусь в той стадии развития, когда пытаюсь быть таким, как первый чувак (типа делать все "правильно", "по уму"). и это приводит иногда к потере контроля над кодом и к панике.
#283 #1089627
Объясните, пожалуйста, в каком момент я дико обосрался, делая задание из ОП гайда, про школьника с айпадом:
https://ideone.com/uVB15L
Что не так с моим циклом? Кроме того что он, наверняка, в таком виде нахуй не нужен
#284 #1089642
>>1089593

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

Пример:

class A {
// обращаться к $x можно в коде от сюда
private $x;
....

public function doSmth() {
$this->x = 1;
}

// и до сюда
}

При этом наследование и откуда вызвана функция тут ни на что не влияет. Если мы применим наследование:

class B extends A { }
$b = new B;
$b->doSmth(); // все ок

То этот код тоже будет работать, так как мы вызываем метод doSmth, описанный в классе A, и поэтому он имеет доступ к приватному полю класса A.

Вот еще более интересный пример:

class C extends A {
private $x; // это не то же самое поле, что было в классе A, хоть оно и называется так же

public function callC() {
$this->x = 2;
}
}
$c = new C;
$c->doSmth(); // метод класса A, работает с полем класса A
$c->callC(); // работает с полем из класса С

Важно понять на этих примерах такие вещи:

- приватная переменная доступна только в одном классе и никак не видна снаружи. Это как бы внутреннее поле класса, к которому никто, кроме него, не может получить доступ
- границы, в которых видны приватные/protected поля, определяются именно границами класса, неважно, откуда и как вызван метод.

И еще насчет наследования. Не очень правильно говорить, что при наследовании методы из предка как-то копируются в наследник. Ничего никуда не копируется. Просто при вызове метода или обращении к полю оно ищется во всех классах, начиная от наследника, и заканчивая самым дальним предком. При этом, разумеется, идет проверка, откуда идет обращение и модификатора доступа private/protected/public (попытка обратиться снаружи к приватному полю вызовет ошибку).
#284 #1089642
>>1089593

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

Пример:

class A {
// обращаться к $x можно в коде от сюда
private $x;
....

public function doSmth() {
$this->x = 1;
}

// и до сюда
}

При этом наследование и откуда вызвана функция тут ни на что не влияет. Если мы применим наследование:

class B extends A { }
$b = new B;
$b->doSmth(); // все ок

То этот код тоже будет работать, так как мы вызываем метод doSmth, описанный в классе A, и поэтому он имеет доступ к приватному полю класса A.

Вот еще более интересный пример:

class C extends A {
private $x; // это не то же самое поле, что было в классе A, хоть оно и называется так же

public function callC() {
$this->x = 2;
}
}
$c = new C;
$c->doSmth(); // метод класса A, работает с полем класса A
$c->callC(); // работает с полем из класса С

Важно понять на этих примерах такие вещи:

- приватная переменная доступна только в одном классе и никак не видна снаружи. Это как бы внутреннее поле класса, к которому никто, кроме него, не может получить доступ
- границы, в которых видны приватные/protected поля, определяются именно границами класса, неважно, откуда и как вызван метод.

И еще насчет наследования. Не очень правильно говорить, что при наследовании методы из предка как-то копируются в наследник. Ничего никуда не копируется. Просто при вызове метода или обращении к полю оно ищется во всех классах, начиная от наследника, и заканчивая самым дальним предком. При этом, разумеется, идет проверка, откуда идет обращение и модификатора доступа private/protected/public (попытка обратиться снаружи к приватному полю вызовет ошибку).
#285 #1089645
>>1089593

Вот, кстати, причина, почему правила доступа работают именно так. Это сделано для того, чтобы код можно было разбить на независимые части (классы) и рассмтаривать их в отдельности от остального кода. Если у тебя есть приватное поле, то это значит что тебе не надо изучать весь код, чтобы понять, откуда в него могут что-то записать - тебе достаточно посмотреть один класс.

Это позволяет делать какие-то гарантии. Ну например, мы можем сделать гарантию, что в приватное поле "возраст" будет записано число от 1 до 100, за счет того, что доступ к нему возможен только изнутри класса, и в этом классе мы ставим проверку перед записью. То есть автор класса может задавать ограничения, гарантии, которые будут беспрекословно соблюдаться. И это делает код более надежным.

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

Ну и изучать код проще - когда ты хочешь использовать класс, тебе не надо смотреть на приватные поля и методы, а только на публичные, которых обычно меньше.
18 Кб, 769x298
#286 #1089816
совсем тупой вопрос может быть.но в уроках ОП такая фигня
ошибка в синтаксисе, почему именно там только?
14 Кб, 783x230
#287 #1089822
запостил!
#288 #1089934
Есть кто может помочь разобраться с гитом? Винда 10 если что.
#289 #1089951
>>1089934
есть
10 Кб, 755x44
#290 #1089954
>>1089816
потому что гладиолус?

>>1089934

>Винда 10


не имеет значения, соснольные команды те же самые
http://rgblog.ru/page/git-dlja-chajnika-komandy-kotorye-pomogut-nachat-rabotu
#291 #1089998
>>1089954
>>1089951
Я может не понимаю, но как свой гит привязать к репозиторию? Я делаю то, что показано в этом учебнике https://git-scm.com/book/ru/v1/Основы-Git-Создание-Git-репозитория
И не работает ни один способ. Я просто не авторизовывался нигде, и не понимаю как. У меня мой гит-баш ничего не просит. Ввел только в конфиг username и email.
105 Кб, 889x453
#292 #1090027
>>1089998

>не работает ни один способ


да ладно
https://github.com/wryyyyyyyy/wtf
#293 #1090087
>>1090027
Я понимаю, что там описаны действующие способы. Но у меня не работает, и я не понимаю, что я делаю не так.
#294 #1090092
>>1090087
если тебе и скриншот не помог, то кидай лог своих действий, будем изучать
#295 #1090159
>>1082507 (OP)
Вопрос от нуба: можно ли в PHP указывать ввод значения, без создания html-формы?
Ну т.е. как в Pascale, где ты просто указываешь read( x) и все.
#296 #1090166
>>1082507 (OP)
Из темы про ООП

https://ideone.com/12rfhf
Зачем создавать второй объект, который идентичен первому?

>// Создаем второй объект


$q = new Question;

Чувствую себя очень тупым, извините за глупый вопрос, если что.
...
#297 #1090168
>>1090166
Один объект класса Question представляет собой ОДИН вопрос в тесте. У нас 3 вопроса - значит, надо создать 3 объекта.
#298 #1090170
>>1090168
Спасибо большое, дошло
#299 #1090171
>>1089308
Слух ОП, я CSS22 прочел всю, вроде там особо ничего нет, даже в VFM https://www.w3.org/TR/CSS22/visuren.html написано не густо, нежели чем в CSS3 драфтах. Я конечно понимаю, что это знать всё не обязательно, но мне хочется узнать что и как работает, ибо действительно приступая к практике многое не понимаешь и делаешь ошибки, хотя в спецификациях все ясно описано. Так что я думаю примкну к части CSS3 и буду подглядывать в CSS2 когда буду работать над адаптацией к старым версиям.
Появилась проблема, я параллельно точно так же решил разобраться с HTML5, читаю вступление и первый раз вижу:

>This document is probably not suited to readers who do not already have at least a passing familiarity with Web technologies, as in places it sacrifices clarity for precision, and brevity for completeness.


Вот тут строчка прям говорит: Если ты не знаешь как все устроено, ты ничего не поймешь. И вот я думаю, типо нужно знать как работает и с помощью чего интернет? Т.е навернуть параллельно литературы по устройству сети и коммуникациям (Доходя до битов). Вот ты ОП, наверняка это все знаешь? Или я параноик?

>More approachable tutorials and authoring guides can provide a gentler introduction to the topic.


In particular, familiarity with the basics of DOM is necessary for a complete understanding of some of the more technical parts of this specification. An understanding of Web IDL, HTTP, XML, Unicode, character encodings, JavaScript, and CSS will also be helpful in places but is not essential.
Тут говорят уже точно, что нужно быть хотя бы знакомым с принципами технологии. Я просмотрел WEB IDL и понял, что это лучше спросить, отложить на будущее, потому что там судя по всему нужно знать скрипт, уж очень он похож. Потом перешел читать HTTP, даже будучи зная принцип его работы письма вроде все просто, однако угадай, где я начал читать? https://tools.ietf.org/html/rfc7235. Потом наткнулся на https://tools.ietf.org/html/ и оказалось, что там более миллиона этих спецификации, как будто описание паттернов, вавилон какой то. Я так понимаю нужно действовать так, если видишь какую либо технологию (Как наверняка адвокаты работают с делом о паттернах) HTML, CSS, JS, то в официальных драфтах как это делают W3 они сами скажут, что желательно знать, ведь так? Все изучать не обязательно же, потихоньку, со временем?
Впринципе в стандартизацию C или C++ я не лез, все по книжке узнавал.
#299 #1090171
>>1089308
Слух ОП, я CSS22 прочел всю, вроде там особо ничего нет, даже в VFM https://www.w3.org/TR/CSS22/visuren.html написано не густо, нежели чем в CSS3 драфтах. Я конечно понимаю, что это знать всё не обязательно, но мне хочется узнать что и как работает, ибо действительно приступая к практике многое не понимаешь и делаешь ошибки, хотя в спецификациях все ясно описано. Так что я думаю примкну к части CSS3 и буду подглядывать в CSS2 когда буду работать над адаптацией к старым версиям.
Появилась проблема, я параллельно точно так же решил разобраться с HTML5, читаю вступление и первый раз вижу:

>This document is probably not suited to readers who do not already have at least a passing familiarity with Web technologies, as in places it sacrifices clarity for precision, and brevity for completeness.


Вот тут строчка прям говорит: Если ты не знаешь как все устроено, ты ничего не поймешь. И вот я думаю, типо нужно знать как работает и с помощью чего интернет? Т.е навернуть параллельно литературы по устройству сети и коммуникациям (Доходя до битов). Вот ты ОП, наверняка это все знаешь? Или я параноик?

>More approachable tutorials and authoring guides can provide a gentler introduction to the topic.


In particular, familiarity with the basics of DOM is necessary for a complete understanding of some of the more technical parts of this specification. An understanding of Web IDL, HTTP, XML, Unicode, character encodings, JavaScript, and CSS will also be helpful in places but is not essential.
Тут говорят уже точно, что нужно быть хотя бы знакомым с принципами технологии. Я просмотрел WEB IDL и понял, что это лучше спросить, отложить на будущее, потому что там судя по всему нужно знать скрипт, уж очень он похож. Потом перешел читать HTTP, даже будучи зная принцип его работы письма вроде все просто, однако угадай, где я начал читать? https://tools.ietf.org/html/rfc7235. Потом наткнулся на https://tools.ietf.org/html/ и оказалось, что там более миллиона этих спецификации, как будто описание паттернов, вавилон какой то. Я так понимаю нужно действовать так, если видишь какую либо технологию (Как наверняка адвокаты работают с делом о паттернах) HTML, CSS, JS, то в официальных драфтах как это делают W3 они сами скажут, что желательно знать, ведь так? Все изучать не обязательно же, потихоньку, со временем?
Впринципе в стандартизацию C или C++ я не лез, все по книжке узнавал.
#300 #1090172
https://ideone.com/HO1cOf

Это как так у меня 326 получается?
#301 #1090174
>>1090172
У тебя цикл
пока X > 0 т.е 10 > 0
x = 10 / 10 = 1
i++
запускаем цикл еще раз ибо он положительный
1 > 0
x = 1 / 10 = 0,1
i++ уже 3
еще раз
0,1 > 0
x = 0,1 / 10 = 0,01
Нутыпонял
#302 #1090175
>>1090174
Черт. А разве тут не должно быть деление без остатка?
#303 #1090176
>>1090174
Блядь, и где мои манеры...

Спасибо, анон! Добра тебе.
#304 #1090177
>>1090175
А у тебя там обозначение сего есть?
#305 #1090178
>>1090177
Да драть меня... Да. Поставил % вместо / и все заработало.
#306 #1090179
>>1090177
Пользуясь моментом, хочу спросить вот это. Я уже нашел форму для ввода числа, но все-таки.
>>1090159
#307 #1090180
>>1090159
Вот этого не знаю, сам не пыхарь, а больше сишник.
Но я думаю можно, потому что насколько я знаю HTML то форма это визуальное представление серверной части, включая соединение ее с ней. Больше уверен что в ПХП без нее можно обойтись, потому что а как иначе?
Но подожди ОПа, он ответит более ясно.
#308 #1090181
>>1090180
Я то пока разбирался прочитал, что ПХП вообще не работает с дровами клав.
#309 #1090182
>>1090181
Типа 100% серверный язык да? Я вот еще прочитал http://php.net/manual/en/tutorial.forms.php т.е в PHP без HTML данные не ввести?
#310 #1090183
>>1090180
О, и ещё нюанс. Как правильно сделать вывод чисел через запятую?
Я сделал так
echo $i , ",";
Но мне кажется, что это не самый лучший выход.
>>1090182
Я сам выполняю тестовое задание, чтобы пойти на вакансию с зп от 16к рубликов, так что ни в коей мере не хочу стать тем, кто даст тебе неверную информацию, но единственный вариант, который я нашел был с формой в виде HTML кода.

Чтобы не плодить множество файлов, я сделал передачу результата ввода в расположенный в том же файле ПХП-код.
#311 #1090184
>>1090183
Можно создать вывод после каждой итерации цикла, типа так:
цикл
инкремент
ввод ","
цикл
инкремент
...
#312 #1090185
>>1090184
Кстати, а есть какая-либо встроенная функция, которая может определить количество разрядов числа?
#313 #1090186
>>1090185
Разрядов числа это в смысле разделение на дроби и целые части и подсчитать их количество?
#314 #1090187
>>1090186
Нет. В смысле, вот есть число 100. Оно состоит из единиц, десятков и сотен. 3 разряда.

У меня задача:
Определять, сколько в числе разрядов и выводить только те, что кратны своему количеству.
Ну т.е. все однозначные (т.к. все они делятся на 1), все четные двузначные и так далее.

Пока вот что придумал:

<?php
$x = $_POST ['x'];
$i = 0;
//начинаем выводить числа. от 0 и до числа, заданного пользователем
for ($i = 0; $count <= $x ; $i++ ){
//выясняем количество разрядов в числе
$g = $i;
while ($g >0) {
$g=$g%10;
$i++;
}
А вот как сделать проверку на целостное деление - хз. В паскале я делал n mod k = 0, а тут не найду нигде.
#315 #1090188
>>1090171

Это они отправляют совсем нубов читать учебники. Но по моему опыту, описано там все как раз довольно подробно, и если что-то описано в другой спецификации, то там стоят ссылки на нее.

Я впрочем в спецификации обычно смотрел какие-то отдельные вопросы и главы, вроде того, как работает какое-то свойство, или как рассчитываются размеры элементов. Целиком я по моему их никогда и не читал.

> вроде там особо ничего нет, даже в VFM


А на какой вопрос ты не нашел ответ?

> но мне хочется узнать что и как работает


Это хорошая идея и это поможет тебе делать верстку быстрее, если ты заранее понимаешь, как будет вести себя тот или иной элемент.

> Если ты не знаешь как все устроено, ты ничего не поймешь.


Это просто формальный отказ от ответственности, мол, мы не виноваты, если вы ничего не поймете без N лет опыта написания браузеров. Обрати внимание, там еще дописано " will also be helpful in places but is not essential"

> WEB IDL


IDL значит Interface Definition Language - язык для описания интерфейсов. Интерфейс - это понятие из ООП, это описание набора действий, которые можно сделать с объектом. IDL это не кокретный язык, а общее название для таких языков, а вот Web IDL - это конкретный язык, который использован в спецификации. Я никогда не читал спецификацию по нему, но я его понимаю интуитивно.

Когда браузер разбирает HTML-код страницы, он строит соответствующее ему дерево DOM, где каждый узел дерева соответствует тегу в исходном коде. В веб-страницы можно встраивать скрипты на JS (а может и на других языках), и эти скрипты могут работать с деревом DOM, например, меняя какие-то свойства элементов, за счет этого, к примеру, скрывая или показывая элемент на экране. IDL в спецификации описывает, какие свойства и методы должны быть у этих узлов дерева DOM.

Вот кусочек описания на IDL из спеки:

https://www.w3.org/TR/html5/embedded-content-0.html#the-img-element

> interface HTMLImageElement : HTMLElement {


> attribute DOMString src;


> attribute unsigned long width;


> attribute unsigned long height;



Здесь interface HTMLImageElement - это название интерфейса, который описывает объект DOM, соответствующий тегу <img>, и написано что он унаследован (то есть расширяет) интерфейс HTMLElement.

Этот код говорит о том, что у элементов DOM, которые представляют картинку (тег <img>), есть (в дополнение к базовым из HTMLElement) еще свойства src (в котором хранится строка) и width/height (в которых хранятся беззнаковые числа). Если ты будешь изучать JS, то вот основы DOM: https://learn.javascript.ru/dom-nodes Если ты пока не знаком с JS, то можешь смело пропускать эти интерфейсы.

> [NamedConstructor=Image


А это говорит о том, что объект DOM можно создать в JS дополнителньо с помощью конструктора с именем Image.

Что касается HTTP, я нескромно предложу прочесть мой краткий урок, думаю, для чтения спецификации HTML/CSS этого хватит: https://github.com/codedokode/pasta/blob/master/network/http.md

То есть тебе не надо целиком читать сторонние спецификации, достаточно смотреть в них ту часть, на которую стоит ссылка, если что-то непонятно.

Ну и еще раз нескромно напомню, что у меня в ОП посте есть задания по HTML/CSS, от простых к верстке полноценного макета.
#315 #1090188
>>1090171

Это они отправляют совсем нубов читать учебники. Но по моему опыту, описано там все как раз довольно подробно, и если что-то описано в другой спецификации, то там стоят ссылки на нее.

Я впрочем в спецификации обычно смотрел какие-то отдельные вопросы и главы, вроде того, как работает какое-то свойство, или как рассчитываются размеры элементов. Целиком я по моему их никогда и не читал.

> вроде там особо ничего нет, даже в VFM


А на какой вопрос ты не нашел ответ?

> но мне хочется узнать что и как работает


Это хорошая идея и это поможет тебе делать верстку быстрее, если ты заранее понимаешь, как будет вести себя тот или иной элемент.

> Если ты не знаешь как все устроено, ты ничего не поймешь.


Это просто формальный отказ от ответственности, мол, мы не виноваты, если вы ничего не поймете без N лет опыта написания браузеров. Обрати внимание, там еще дописано " will also be helpful in places but is not essential"

> WEB IDL


IDL значит Interface Definition Language - язык для описания интерфейсов. Интерфейс - это понятие из ООП, это описание набора действий, которые можно сделать с объектом. IDL это не кокретный язык, а общее название для таких языков, а вот Web IDL - это конкретный язык, который использован в спецификации. Я никогда не читал спецификацию по нему, но я его понимаю интуитивно.

Когда браузер разбирает HTML-код страницы, он строит соответствующее ему дерево DOM, где каждый узел дерева соответствует тегу в исходном коде. В веб-страницы можно встраивать скрипты на JS (а может и на других языках), и эти скрипты могут работать с деревом DOM, например, меняя какие-то свойства элементов, за счет этого, к примеру, скрывая или показывая элемент на экране. IDL в спецификации описывает, какие свойства и методы должны быть у этих узлов дерева DOM.

Вот кусочек описания на IDL из спеки:

https://www.w3.org/TR/html5/embedded-content-0.html#the-img-element

> interface HTMLImageElement : HTMLElement {


> attribute DOMString src;


> attribute unsigned long width;


> attribute unsigned long height;



Здесь interface HTMLImageElement - это название интерфейса, который описывает объект DOM, соответствующий тегу <img>, и написано что он унаследован (то есть расширяет) интерфейс HTMLElement.

Этот код говорит о том, что у элементов DOM, которые представляют картинку (тег <img>), есть (в дополнение к базовым из HTMLElement) еще свойства src (в котором хранится строка) и width/height (в которых хранятся беззнаковые числа). Если ты будешь изучать JS, то вот основы DOM: https://learn.javascript.ru/dom-nodes Если ты пока не знаком с JS, то можешь смело пропускать эти интерфейсы.

> [NamedConstructor=Image


А это говорит о том, что объект DOM можно создать в JS дополнителньо с помощью конструктора с именем Image.

Что касается HTTP, я нескромно предложу прочесть мой краткий урок, думаю, для чтения спецификации HTML/CSS этого хватит: https://github.com/codedokode/pasta/blob/master/network/http.md

То есть тебе не надо целиком читать сторонние спецификации, достаточно смотреть в них ту часть, на которую стоит ссылка, если что-то непонятно.

Ну и еще раз нескромно напомню, что у меня в ОП посте есть задания по HTML/CSS, от простых к верстке полноценного макета.
#316 #1090189
>>1090187
Все понял. Тут можно с помощью if сделать. Ну или свитч если у тебя есть, я PhP синтаксис не очень знаю, но у тебя все верно сделано. ОП пришел как раз, сейчас пояснит тебе все.
Всего доброго.
#317 #1090190
>>1090189
Приятных сновидений!
#318 #1090192
>>1090188

>А на какой вопрос ты не нашел ответ?


Вопрос появился только тогда, когда я начал читать CSS3 драфт. Получилось так, что в секции CSS3 определение Display Model отделено от VFM совсем.
Например сравни описание Box Model
https://drafts.csswg.org/css-box-3/
https://www.w3.org/TR/CSS22/box.html
Нет, конечно понятное дело, что это уровень 3 и вообще стандарт толком еще не принят и что в полном беспорядке. Но это не проблема, просто ориентироваться трудно.

>


Когда браузер разбирает HTML-код страницы, он строит соответствующее ему дерево DOM, где каждый узел дерева соответствует тегу в исходном коде. В веб-страницы можно встраивать скрипты на JS (а может и на других языках), и эти скрипты могут работать с деревом DOM, например, меняя какие-то свойства элементов, за счет этого, к примеру, скрывая или показывая элемент на экране. IDL в спецификации описывает, какие свойства и методы должны быть у этих узлов дерева DOM.
Аа вот оно как, я сам DOM пока даже не читал, слышал про скрипты и все в границах спецификации. Хмм щас более понятно стало.

> то можешь смело пропускать эти интерфейсы.


Это мне и надо было, спасибо!

>достаточно смотреть в них ту часть, на которую стоит ссылка, если что-то непонятно.


Вот это я и хотел делать.
Я еще задание по верстке не закончил, я тренировал селекторы и смотрел, что мог пропустить.
Ты мне еще ОП давал классификацию БЭМ, которую я пока не читал, голова и так жужжит от ингриша. Хотя я его с этими спецификациями подтянул знатно В общем пойду фундаментально под запись HTML изучать, ну и практиковаться.
Еще спросить хотел. Недавно вот наткнулся на Pong написанный с помощью классов CSS, не идеально получилось, но я вообще в шоке, без JS. Но там много кода, я так думаю свитч менюшек как в задании по макету это как замена JS (Временная) чтобы показать заказчику как функционирует тот или иной элемент? Просто мучаться с этими селекторами, писать кучу объемного кода, когда можно использовать JS используя пару функции, не проще ли? Я надеюсь правильно объяснил.
#318 #1090192
>>1090188

>А на какой вопрос ты не нашел ответ?


Вопрос появился только тогда, когда я начал читать CSS3 драфт. Получилось так, что в секции CSS3 определение Display Model отделено от VFM совсем.
Например сравни описание Box Model
https://drafts.csswg.org/css-box-3/
https://www.w3.org/TR/CSS22/box.html
Нет, конечно понятное дело, что это уровень 3 и вообще стандарт толком еще не принят и что в полном беспорядке. Но это не проблема, просто ориентироваться трудно.

>


Когда браузер разбирает HTML-код страницы, он строит соответствующее ему дерево DOM, где каждый узел дерева соответствует тегу в исходном коде. В веб-страницы можно встраивать скрипты на JS (а может и на других языках), и эти скрипты могут работать с деревом DOM, например, меняя какие-то свойства элементов, за счет этого, к примеру, скрывая или показывая элемент на экране. IDL в спецификации описывает, какие свойства и методы должны быть у этих узлов дерева DOM.
Аа вот оно как, я сам DOM пока даже не читал, слышал про скрипты и все в границах спецификации. Хмм щас более понятно стало.

> то можешь смело пропускать эти интерфейсы.


Это мне и надо было, спасибо!

>достаточно смотреть в них ту часть, на которую стоит ссылка, если что-то непонятно.


Вот это я и хотел делать.
Я еще задание по верстке не закончил, я тренировал селекторы и смотрел, что мог пропустить.
Ты мне еще ОП давал классификацию БЭМ, которую я пока не читал, голова и так жужжит от ингриша. Хотя я его с этими спецификациями подтянул знатно В общем пойду фундаментально под запись HTML изучать, ну и практиковаться.
Еще спросить хотел. Недавно вот наткнулся на Pong написанный с помощью классов CSS, не идеально получилось, но я вообще в шоке, без JS. Но там много кода, я так думаю свитч менюшек как в задании по макету это как замена JS (Временная) чтобы показать заказчику как функционирует тот или иной элемент? Просто мучаться с этими селекторами, писать кучу объемного кода, когда можно использовать JS используя пару функции, не проще ли? Я надеюсь правильно объяснил.
#319 #1090193
>>1090190
А у меня уже день...
#320 #1090194
Нужно выводить только числа, делящиеся на собственное количество разрядов.

https://ideone.com/Nl3tRZ

Почему-то все виснет.
#321 #1090196
>>1090192

По box model лучше прочесть наверно обе версии, а то можно запутаться. Но суть там в том, что из HTML кода создается соответствующее ему дерево DOM, а для отображения страницы из каждого узла дерева DOM создается от 0 до N прямоугольных боксов, которые затем отрисовываются на экране. 0 боксов создается, если например, элемент скрыт через display: none. Больше одного бокса создается, например, при наличии у элемента псевдоэлементов или при генерации анонимных боксов.

Ну и там же даются определения вроде content box, padding box и тд.

> Просто мучаться с этими селекторами, писать кучу объемного кода, когда можно использовать JS используя пару функции, не проще ли?


А не факт, что там будет пару функций. Скорее всего, там тот же jQuery понадобится, а без него будет громоздко. По идее как раз CSS должен быть проще, ну например, сделать показ блока при наведении средствами CSS гораздо проще чем мучаться с JS, так как в CSS мы описываем только желаемый вид в определенном состоянии. В итоге ты придешь к тому, что ты в JS будешь только доабвлять/убирать классы, а в CSS описывать их поведение.

Ну или например, в случае с реализацией переключателя CSS, у нас есть инпут, который можно использовать в форме, которым можно управлять с клавиатуры, а в случае JS это надо описывать все отдельно.

Можешь для сравнения попробовать сделать оба варианта, с и без JS, если есть время.
#322 #1090197
>>1090194
Погоди, а разве нельзя просто вывод запятой сделать так " ,"? (Пробел и запятая)?
#323 #1090198
>>1090197
Уважайте наши традиции.
поправил
#324 #1090199
>>1090196
Бокс модель я всю знаю, анонимные боксы, контент боксы, нормал флоу и т.д Я имел ввиду, то что W3 сейчас меняет расположение тем по другим местам. Display model теперь косвенно относится к VFM, хоть ее упоминание и остается в CSS2. Немного путает.
С другой стороны в CSS2 все складно и понятно. Я знаю конечно, что CSS3 это лишь бета версия, совершенно не готовая для публикации, там беспорядок.
#325 #1090200
>>1090197
echo $i , " ", ","; запятая после вывода числа?
1 ,2 ,3 ,4 ?
#326 #1090201
>>1090200
Ну, это не имеет значения, т.к. сервак тупо виснет при запросе на 10 первых чисел, делящихся на 1.
#327 #1090202
>>1090196
А да забыл добавить, какой мне JS если я толком верстку пока криво делаю? Или ты думаешь, что можно на стороне учить? Или... Я уже должен был потихоньку изучать его? Должен... Хмм.
#328 #1090203
>>1090201
Чот ОПыч тебе не отвечает. Ну смотри, ты там интересно сделал конеш. Мне кажется на 10 можно делить бесконечно, не тупит ли он из-за этого?
#329 #1090204
>>1090203

>Мне кажется на 10 можно делить бесконечно, не тупит ли он из-за этого?


Так я ж использую деление для определения количества разрядов. Типа, сколько раз число разделится на 10-ку, прежде чем от него останется 0.
И я ведь использую деление без остатка.
#330 #1090205
>>1090203
Уже успел проверить код. Проблема именно здесь:

$g = $i;
while ($g >0) {
$g=$g%10;
$n++;
}

Если заменить цикл на
$n=2;
То все работает.
#331 #1090207
Исправил!
Выкинул неисправный while нахуй и заменил его на преобразование числа в строку и подсчета элементов числа.
#332 #1090219
>>1090194
Код лютая хуита.

Очень долго объяснять, вот я тебе нормально зделол:
https://ideone.com/9n7p0E
#333 #1090220
>>1090207

>заменил его на преобразование числа в строку


Дегенерат, чо. Поздравляют!
#334 #1090241
>>1090220
Ну срать о том какой он умный каждый сможет, а ты покажи ошибку.
>>1090219

>CheckDenominationOnDigitsNumers


Чот проорал.
4 Кб, 383x126
#335 #1090242
>>1090092
Вот мне какой отказ вываливает на попытку клонировать репозиторий, что я не так делаю?
#336 #1090243
>>1090219
Блин, смотрю щас код этот, как же все похоже на Си, прям всё, как будто я уже PHP знаю (Ну не весь конеш, как и Си) но все так похоже... Единственное естественно я разницы глобальной не вижу, потому-что я еще личинка, но думаю в будущем почувствую. Хотя это серверный язык, там Системный.
#337 #1090261
>>1090242
Не может прочесть с удаленного хранилища. Пожалуйста убедитесь в корректности прав доступа и существований хранилища.
#338 #1090265
Оффтоп.


https://stackoverflow.com/jobs/139937/senior-front-end-developer-for-a-real-estate-web-allthings?so=i&pg=1&offset=21&q=symfony

Поискал тут пару минут заграничные вакансии и офигел. Нет, я конечно знал, что там лучше платят, но не знал, что на столько. Сам думаю, что нужно стремиться к лучшему, а именно - профессиональные знания в web-разработке и удалённая работа на заграничную компанию. А иначе так и буду двигать формы на битриксе за хорошую по российским меркам, но нищенскую по западным ЗП. ОП и люди, которые в этой сфере давно, что посоветуете?

У меня план примерно такой:
учу Symfony на уровне пользователя (знаю, что дать на вход методу и знаю, что получу от него)
учу Symfony на уровне разработчика (знаю что внутри этих методов, знаю ядро), параллельно изучая патерны и т.п.
Когда уже стану сеньёром, начинаю ебашить английский, ибо в этот момент уже можно позволить тратить на программирование поменьше времени и побольше на язык
Нахожу работу за бугром

Предположительный срок - 3-5 лет.

Т.к. сейчас мои размышления диванные, вероятно, я могу видеть вещи не такими, какие они есть. Для этого и написал сюда, чтобы получить фидбек
#339 #1090268
>>1090242
Я так понял ты на Шинус10 скачал эмулятор шлинкуса и собираешься с ним работать с комплаем min-gw64? Читал документацию по нему? Там мнооого, ооочень много написано, там такая большая вики, что как мне кажется, проще уж шлинукс вбить себе. Ну или с соснолью шины10 работать, хотя с другой стороны если там прям можно с гитом работать и сразу в репозиторий компить, то прикольно.
Я так понял это Cygwin да?
#340 #1090269
>>1090268 - ОП
Кстати я пока читал чуть не умер.
https://cygwin.com/faq.html
#341 #1090273
>>1090265
Как ты вообще собрался стать сеньором не зная английский?
#342 #1090274
>>1090196
ОП вот чего я боюсь, я хочу выучить фундаментально нотную грамоту, чтобы слышать звуки, а не просто копировать табы и прочее. Посмотри статью пожалуйста, если будет возможность: https://habrahabr.ru/post/342156/. Я параноик в этом плане.
#343 #1090283
>>1090273
Ну я не ноль ведь. Видеокурсы понимаю, документацию читаю, гуглю на английском.
53 Кб, 735x291
#344 #1090290
>>1090242

>что я не так делаю?


не читаешь описание git clone
#345 #1090302
>>1090283
Не проще ли выучить сначала ангельский, а потом не мучиться и с легкостью воспринимать инфу?
#346 #1090312
>>1090268
нет, не эмулятор отсюда https://git-scm.com/download/win скачал, через утилиту gtit-bash пытаюсь научиться.

>>1090290
Ок, я склонировал свой репозиторий в папку по https-ссылке, но всё равно не понимаю что дальше. Это же не связало клонированный реп с гитхабом, как мне связать репозиторий на гит-хабе, с папкой на компе?
12 Кб, 667x259
#347 #1090316
Хм, у меня стоит php 7.1.2. Может и прописать сюда 7.1.2? А то на 5.6 пыхе проект точно не заведётся, как минимум из-за callFunction([one,two]), про 7.0.0 не знаю
#348 #1090317
>>1090302
Так я не мучаюсь. Раз в час в словаре слово перевожу, а так всё норм понимаю
72 Кб, 985x358
#349 #1090328
>>1090312
инициализируй, измени, закоммить, добавь репу и можно пушить
#350 #1090340
>>1090328

>ализируй, измени, закоммить, добавь р


Пасиб, что-то получилось через https, сейчас попробую по ssh поковыряться.
#351 #1090353
Где можно найти свежие лекции всяких гарвардов по вебу? На ютубе находил только пяти-трехлетней давности.
#352 #1090356
>>1090265
Расскажи ньюфагам какие были твои знания когда тебя взял ковырять битрикс?
#353 #1090358
>>1090353
coursera, edx
#354 #1090359
Test
#355 #1090360
Парни, помогите, простой вопрос. В get запросе к серверу, какую роль играет timeout? В моём случаи он равен 10
И какой запрос нужно отравить, что бы получать от сервера нескончаемый ответ?
#356 #1090368
Парни, ну же, где вы.
#357 #1090377
>>1090356
На тот момент были сделаны Students и FileHosting из шапки треда. Но можно было и с меньшими знаниями устроиться.
Компания заебись, но Bitrix - основной инструмент с которым работаем. А душа лежит к прекрасному, вот и продолжил своё развитие спустя какого-то времени "прогаю только на работе"
#358 #1090381
>>1090377
Вот ты. Ответь на вопрос >>1090360
#359 #1090398
Блять, пидоры, как же вы бесите.
#360 #1090400
>>1090360

Если ты про протокол HTTP, то там нет "параметра" timeout. Следовательно, речь не о протоколе, а о какой-то библиотеке, название которой ты не написал (жаль), или скопированном откуда-то куске кода. Ответ нужно искать в документации по используемой библиотеке.

Могу предположить, что речь о каком-то таймауте (времени ожидания), например, время ожидания ответа от DNS сервера, максимальное время на установку TCP соединения, максимальное время ожидания HTTP ответа от сервера, это надо смотреть документацию по библиотеке.

Если ты хочешь исправить пробелы в своих знаниях, могу предложить почитать урок про HTTP: https://github.com/codedokode/pasta/blob/master/network/http.md

Перед тем, как его писать, я пробовал найти готовый и ничего, что бы меня устроило, не нашел.
#361 #1090403
>>1090400
У меня такая функция: array('http' => array('method' => 'GET','timeout' => 10 ))
#362 #1090405
>>1090400
Благодарю за ссылку, сейчас ознакомлюсь.
Моя задача такая, послать команду на сервер, что бы он мне слал в ответ переменные бесконечным потоком. Как предложишь решить эту задачу? Мне нужно быстро найти ответ на этот вопрос, углублять свои знания я буду чуть позже.
#363 #1090410
>>1090405

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

Для решения твоей задачи надо гуглить слова comet и websocket.
#364 #1090412
>>1090410
Там используется WAMP protocol
https://poloniex.com/support/api/
#365 #1090431
>>1090412

Так WAMP это и есть прикладной протокол поверх websocket. Ты бы хоть погуглил.
#366 #1090432
Бля, ну ёп вашу мать. Помогите кто-нибудь. Как сделать так, что бы сервер постоянно присылал тебе данные, а не запрос-ответ. Используя для этого WAMP protocol ?
#367 #1090433
>>1090431
Ну ок, что нужно в коде написать что бы оно работало так как мне нужно? Что сложного в том, что сервер постоянно тебе что то присылает?
41 Кб, 820x879
#368 #1090456
Хуле он кукарекает? Что не так на четвертой строке?
#369 #1090462
>>1090220
Пояснишь свое мнение или просто мудаком останешься?

>>1090219
Твое не подвходит по техзадание.
Вот что у меня https://ideone.com/7Out5M
#370 #1090470
Из темы про ООП в учебнике ОП'а.

// Функция, создающая массив с вопросами:
function createQuestions()
{
// Создаем пустой массив
$questions = [];

// Создаем и заполняем первый объект
$q = new Question;
$q->text = ...
...
// Кладем вопрос в массив
$questions[] = $q;

// Создаем второй объект
$q = new Question;
...

return $questions;
}

Я правильно понял, что функцию нужно дописать?
https://ideone.com/kJ04rh
#371 #1090472
>>1090456
особенности кастрации php силами ideone
https://ideone.com/OqKqWw
#372 #1090480
>>1090470
И правильно ли я дописал?
5 Кб, 151x151
instagram в рот ему ноги. #373 #1090485
Инстаграм может отдавать страницы в виде JSON
Пример
https://www.instagram.com/p/BbTLbYSH59J/?__a=1

Может кто знает, что значит поле media_preview

к примеру это tracking_token явно base64 и легко декодируется.
#374 #1090490
>>1090472
Ок, по крайней мере я понял что trim не подходит
#375 #1090493
Анон, подскажи. Если мне нужно написать скрипт, который будет трансформировать длинные ссылки в короткие, то мне в любом случае понадобится подключать SQL?
#376 #1090503
>>1090493
Ты можешь хранить все в файле.
#377 #1090508
Блять, какой же ебанутый этот ваш пиашпи, ни типов переменных, нихуя не понятно, переменные, структуры, какие-то блять ассоциативные массивы, всё в одной куче блять.
#378 #1090515
>>1090508
мне после пхп жс кажется адом прям. Тут по крайней мере есть ПСР, тайпхинты в функциях, а там вообще фарш.
#379 #1090518
>>1090508
бомбануло
PHP Unit #380 #1090534
Может кто-то пояснить нахуя нужны пхп тесты эти? Смотрю уроки и не пойму нахуй эта хуйня нужна
#381 #1090538
>>1090470
Как работает самая последняя строчка?
https://ideone.com/V96LgP
#382 #1090548
>>1090534
напиши один раз приложение или библиотечку и покрой тестами 100%, поймешь в чем прикол. вкратце, сразу начинаешь по-другому смотреть на ООП и много времени экономишь при поддержке и допиливании, т.к. не приходится вручную проверять весь функционал.

плюс все серьезные конторы с нормальными з/п требуют умения тдд, все равно не обойдешь их.
#383 #1090550
>>1090538
Я понял. Туплю немного. Простите
#384 #1090551
>>1090508
строгая типизация есть в 7, если что. плюс в аннотациях принято писать тип аргументов и возвращаемого значения. ассоциативные массивы не используй, если не нравится.
#385 #1090567
Никак не могу замкнуть все запросы на index.php. Точнее у меня получилось, но только, когда index.php лежит в корне, то есть в htdocs. Может есть какой-то хороший гайд по htaccess-у? Я перепробовал все, что нашел в гугле, но у меня все равно не получается.
#386 #1090577
>>1090534

Попробуй до кучи (нескромная реклама) почитать еще мой урок про тестирование: https://gist.github.com/codedokode/a455bde7d0748c0a351a

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

Целей несколько:

1) просто проверить, правильно ли написан код. Вот ты написал функцию форматирования номера телефона, а где гарантия, что она правильно работает? Ты скорее всего напишешь простой скрипт, который вызывает эту функцию, выводит результат, и глазами проверишь, что все верно. Если эту проверку глазами заменить на автоматическую, получится юнит-тест для функции. Хотя юнит-тест может быть даже проще - он может просто вызывать функцию и проверять, что не происходит каких-то ошибок. Аналогично с веб-страницами - ты сделал страницу регистрации и руками проверяешь, что она выдает ошибку при непраивльных данных и работает верно при правильных. Это тоже можно автоматизировать и получится приемочный тест. Ты написал API, и хочешь его проверить - это тоже автоматизируется.

Само по себе написание теста может занять больше времени, чем ручная проверка (хотя с опытом эта разница снижается и ты понимаешь, как протестировать тот или иной код максимально простым способом). Но у автоматизированного теста есть огромное преимущество - после того, как он написан, его можно запускать сколько угодно раз. Имея набор автоматизированных тестов, ты можешь поручить компьютеру хоть каждые 5 минут (или после любого изменения) тестировать все твое приложение. Вручную такое нереалистично - нужно нанять кучу людей. Отсюда вытекает преимущество 2:

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

Да даже если над проектом работаешь ты один - где гарантия, что ты не сломаешь код, который писался полгода назад? Без тестов это просто останется незамеченным.

3) тесты позволяют не бояться делать большие, сложные изменения и рефакторитинги. Представь опять же большой проект, и в нем ты хочешь например поменять везде кодировку с cp1251 на utf8. Имея тесты, ты легко можешь проверить, что после рефакторинга функционал приложения сохранился и все работает корректно.

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

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

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

Заметь, что тесты не обязаны быть сложными - даже самый простой тест (smoke test), который вызывает функцию или загружает страницу сайта, уже полезен и может обнаруживать ошибки.

Дальше в моем уроке.

Теорию конечно знать мало, потому предлагаю тебе взять какой-нибудь проект (можно тот, что ты сам делал, можно какой-нибудь open source проект) и покрыть его тестами.
#386 #1090577
>>1090534

Попробуй до кучи (нескромная реклама) почитать еще мой урок про тестирование: https://gist.github.com/codedokode/a455bde7d0748c0a351a

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

Целей несколько:

1) просто проверить, правильно ли написан код. Вот ты написал функцию форматирования номера телефона, а где гарантия, что она правильно работает? Ты скорее всего напишешь простой скрипт, который вызывает эту функцию, выводит результат, и глазами проверишь, что все верно. Если эту проверку глазами заменить на автоматическую, получится юнит-тест для функции. Хотя юнит-тест может быть даже проще - он может просто вызывать функцию и проверять, что не происходит каких-то ошибок. Аналогично с веб-страницами - ты сделал страницу регистрации и руками проверяешь, что она выдает ошибку при непраивльных данных и работает верно при правильных. Это тоже можно автоматизировать и получится приемочный тест. Ты написал API, и хочешь его проверить - это тоже автоматизируется.

Само по себе написание теста может занять больше времени, чем ручная проверка (хотя с опытом эта разница снижается и ты понимаешь, как протестировать тот или иной код максимально простым способом). Но у автоматизированного теста есть огромное преимущество - после того, как он написан, его можно запускать сколько угодно раз. Имея набор автоматизированных тестов, ты можешь поручить компьютеру хоть каждые 5 минут (или после любого изменения) тестировать все твое приложение. Вручную такое нереалистично - нужно нанять кучу людей. Отсюда вытекает преимущество 2:

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

Да даже если над проектом работаешь ты один - где гарантия, что ты не сломаешь код, который писался полгода назад? Без тестов это просто останется незамеченным.

3) тесты позволяют не бояться делать большие, сложные изменения и рефакторитинги. Представь опять же большой проект, и в нем ты хочешь например поменять везде кодировку с cp1251 на utf8. Имея тесты, ты легко можешь проверить, что после рефакторинга функционал приложения сохранился и все работает корректно.

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

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

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

Заметь, что тесты не обязаны быть сложными - даже самый простой тест (smoke test), который вызывает функцию или загружает страницу сайта, уже полезен и может обнаруживать ошибки.

Дальше в моем уроке.

Теорию конечно знать мало, потому предлагаю тебе взять какой-нибудь проект (можно тот, что ты сам делал, можно какой-нибудь open source проект) и покрыть его тестами.
#387 #1090580
У кого есть книги из шапки? Дайте плз.

>- По PHP: Профессиональное программирование на PHP Джордж Шлосснейгл


>- По PHP: Мэтт Зандстра — PHP: Объекты, шаблоны, методики программирования

#388 #1090589
>>1090577
Почему у меня сложилось впечатление, что я могу написать сам тест с ошибкой и таким образом теряется весь смысл тестирования?
#389 #1090590
>>1090589

Тут есть важный момент: тест не должен повторять логику работы тестируемого кода. Ну допустим, у тебя есть функция, которая ищет корень из числа. Ты не должен проверять ее аналогичным способом. Вместо этого надо, наоборот, возвести результат в квадрат и сравнить. Или найти заранее подготовленные и проверенные вручную пары чисел.

Или, если мы тестируем страницу добавления комментария, то мы делаем это так: заполняем форму, добавляем в комментарий уникальное число, отправляем ее, загружаем страницу и ищем в блоке комментариев это число (заодно можно посчитать еще их количество, но мне кажется, способ с числом универсальнее и не зависит от верстки).

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

То есть если писать тест правильно, то на практике ты с такой проблемой не столкнешься.

Опять же, кстати, хороший вопрос задал, ответ на который позволяет рассказать что-то полезное.

Этот подход кстати используется и в других отраслях - в авиации и космонавтике часто дублирующие друг друга узлы заказывают разным производителям.
#390 #1090593
>>1090590
Ладно, убедил. Но меня пожалуй уволят если я начну тратить время на покрывание тестами...
#391 #1090613
>>1090580

>Шлосснейгл


>>- По PHP: Мэтт Зандстра — PHP: Объекты, шаблоны, методики программирования


>>1090580
Они есть везде. Набери, например, в vk.com/docs
#392 #1090618
>>1090567

У тебя ведь Апач 2.4? Я пишу советы именно по нему, не по 2.2.

Вообще, есть мануал по Апачу, на англ, и там есть раздел про mod_rewrite: http://httpd.apache.org/docs/current/mod/mod_rewrite.html

Из русского есть такая статья: https://habrahabr.ru/company/sprinthost/blog/129560/

Для отладки можно добавить в конфиг Апача специальную директиву LogLevel rewrite:traceX как опсиано тут: http://httpd.apache.org/docs/current/mod/mod_rewrite.html#logging и тут http://httpd.apache.org/docs/current/mod/core.html#loglevel

Это включит режим отладки, в котором в лог будут писаться выполняемые действия по шагам. Может, они помогут найти причину ошибки.

>>1090470

Твой код выглядит правильно. Для проверки ты можешь вызвать функцию, сохранить ее результат в переменную и вывести ее с помощью var_dump(...) или print_r(...) - должна вывестись информация о всех вопросах.

>>1090538

> Как работает самая последняя строчка?



Вот эта?

> printQuestions($questions);



Она вызывает функцию printQuestions, передавая ей первым аргументом переменную $questions, которая содержит в себе массив из 3 элементов, значение каждого элемента массива - это объект класса Question.

Ну а функция циклом обходит массив, в этом цикле по очереди берется каждый объект-вопрос и на экран выводится информация, хранящаяся в нем.

>>1090534

Я еще вспомнил, тесты - они обычно повышают качество кода, так как у тебя постоянно тестируются отдельные компоненты (функции и классы), а также отдельные возможности приложения, и ошибки быстрее обнаруживаются.
#392 #1090618
>>1090567

У тебя ведь Апач 2.4? Я пишу советы именно по нему, не по 2.2.

Вообще, есть мануал по Апачу, на англ, и там есть раздел про mod_rewrite: http://httpd.apache.org/docs/current/mod/mod_rewrite.html

Из русского есть такая статья: https://habrahabr.ru/company/sprinthost/blog/129560/

Для отладки можно добавить в конфиг Апача специальную директиву LogLevel rewrite:traceX как опсиано тут: http://httpd.apache.org/docs/current/mod/mod_rewrite.html#logging и тут http://httpd.apache.org/docs/current/mod/core.html#loglevel

Это включит режим отладки, в котором в лог будут писаться выполняемые действия по шагам. Может, они помогут найти причину ошибки.

>>1090470

Твой код выглядит правильно. Для проверки ты можешь вызвать функцию, сохранить ее результат в переменную и вывести ее с помощью var_dump(...) или print_r(...) - должна вывестись информация о всех вопросах.

>>1090538

> Как работает самая последняя строчка?



Вот эта?

> printQuestions($questions);



Она вызывает функцию printQuestions, передавая ей первым аргументом переменную $questions, которая содержит в себе массив из 3 элементов, значение каждого элемента массива - это объект класса Question.

Ну а функция циклом обходит массив, в этом цикле по очереди берется каждый объект-вопрос и на экран выводится информация, хранящаяся в нем.

>>1090534

Я еще вспомнил, тесты - они обычно повышают качество кода, так как у тебя постоянно тестируются отдельные компоненты (функции и классы), а также отдельные возможности приложения, и ошибки быстрее обнаруживаются.
#393 #1090619
>>1090508

Непонятно - перечитай учебник из ОП поста (или любой другой) еще раз.

>>1090493

Да, с SQL базой данных это будет удобно делать. При хранении в файлах ты начнешь переизобретать СУБД и потратишь зря время, и работать она все равно будет хуже чем сделанная профессионалами.

>>1090490

trim удаляет только пробелы с краев. Тебе подойдет str_replace или strtr.

>>1090456

На ideone отключили модуль mbstring. Попробуй запускать свой код на других сайтах: https://repl.it/languages/php , http://phptester.net/ , http://sandbox.onlinephpfunctions.com/ , http://codepad.org/ или http://www.runphponline.com/ , http://phpfiddle.org/ (сложный) - может где-то там заработает.

>>1090433

"что нужно в коде написать" - я не могу за тебя выполнять твою работу. Я тебе указал, в каком направлении гуглить, можешь попробовать разобраться или искать готовое решение. Алсо, могу предупредить что это будет сложно, обычно php используют для короткоживущих скриптов, а тебе надо долгоработающий скрипт, который будет постоянно получать данные с API, передавать их клиентам, придется возиться с сетевым программированием, не для совсем новичков.

>>1090432

Очевидно, написать свой сервер, поддерживающий протокол WAMP. Апач тут не поможет. Если данные нужны только на сервере -то скрипт для командной строки.
#394 #1090620
>>1090340

Давай разберемся в проблеме.

Если ты возьмешь любой репозиторий на гитхабе, например мой https://github.com/codedokode/pasta/ , то там есть зеленая кнопка Clone or Download, и там написан URL для клонирования (2 варианта - HTTPS и SSH). В git book виды ссылок подробно описаны: https://git-scm.com/book/ru/v1/Git-на-сервере-Протоколы

И на гитхабе также есть статья на англ: https://help.github.com/articles/which-remote-url-should-i-use/

И там написано:

> Cloning with SSH URLs



> SSH URLs provide access to a Git repository via SSH, a secure protocol. To use these URLs, you must generate an SSH keypair on your computer and add the public key to your GitHub account.



URL, который начинается с git@github (SSH-URL), он подразумевает, что у тебя есть SSH-доступ на сервер githib.com от имени пользователя git. То есть GIT заходит на сервер по SSH, и далее там выполняет какие-то команды, чтобы прочитать данные из хранящегося на сервере репозитория. На такой случай у гитхаба есть "эмулятор" SSH, который не позволяет реально залогиниться и получить доступ к командной строке, но который поддерживает работу с репозиторием через git. Но для этого, тебе нужен аккаунт и нужно создать и правильно добавить туда ssh-ключ (ssh-ключ используется для аутентификации вместо пароля, который менее надежен).

Выгода от SSH протокола в том, что на большинстве linux-серверов уже есть SSH и для поддержки этого протокола не надо ничего специально на севрере настраивать (для HTTPS например надо настраивать и запускать git-сервер). Но в случае с гитхабом, это не наша проблема - там все настроено за нас, и удобнее исопльзовать HTTPS.

Далее, ты спрашивал

> как свой гит привязать к репозиторию?


git - распроделенная система, и в нем нет каких-то специальных "привязок". Ты в любой момент хранишь у себя полную копию репозитория, и, при желании, можешь ее синхронизировать с копиями на других серверах. Гитхаб использует именно этот вариант - ты просто в настройках своего реплозитория указываешь нужный URL как remote, и по команду push он выгрузит туда (на гитхаб) изменения. Но ты не обязан исопльзовать именно гитхаб или только гитхаб - ты можешь также синхронизировать изменения на флешку, свой собственный сервер по SSH, на альтернативу гитхабу под названием bitbucket.

Изучи главу про синхронизацию изменений и удаленные копии репозитория: https://git-scm.com/book/ru/v1/Основы-Git-Работа-с-удалёнными-репозиториями

Вернемся к статье из учебника:

> Например, если вы хотите клонировать библиотеку Ruby Git, известную как Grit, вы можете сделать это следующим образом:


> $ git clone git://github.com/schacon/grit.git



Увы, тут пропущено то, что предварительно тебе надо настроить SSH-ключи для доступа к репозиторию на гитхабе (текст учебника выложен на том же гитхабе, так что можешь позже внести исправления на HTTPS URL и предложить их смержить). Как я уже писал выше, проще просто использовать HTTPS URL, тем более что для клонирования даже не нужен аккаунт и пароль.

clone создает новый, пустой репозиторий, добавляет в него ссылку на удаленный репозиторий под именем origin и скачивает все данные из удаленного репоизитория в локальный. Но ты не обязан использовать clone - ты можешь создать пустой репозиторйи через init, добавить удаленный через git remote add, и синхронизировать через pull/push.

Там еще есть fetch, push, их надо будет изучить, и pull, но это лучше изучать после merge.

Спрашивай еще, если что-то непонятно.

Также, советую в консоли щелкнуть правой кнопкой мыши на заголовок и настроить шрифт покрупнее. А заодно разрешить быстрое копирование/вставку.
#394 #1090620
>>1090340

Давай разберемся в проблеме.

Если ты возьмешь любой репозиторий на гитхабе, например мой https://github.com/codedokode/pasta/ , то там есть зеленая кнопка Clone or Download, и там написан URL для клонирования (2 варианта - HTTPS и SSH). В git book виды ссылок подробно описаны: https://git-scm.com/book/ru/v1/Git-на-сервере-Протоколы

И на гитхабе также есть статья на англ: https://help.github.com/articles/which-remote-url-should-i-use/

И там написано:

> Cloning with SSH URLs



> SSH URLs provide access to a Git repository via SSH, a secure protocol. To use these URLs, you must generate an SSH keypair on your computer and add the public key to your GitHub account.



URL, который начинается с git@github (SSH-URL), он подразумевает, что у тебя есть SSH-доступ на сервер githib.com от имени пользователя git. То есть GIT заходит на сервер по SSH, и далее там выполняет какие-то команды, чтобы прочитать данные из хранящегося на сервере репозитория. На такой случай у гитхаба есть "эмулятор" SSH, который не позволяет реально залогиниться и получить доступ к командной строке, но который поддерживает работу с репозиторием через git. Но для этого, тебе нужен аккаунт и нужно создать и правильно добавить туда ssh-ключ (ssh-ключ используется для аутентификации вместо пароля, который менее надежен).

Выгода от SSH протокола в том, что на большинстве linux-серверов уже есть SSH и для поддержки этого протокола не надо ничего специально на севрере настраивать (для HTTPS например надо настраивать и запускать git-сервер). Но в случае с гитхабом, это не наша проблема - там все настроено за нас, и удобнее исопльзовать HTTPS.

Далее, ты спрашивал

> как свой гит привязать к репозиторию?


git - распроделенная система, и в нем нет каких-то специальных "привязок". Ты в любой момент хранишь у себя полную копию репозитория, и, при желании, можешь ее синхронизировать с копиями на других серверах. Гитхаб использует именно этот вариант - ты просто в настройках своего реплозитория указываешь нужный URL как remote, и по команду push он выгрузит туда (на гитхаб) изменения. Но ты не обязан исопльзовать именно гитхаб или только гитхаб - ты можешь также синхронизировать изменения на флешку, свой собственный сервер по SSH, на альтернативу гитхабу под названием bitbucket.

Изучи главу про синхронизацию изменений и удаленные копии репозитория: https://git-scm.com/book/ru/v1/Основы-Git-Работа-с-удалёнными-репозиториями

Вернемся к статье из учебника:

> Например, если вы хотите клонировать библиотеку Ruby Git, известную как Grit, вы можете сделать это следующим образом:


> $ git clone git://github.com/schacon/grit.git



Увы, тут пропущено то, что предварительно тебе надо настроить SSH-ключи для доступа к репозиторию на гитхабе (текст учебника выложен на том же гитхабе, так что можешь позже внести исправления на HTTPS URL и предложить их смержить). Как я уже писал выше, проще просто использовать HTTPS URL, тем более что для клонирования даже не нужен аккаунт и пароль.

clone создает новый, пустой репозиторий, добавляет в него ссылку на удаленный репозиторий под именем origin и скачивает все данные из удаленного репоизитория в локальный. Но ты не обязан использовать clone - ты можешь создать пустой репозиторйи через init, добавить удаленный через git remote add, и синхронизировать через pull/push.

Там еще есть fetch, push, их надо будет изучить, и pull, но это лучше изучать после merge.

Спрашивай еще, если что-то непонятно.

Также, советую в консоли щелкнуть правой кнопкой мыши на заголовок и настроить шрифт покрупнее. А заодно разрешить быстрое копирование/вставку.
#395 #1090621
>>1090328

Ты зачем от рута сидишь, новичков дурному учишь?

>>1090316

Да, пропиши 7.0 или 7.1 конечно.

>>1090312

Это не эмулятор, это программа git + набор линуксовых утилит, портированных под Windows (bash и другие вроде ls, rm итд).

> Это же не связало клонированный реп с гитхабом, как мне связать репозиторий на гит-хабе, с папкой на компе?


Почитай в книге про удаленные репозитории. Тебе надо просто добавить в репозиторий ссылку на удаленный репозиторий (или несколько репозиториев) и можно синхронизировать данные командами fetch/pull/push.

>>1090274

Оффтопик Чтобы слышать звуки, мало учить нотную грамоту, надо развивать слух, есть разные упражнения для тренировки. Лучше всего, конечно, если слух есть от рождения, вот, например про Моцарта написано в википедии: "Эти уроки оказали огромное воздействие на маленького Вольфганга, которому было около трёх лет: он садился за инструмент и мог подолгу развлекаться подбором созвучий. Кроме того, он запоминал отдельные места музыкальных пьес, которые слышал, и мог проиграть их на клавесине"

По статье, я не знаю, что тут прокомментировать. В России IT-специальностям нормально почти нигде не учат, кроме каких-то самых известных университетов и программ обучения совместно с компаниями вроде яндекса/мейла, так что самоучек в нашей сфере очень много. И даже там, где учат, ты вряд ли сможешь чему-то научиться, просто посещая лекции и не занимаясь самостоятельно. Да ты даже поступить туда не сможешь, не занимаясь самостоятельно. Статья, увы, не про российский опыт, и может быть частично неактуальна. Вроде как на Западе к димпломам (то есть к способности выложить кучу денег за обучение в престижном дорогом университете, либо получить сколаршип) больше внимания, чем у нас. Там правда и учиться придется по-настоящему, а не как у нас.

Вообще, тебе надо решать какие-то практические задания, просто так учить горы теоретического материала будет тяжеловато. Вот я там выше писал, например, про центрирование картинок, можешь попробовать решить, паралельно гугля способы и в спецификациях читая подробности про используемые там свойства >>1089218

А так, я не уверен, что ты сможешь быстро осилить эту спецификацию. Лучше именно те места, которые непонятны, смотреть в спецификации. Там есть тонкости в visual formatting model, есть тонкости с разными контекстами (когда боксы группируются в слои), но остальное - это просто разные свойства, которые можно изучать по отдельности.

Также, если ты любишь детально во всем разбираться, могу дать ссылку на книгу на русском: http://css-live.ru/articles/obzor-inlajnovyj-kontekst-formatirovaniya.html
#395 #1090621
>>1090328

Ты зачем от рута сидишь, новичков дурному учишь?

>>1090316

Да, пропиши 7.0 или 7.1 конечно.

>>1090312

Это не эмулятор, это программа git + набор линуксовых утилит, портированных под Windows (bash и другие вроде ls, rm итд).

> Это же не связало клонированный реп с гитхабом, как мне связать репозиторий на гит-хабе, с папкой на компе?


Почитай в книге про удаленные репозитории. Тебе надо просто добавить в репозиторий ссылку на удаленный репозиторий (или несколько репозиториев) и можно синхронизировать данные командами fetch/pull/push.

>>1090274

Оффтопик Чтобы слышать звуки, мало учить нотную грамоту, надо развивать слух, есть разные упражнения для тренировки. Лучше всего, конечно, если слух есть от рождения, вот, например про Моцарта написано в википедии: "Эти уроки оказали огромное воздействие на маленького Вольфганга, которому было около трёх лет: он садился за инструмент и мог подолгу развлекаться подбором созвучий. Кроме того, он запоминал отдельные места музыкальных пьес, которые слышал, и мог проиграть их на клавесине"

По статье, я не знаю, что тут прокомментировать. В России IT-специальностям нормально почти нигде не учат, кроме каких-то самых известных университетов и программ обучения совместно с компаниями вроде яндекса/мейла, так что самоучек в нашей сфере очень много. И даже там, где учат, ты вряд ли сможешь чему-то научиться, просто посещая лекции и не занимаясь самостоятельно. Да ты даже поступить туда не сможешь, не занимаясь самостоятельно. Статья, увы, не про российский опыт, и может быть частично неактуальна. Вроде как на Западе к димпломам (то есть к способности выложить кучу денег за обучение в престижном дорогом университете, либо получить сколаршип) больше внимания, чем у нас. Там правда и учиться придется по-настоящему, а не как у нас.

Вообще, тебе надо решать какие-то практические задания, просто так учить горы теоретического материала будет тяжеловато. Вот я там выше писал, например, про центрирование картинок, можешь попробовать решить, паралельно гугля способы и в спецификациях читая подробности про используемые там свойства >>1089218

А так, я не уверен, что ты сможешь быстро осилить эту спецификацию. Лучше именно те места, которые непонятны, смотреть в спецификации. Там есть тонкости в visual formatting model, есть тонкости с разными контекстами (когда боксы группируются в слои), но остальное - это просто разные свойства, которые можно изучать по отдельности.

Также, если ты любишь детально во всем разбираться, могу дать ссылку на книгу на русском: http://css-live.ru/articles/obzor-inlajnovyj-kontekst-formatirovaniya.html
#396 #1090623
>>1090269

cygwin - это порт (адаптация) linux-программ для работы под Windows. cygwin предоставляет API, похожее на то, что дает ядро линукса и стандартная библиотека libc, и программу требуется перекомпилировать под cygwin. В теории любую открытую программу можно перекомпилировать, на практике, если она не рассчитана на cygwin, то придется допиливать систему сборки.

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

>>1090268

Нет там эмуляторов, там git ПРОСТО скомпилирован под винду + bash + минимальный набор линуксовых утилит. Вроде это msys называлось.

>>1090265

Я бы советовал тебе развиваться сбалансированно и уделить внимание еще фронтенду (JS, сложные интерфейсы), SQL, сетевому программированию. И Симфони тоже конечно. 3-5 лет как-то пессимистично, это надо очень лениво учиться.

Алсо поищи и почитай статьи тех, кто так работает.

>>1090194

Ты берешь отстаток от деления числа на 10. Если число меньше 10, то остатак будет такой же и цикл будет вечным.

Алсо, посчитать число разрядов одним действием можно, используя десятичный логарифм. Его вроде в школе изучали.

>>1090219

> $t = (int)($t / 10);


Для округления есть round, floor, ceil, где четко описаны правила округления, не надо использовать какие-то странные альтернативы.

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

Имена функций обычно начинаются с глагола, сделайЧтоТо().

Ну и программа зачем-то выводит NULL.
#396 #1090623
>>1090269

cygwin - это порт (адаптация) linux-программ для работы под Windows. cygwin предоставляет API, похожее на то, что дает ядро линукса и стандартная библиотека libc, и программу требуется перекомпилировать под cygwin. В теории любую открытую программу можно перекомпилировать, на практике, если она не рассчитана на cygwin, то придется допиливать систему сборки.

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

>>1090268

Нет там эмуляторов, там git ПРОСТО скомпилирован под винду + bash + минимальный набор линуксовых утилит. Вроде это msys называлось.

>>1090265

Я бы советовал тебе развиваться сбалансированно и уделить внимание еще фронтенду (JS, сложные интерфейсы), SQL, сетевому программированию. И Симфони тоже конечно. 3-5 лет как-то пессимистично, это надо очень лениво учиться.

Алсо поищи и почитай статьи тех, кто так работает.

>>1090194

Ты берешь отстаток от деления числа на 10. Если число меньше 10, то остатак будет такой же и цикл будет вечным.

Алсо, посчитать число разрядов одним действием можно, используя десятичный логарифм. Его вроде в школе изучали.

>>1090219

> $t = (int)($t / 10);


Для округления есть round, floor, ceil, где четко описаны правила округления, не надо использовать какие-то странные альтернативы.

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

Имена функций обычно начинаются с глагола, сделайЧтоТо().

Ну и программа зачем-то выводит NULL.
#397 #1090624
>>1090207

Это некорректно, так как большие числа преобразуются в строку вида "1e20" ( http://physic.kemsu.ru/pub/library/learn_pos/Free_Pascal/Free Pascal/soder/3_1_3.htm ) и получится неверный ответ. Изучай десятичный логарифм.

>>1090204

Ты берешь остаток от деления. А не результат деления.

>>1090202

Можешь изучать, хуже не будет.

>>1090185

Десятичный логарифм. Операция, обратная возведению 10 в степень.

>>1090183

Еще можно класть числа в массив и вывести через implode.

>>1090181

Ему не нужно обращаться к драйверу, так как он использует абстракцию, которую предоставляет ОС для консольных приложений - стандартный поток ввода или stdin (погугли).

>>1090159

В Паскале ты пишешь программу для командной строки, и запускаешь ее в консоли. Она читает данные с стандартного потока ввода (по умолчанию это клавиатура, но можно перенаправить этот поток, чтобы он читал данные например из файла).

В PHP ты открываешь страницу в браузере, браузер шлет HTTP-запрос, сервер запускает скрипт, отправляет в ответе то, что выведет этот скрипт (уроки https://github.com/codedokode/pasta/blob/master/soft/web-server.md ). Очеивдно, что тут читать с клавиатуры ничего нельзя, так как нет гарантий, что на компьютере, где запущена программа-сервер, вообще есть клавиатура.

Но ты можешь написать на PHP скрипт и запустить его в командной строке. Тогда ты сможешь читать данные из STDIN:

https://github.com/codedokode/pasta/blob/master/soft/cli.md
http://php.net/manual/ru/features.commandline.php

Прочти и там наверно найдешь ответ на свой вопрос.

Кстати, если ты под линуксом, то можешь обернуть запуск php с помощью команды rlwrap и получишь в дополнение сохранение истории введенных данных с поиском, и команды для редактирования строки. Подробности в мануале по библиотеке readline.

Ты не представляешь, какая мощная и выразительная вещь - командная строка. Изучай ее скорее.
#397 #1090624
>>1090207

Это некорректно, так как большие числа преобразуются в строку вида "1e20" ( http://physic.kemsu.ru/pub/library/learn_pos/Free_Pascal/Free Pascal/soder/3_1_3.htm ) и получится неверный ответ. Изучай десятичный логарифм.

>>1090204

Ты берешь остаток от деления. А не результат деления.

>>1090202

Можешь изучать, хуже не будет.

>>1090185

Десятичный логарифм. Операция, обратная возведению 10 в степень.

>>1090183

Еще можно класть числа в массив и вывести через implode.

>>1090181

Ему не нужно обращаться к драйверу, так как он использует абстракцию, которую предоставляет ОС для консольных приложений - стандартный поток ввода или stdin (погугли).

>>1090159

В Паскале ты пишешь программу для командной строки, и запускаешь ее в консоли. Она читает данные с стандартного потока ввода (по умолчанию это клавиатура, но можно перенаправить этот поток, чтобы он читал данные например из файла).

В PHP ты открываешь страницу в браузере, браузер шлет HTTP-запрос, сервер запускает скрипт, отправляет в ответе то, что выведет этот скрипт (уроки https://github.com/codedokode/pasta/blob/master/soft/web-server.md ). Очеивдно, что тут читать с клавиатуры ничего нельзя, так как нет гарантий, что на компьютере, где запущена программа-сервер, вообще есть клавиатура.

Но ты можешь написать на PHP скрипт и запустить его в командной строке. Тогда ты сможешь читать данные из STDIN:

https://github.com/codedokode/pasta/blob/master/soft/cli.md
http://php.net/manual/ru/features.commandline.php

Прочти и там наверно найдешь ответ на свой вопрос.

Кстати, если ты под линуксом, то можешь обернуть запуск php с помощью команды rlwrap и получишь в дополнение сохранение истории введенных данных с поиском, и команды для редактирования строки. Подробности в мануале по библиотеке readline.

Ты не представляешь, какая мощная и выразительная вещь - командная строка. Изучай ее скорее.
#398 #1090625
>>1089816

В блоке else нельзя указать условие. Ошибка у тебя.

>>1089627

Если я сразу скажу ответ, пользы будет мало. Лучше я научу, как отлаживать такие проблемы.

Тебе надо сделать вывод на каждом шаге цикла, чему равны в этот момент переменные. И взять сумму поменьше - например, 1000 или 4000 или 6000, для которой легко проверить расчеты вручную.

Также, у тебя слишком длинная шапка цикла for, я бы советовал конструкцию $creditSum = ($creditSum*$percent) ... из нее вынести.

>>1090593

Тренируйся на своих или чужих проектах в свободное время.
#399 #1090669
>>1090503
>>1090619
Премного благодарен!
#400 #1090671
>>1090621
Ты так много делаешь, спасибо. Вообще в статье посыл в том, что нужно сочетать теорию с практикой и постоянно трудиться. Ну на этом я и остановлюсь, а то смысла без использования спецификации нет.
#401 #1090673
>>1090624

>Десятичный логарифм. Операция, обратная возведению 10 в степень.


У меня по заданию нужно выводить число от 0 до бесконечности. Т.е. пользователь может ввести число с любым количеством знаков.
#402 #1090674
>>1090621

>зачем от рута сидишь


швабодка же
THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU

>новичков дурному учишь


так не учу же, да и кто будет слушать рандомного мимокрокодила с аиб?
в бородатые времена их вообще вишней кормили
#403 #1090675
А сюда можно кидать вопросы по SQL, в контексте задач по PHP?
#404 #1090678
>>1090675
Задавай в любом контексте, тред связан с веб-технологиями и мимокроки отвечают в этих рамках.
#405 #1090687
>>1090678
Параметр AUTO_INCREMENT, который указывается в БД, делает идентификатор - уникальным?

ЧПУ - это любой URL, который может прочитать человек? Т.е. 2ch.hk/pr/res/ - ЧПУ, а вот %D20 и подобные трансформации символов - нет?

И я тут изучаю чужой код, посему несколько уточняющих вопросов:

Если я хочу в переменную $link запухнуть ссылку, мне обязательно нужно указать htmlspecialchars ?
$link = htmlspecialchars($_POST['link']);

if(empty($_POST['link'])){} - т.е. логика этого if "если ничего не передано, то ничего не делать?

@$select = mysql_fetch_assoc(mysql_query("SELECT * FROM `short` WHERE `url` = '".$link."'")); - я как-то не могу понять, почему перед переменной $select стоит @
#406 #1090730
Добра. Один мой коллега на работе, который вроде как намного опытнее меня, сказал, что в больших проектах объекты не нужны, объекты это зло и норм пацаны всюду ебошут sql запросами. Имел он ввиду судя по всему модели из MVC. Так вот, прав ли он?
С одной стороны они съедают кучу памяти. С другой, код с ними намного лучше поддерживать. И вообще, для проектов, где приходится отказываться от моделей, есть смысл выбрать какой нибудь другой язык, не?
#407 #1090738
>>1090730
Он имел ввиду, то что он долбоеб, не более.
Какие такие "большие" проекты он имел ввиду.
Вот я знаю, только один большой проект где все на массивах.
#408 #1090747
>>1090730
Не знаю почему так много идиотов развелось, которые думают, что ООП не нужно.
#409 #1090754
>>1090730
ООП нужен для совместной разработки. Когда Вася делает фронт + бэк, а Петя - библиотечку для конвертации хуйнянейм в пизданейм.

Затем Вася подключает библиотечку и выдает пользователю пизданейм.
#410 #1090761
>>1090730
абсолютно не прав. это видимо коллега из тех "опытных", которые еще говорят, что тесты - это трата времени.

объекты не съедают кучу памяти. объекты и все, что создает сам язык - хуйня в плане накладных расходов. самое узкое место больших нагруженных проектов - это как раз чтение БД.
14 Кб, 615x98
#411 #1090790
Оп, ты можешь исправить ошибку на сайте? В регулярных выражениях неверный пример.
#412 #1090797
У меня такая проблема: я на несколько месяцев забросил обучение, и теперь когда я вернулся, котики с оп поста осуждают меня.
#413 #1090806
>>1090730

Я думаю, он говорил не про "объекты", а про полноценный ORM vs паттерн TableGateway (я надеюсь, он не предлагает по всему коду раскидывать SQL запросы и тем более дублировать одинаковый код в нескольких местах). Хотя конечно, я могу ошибаться, понять, что имелось в виду, трудно.

Есть и преимущества и недостатки у каждого подхода.

Подход с массивами в большом проекте как раз очень плохо работает, так как непонятно, какие поля есть в этом массиве. Я работал с такими проектами, разбираться трудно, потому что в массиве часть полей из БД в исходном виде, часть преобразованы, часть добавлены дополнительно и там мозг сломаешь, пока разберешься. Особенно доставляет, когда у полей имена бессмысленные вроде shs или сделаны в разных стилях (с подчеркиванием и без подчеркивания).

> С одной стороны они съедают кучу памяти.


Ты ведь не делал тесты, почему ты так решил? Откуда вообще этот миф, что объекты "съедают память"?

Это зависит от реализации. В новых версиях PHP работа с объектом в определенных случаях может быть даже быстрее работы с массивом, и памяти он может занимать меньше.

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

> И вообще, для проектов, где приходится отказываться от моделей, есть смысл выбрать какой нибудь другой язык, не?


Какой язык?

Ты во-первых, путаешь понятия "модель" из MVC и модель как объект, соответствующий строчке в таблице, во-вторых, если ты выбираешь данные из БД, "модели" всегда есть, просто они могут быть не в виде объекта, а в виде массива.

Ну и если ты вдруг решишь написать какую-то часть кода на Си или Го, то, внезапно, обнаружишь, что там работать со структурами (объектов там нет) гораздо удобнее, чем с ассоциативными массивами. Это как раз особенности динамических языков вроде PHP или JS, что там часто используют ассоциативные массивы.

В общем, надеюсь, что твой коллега дает советы, тщательно разобравшись в разных подходах, а не из соображения "лень разбираться".
#413 #1090806
>>1090730

Я думаю, он говорил не про "объекты", а про полноценный ORM vs паттерн TableGateway (я надеюсь, он не предлагает по всему коду раскидывать SQL запросы и тем более дублировать одинаковый код в нескольких местах). Хотя конечно, я могу ошибаться, понять, что имелось в виду, трудно.

Есть и преимущества и недостатки у каждого подхода.

Подход с массивами в большом проекте как раз очень плохо работает, так как непонятно, какие поля есть в этом массиве. Я работал с такими проектами, разбираться трудно, потому что в массиве часть полей из БД в исходном виде, часть преобразованы, часть добавлены дополнительно и там мозг сломаешь, пока разберешься. Особенно доставляет, когда у полей имена бессмысленные вроде shs или сделаны в разных стилях (с подчеркиванием и без подчеркивания).

> С одной стороны они съедают кучу памяти.


Ты ведь не делал тесты, почему ты так решил? Откуда вообще этот миф, что объекты "съедают память"?

Это зависит от реализации. В новых версиях PHP работа с объектом в определенных случаях может быть даже быстрее работы с массивом, и памяти он может занимать меньше.

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

> И вообще, для проектов, где приходится отказываться от моделей, есть смысл выбрать какой нибудь другой язык, не?


Какой язык?

Ты во-первых, путаешь понятия "модель" из MVC и модель как объект, соответствующий строчке в таблице, во-вторых, если ты выбираешь данные из БД, "модели" всегда есть, просто они могут быть не в виде объекта, а в виде массива.

Ну и если ты вдруг решишь написать какую-то часть кода на Си или Го, то, внезапно, обнаружишь, что там работать со структурами (объектов там нет) гораздо удобнее, чем с ассоциативными массивами. Это как раз особенности динамических языков вроде PHP или JS, что там часто используют ассоциативные массивы.

В общем, надеюсь, что твой коллега дает советы, тщательно разобравшись в разных подходах, а не из соображения "лень разбираться".
#414 #1090808
>>1090761

Вообще, не факт. MySQL очень быстро работает, если ты делаешь выборки небольших объемов данных по индексам, у тебя большинство запросов будет меньше 1 мс. С другой стороны, я в тестах видел случаи, когда маппинг выбранных данных на объекты доктриной занимал гораздо больше времени, чем сама выборка. С третьей стороны, может быть можно этот маппинг как-то оптимизировать.

>>1090790

А что с ним не так? [012] должно быть?
#415 #1090810
можно ли выдрать только админку от вордпресса и прилепить ее к своему сайту на пхп фреймворке?
#416 #1090817
>>1090810
кек.
1,5 Мб, webm, 720x720, 0:10
#417 #1090820
>>1090806
Предыстория такова. Есть один древний проект (что-то вроде интернет магазина) на Yii 1 из 2012 - 2013 года. Одним из требований клиента было не использовать юишные модели. Чувак поддерживающий этот сайт перешел на другую работу, и проект благополучно достался мне. В итоге модели в нем не используются совсем а SQL запросы размазаны тонким (а в некоторых местах очень даже толстым) слоем по контроллерам. Так вот, если будет чего непонятно, мне посоветовали обращаться другому чуваку, который над этим сайтом тоже работал.
Первой моей мыслью было "А какого хуя SQL не собрали в моделях в виде статических методов". Не успел я это у него спросить. Я просто сказал, что без моделей в MVC фреймворке жить печально, на что мне был дан четкий ответ, что "Объекты зло, объекты со связанными таблицами сверхзло, и что на любом проекте, где хотя-бы(!) на сайте используются фильтры в каких нибудь списках товаров, использовать их не следует."
Я немножко был выбит из колеи, и теперь думаю, что за советами к этому чуваку мне ходить не следует.
#418 #1090825
>>1090820

>Одним из требований клиента было не использовать юишные модели


ват? какой смысл было тогда уи брать? ебашили бы как диды на голом пхп тогда со смесью пхп с цсс с хтмл с запросами.
таких клиентов надо слать нахуй.

>>1090730
Если проект уже готовый и пришел новый разработчик, который не хочет долго в нем ковырять да и бизнесу нужно побыстрее, то не вижу ничего плохого в том, чтобы ебануть запрос в контроллер или вьюху, чтобы быстро что-то пофиксить или дописать функционал.

На стадии проектирования архитектуры лучше делать все красиво, с моделями и разделением логики.
#419 #1090836
>>1090810

Вообще, можно поступить по другому. Вордпресс сложный и потому потенциально уязвимый продукт. Можно взять вордпресс и поместить на отдельный домен, закрытый HTTP-авторизацией и использующий HTTPS (например, https://admin.example.com). Таким образом, боты и сканеры не смогут получить доступ никуда. А основной сайт не содержит админки, но берет данные из той же базы данных, с которой работает вордпресс.

Я когда-то такую вещь делал, брал админку от готовой CMS на отдельном домене, а публичную часть сайта писал с нуля, она просто выводила данные из базы. На мой взгляд, это довольно безопасный подход: код публичной части простой и в нем мала вероятность уязвимости, а сложная потенциально уязвимая часть (админка) закрыта HTTP-авторизацией.
#420 #1090838
>>1090825

Если ты пришел сделать одну задачу, и тебе все равно, что будет потом, то да. Но если ты бизнес, который планирует несколько лет развивать сайт, то такой подход приведет к тому, что код править и поддеривать будет сложнее, там чаще будут ошибки.

Некоторые конечно скажут "зачем писать хорошо, через несколько лет поменяются технологии и сайт перепишут на Руби (2008), Node (2012), Го (2014), Реакте и тд.". Те, кто так говорят, они просто программисты и деньги считать не умеют.
#421 #1090869
>>1090820
реальная история, коллега меняла работу и ей в в какой-то конторе после вопроса пользуются ли они гит-флоу в каком-то виде, сказали что-то типа "да нет, мы гитом не пользуемся - он же ничего не дает, только гемор". что они для простоты сразу на фтп заливают файлики.
#422 #1090902
>>1090836
то есть отсоединить можно отсоединить папку wp-admin от папки wp-content и ошибки не будет? Или у тебя данные с админки выводились также на сайте, расположенный на домене с админкой, просто он был скрыт?
#423 #1090907
>>1090869

Я когда-то давно работал в похожей системе. Там нас было 2 человека, работающих над одним проектом, и мы периодически пересылали друг другу измененные файлы для ручного мерджа. Ну если у них так много свободного времени, это конечно их право. Или может у них проект очень вяло развивается и проблем нет. Или может у них просто низкая зарплата и это обходится им дешевле, чем настройка гита :)
#424 #1090908
>>1090838
Я как раз подхожу с точки зрения бизнеса. Бизнесу нужно быстро, а потом хоть потоп - макаки пофиксят.

Вот у меня, например, была задача сделать чекбокс в одном оче сложном плагине для вордпресса, который создавал RSS ленту. Там какой-то инстанс объекта создавался в нескольких местах, что и куда и на каком этапе шло было не понятно. Они вроде как прикрутили какой-то хук, убивающий создание объекта, но во-первых, не сработал, во-вторых создание этого объекта происходило тока один раз и если у поста был статус опубликовано, то он автоматом добавлялся в ленту. То есть убрать его было нельзя. То есть наверное можно было бы, но пришлось бы опять писать какой-то метод, добавлять в тело плагина запрос на удаление объекта из бд, как-то связывать это с инстансом (а как, если они в разных файлах вообще?), искать ту колонку, где посты помечались как feed.

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

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

Но зато я сделал эту хрень за 1 день, ведь бизнес знает, что такой плагин есть, знает что там нужно просто добавить чекбокс и по его мнению это делается легко и быстро. А вот если бы я сидел и пытался расковырять плагин, понять как он работает - то я бы неизвестно сколько дней потратил и бизнес посчитал бы меня плохим спецом, пусть и формирование rss ленты заняло бы на несколько секунд меньше - бизнес бы тупо этого не заметил.
#425 #1090909
>>1090902

Это надо проверять анализом кода (например поиском по названию папки) и экспериментально. Но если у тебя сайт с вопдпрессом полностью закрыт от посторонних HTTP-авторизацией, то можно и не заморачиваться с этим.
#426 #1090910
>>1090869
ну если они заливают и тестят прямо на проде, то да, так лучше.
#427 #1090915
>>1090908

А теперь представь что будет, когда друг на друга наслоят десятки таких "костылей". Если ты там накрутил костылей и ушел - конечно, тебе потом мучаться не придется.

Я про такие ситуации знаю, заканчивается это тем, что новый разработчик говорит заказчику "это надо переписывать". А переписывание - это дорого либо очень дорого, не верьте тем, кто думает, что это можно сделать быстро и качественно.

Понятно, что зависит от ситуации, но если ты постоянно поддерживаешь и развиваешь большой проект, так ты работать нормально не сможешь, производительность будет падать, придется тратить время на разбор и исправление костылей. Если у тебя ситуация, подправить плагин и продать - это другая ситуация. Я-то стараюсь учить людей, чтобы они были способны делать и большие, сложные проекты, а не костыли к кривым плагинам для вордпресса дописывать.

Алсо, вместо таблицы проще было добавить к посту кастомное свойство - по моему, в ВП для этого есть готовый функционал. И даже чтобы галочку для этого свойства в админку добавить - тоже что-то встроенное есть.
#428 #1090928
Как лучше подключать бутстрап? Через CDN или css в папку на сервер закачивать?
23 Кб, 240x149
#429 #1090939
Вопрос не по пхп, а по процессу разработки в целом.

Устроился на удаленку (до этого не работал по сабжу).

Сейчас они пилят проект на ларе, меня подключили к нему. Существует тестовый и боевой север, а также удаленный репозиторий.

Столкнулся с несколькими незнакомыми мне вещами:
- Во первых плохие познания в гите, но вроде разобрался;
- Не знал как правильно работать с удаленным сервером, благо смог в putty;
- Но самое главное, я хз как вообще должен проходить процесс разработки.

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

Дали мне задание допилить функционал в админке и сделать раздел по его управлению. Все сделал. Запушил на репу. Зашел на сервер, написал git status и ссыкнул ибо там гора измененных/добавленых файлов, с которыми я не работал, соответственно не решился с репозитория пулить туда мои допилы.

Отписался, что мол на репу запушил, но спулить на сервер побаиваюсь чтобы не нарушить нихуя. Ну вообщем они сами стянули и все ок.

В связи с чем вопрос, как вообще все это правильно должно выглядеть? моар подробностей
#430 #1090953
>>1090790
Мне кажется, что учитывая пример поиска "выражение 12:34", должно быть ~[12]:[0-5][0-9]~u .
#431 #1090954
>>1090797
Я полгода проработал в сапорте ПХП продукта, а когда через полгода вернулся к теме ПХП не знал, что этот язык не предназначен для запуска на ПК, как Паскаль АБС. Котики смотрели на меня, как на червя-пидора.
#432 #1090955
>>1090808
>>1090953
Промахнулся.
#433 #1090957
>>1090955
Я не оп, но тогда не получится например времени 22:00 попасть под регулярку.

Тогда может лучше так?
~[012][0-9]:[0-5][0-9]~u

На верность не претендую, просто спрашиваю.
14 Кб, 615x98
#434 #1090958
>>1090957
Подожди. Первая часть [12] - это поиск самого числа "12" в тексте, так? Далее ищется число "от 0 до 9", но в 12:34 после 12-ти сразу следует символ :.
#435 #1090960
>>1090958

> это поиск самого числа "12" в тексте, так?



Нет, это Или. Или число 1 или число 2.
[abc] или буква a, или b, или c

вот пример тебе, чтобы легче понять было https://regex101.com/r/quCWyf/1
Задача Вектор #436 #1090962
ОП, посмотри задачу про Вектор, пожалуйста.

https://3v4l.org/aJdlK
#437 #1090963
Подкиньте идею для решения калькулятора,не могу понять как сделать выполнение пред идущей операции
#438 #1090968
>>1090958

>[12]


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

>[0-9]


любой символ от 0 до 9. Вообще можно написать например [0-A] или [`-}] это должно вызвать вопрос, что за порядок символов. На самом деле - это таблица ASCII, можно погуглить

...дальше все понятно... кроме модификатора "u", зачем он тут?
#439 #1090973
>>1090939

По гиту - найди время и прочти учебник (на русском) https://git-scm.com/book/ru/v1/Введение

Там есть глава "удаленные репозитории" https://git-scm.com/book/ru/v1/Основы-Git-Работа-с-удалёнными-репозиториями

Ее тоже прочти (в первую очередь).

Тут надо разделить 2 вещи: удаленные репозитории и деплой. Начнем с первого. Обычно где-то (на приватном гитхабе, на собственном сервере компании) есть центральный репозиторий с кодом. Ты клонируешь его себе и получаешь полную его копию. Затем ты делаешь правки. Коммитишь их в свой репозиторий, написав понятный комментарий. Затем синхронизируешься - выкачиваешь из центрального репозитория правки других разработчиков, мерджишь их (git pull), а затем отправляешь туда свои (git push).

Теперь насчет деплоя - выкладки изменений на сайт. Это лучше автоматизировать:

1) самый простой вариант (годится для dev) - просто держать там копию репозитория так, что когда ты туда пушишь код, он оказывается сразу на сайте. Можно поставить хук на сервере, чтобы при появлении новых коммитов в этом репозитории, изменения бы копировались в папку веб-сервера.

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

3) сделать более сложную систему деплоя, например, освоив ansible (особенно когда у тебя продакшен сложный и состоит из нескольких серверов).

Ты занимаешься глупостью и большой тратой времени, правя файлы на серверу вручную.
#440 #1090979
>>1090939

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

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

Алсо, что касается dev - у каждого разработчика должен быть свой dev (либо он должен тестировать свои изменения у себя). 2 человека не должны работать с одним dev-сервером, это неудобно.

Алсо, некоторые используют средства виртуализации. Докер например. То есть тебе дают образ виртуальной машины, к которой установлены нужные программы и все настроено для выполнения кода. И ты, развернув у себя этот образ, получаешь свой маленький dev сервер.

Статьи

https://habrahabr.ru/company/badoo/blog/317700/
https://habrahabr.ru/post/340550/
https://habrahabr.ru/post/211733/
https://habrahabr.ru/post/309832/
https://habrahabr.ru/company/oleg-bunin/blog/319314/
#441 #1090982
>>1090968

Проще везде писать u, чем разбираться в тонкостях юникода и PCRE. Ты вот можешь 100% точно ответить, в каких условиях можно не указывать этот модификатор (хороший вопрос для собеседования, хехе)?

Забыть флаг легко, а искать причину ошибки ты потом будешь долго.

>>1090963

Нужно завести переменные, и в их запоминать "предыдущее число" и "предыдыщий знак"

В выражении 2 - 3 + 4, когда мы дойдем до плюса, у нас будет:

итог = 0
предыдущее число = 2
пред. знак = -
текущее число = 3
текущий знак = +
#442 #1090984
>>1090982
Спасибо, но я посмотрел как можно решить и оказывается что так просто, что я даун пздц
#443 #1090986
>>1090984

Пора наверно задачки обновить :) Чтобы ответы не гуглились.
#444 #1091001
Помогите с задачей "Экранирование" отсюда https://github.com/codedokode/pasta/blob/master/soft/web-server.md

у меня получается такой код:

$text = htmlspecialchars($_GET["text"]);
$preText = "<pre>{$text}</pre>";
echo $preText;

$linkText = htmlspecialchars("?text={$text}&lt=1");

$linkText = str_replace(array("\r\n", "\r", "\n", "\t", ' ', ' ', ' '), '', $linkText);

echo "<a href='{$linkText}'>Ссылка</a>";

Но при нажатии ссылки не появляется текст, как решить ошибку?
#445 #1091017
>>1091001

А где поле ввода?
#446 #1091056
Пехапечь выручай есть 2 таблицы

companies
name
country

и

trades
id
seller (тут название из companies.names)
buyer (тут название из companies.names)
values(число)

нужен запрос что бы получилось

companies.country | companies.name | export | import

export import (сумма где фирма выступает покупателем и продавцом ) в 1 стране может быть несколько фирм
#447 #1091068
>>1091056
Ошибка постинга: В сообщении присутствует слово из спам листа.
#448 #1091070
>>1090968
Премного благодарен за объяснение!

>>1090982

>Ты вот можешь 100% точно ответить, в каких условиях можно не указывать этот модификатор


Дай угадаю: если в тексте есть кириллица?
#449 #1091071
Анон, объясни логику.

Почему в коде пишется так:
$mysqli->query (что-то там)
Почему класс переходит в запрос? Ведь надо бы писать, что-то уровня query ($mysqli) и далее, как с функциями.
#450 #1091074
>>1091071
Я на любом языке сразу создаю функцию db($sql) и db($sql, $params). Что может быть короче и удобнее?
#451 #1091076
>>1091074
Ну, до такого я ещё не дорос и создание фукнции для меня представляет такую трудность, что проще этого не делать.
#452 #1091086
>>1091017
поле ввода такое
<form action="shielding.php" method="get">
<textarea name="text" cols="30" rows="10">

</textarea>
<p><input type="submit"></p>
</form>
#453 #1091088
Анон, подскажи, это "традиционная" фраза такая для вывода строки из БД:
$row = $result_set->fetch_assoc();
или просто я сталкивался с копипастингом?

И я сейчас разбираюсь с чужим циклом для вывода значений из БД. Правильно ли я понимаю его. Мои слова в комментах.

function replaceSEF ($content){
//начало функции
$regex = ("[(<a[^>]href\s=\s[\"'])([^'\"])([\"'][^>]>\s.?\s</a>)]i";
//регулярное выражение для поиска ссылок в тексте. я потом упрощу, т.к. мне пользователь должен будет вводить её
preg_match_all($regex, $content, $matches);
//встроенная функция для поиска ВСЕХ совпадений в тексте
for ($i = 0; $i< count($matches[2]); $i++){
//у переменной индекс равен 2, потому-что в БД создано 3 строки и именно третья хранит информацию, по которой идет сравнение
$result_set = $mysqli->query ("SELECT 'alias' FROM 'sef' WHERE 'link' = ' " .$matches[2][$i]." ' ");
//$result_set - это специальный класс для получения данных из БД
$row = $result_set->fetch_assoc();
//превращаем класс в массив
$content= str_replace($matches[2][$i], $row["alias"], $content);
//тут не понимаю, что происходит
if ($result_set) $result_set ->close();
//это означает, что если $result_set ничего не будет найдено, то цикл просто не случится и соединение закроется.
}
return $content;
#454 #1091090
>>1091088
Код немного поехал.
Вот ссылкой https://ideone.com/VNhxN8
#455 #1091098
>>1091088
count($matches[2]) - это очень плохо писать в цикле. Правильно писать так:
$count = count($matches[2])
for ($i = 0; $i < $count; $i++)

А еще лучше вообще использовать
foreach ($matches[2] as $link)

$sql запрос в таком виде как у тебя не безопасен. Нужно все параметры вводимые пользователем, предварительно обезвреживать при помощи следующей конструкции:

$link = $mysqli->real_escape_string($link);
#456 #1091099
>>1091071
Это сделано для того, что бы можно было одновременно работать с несколькими базами данных.
Т.е. создаёшь сначало несколько соединений:
$mysqli1 = new mysqli ("localhost", "db_1", "pass", "db_1");
$mysqli2 = new mysqli ("http://fu.ru", "db_2", "password", "db_2");

И после этого можешь выбирать, к какой из двух баз данных сделать запрос:
$mysql1->query("SELECT ..."); //Запрос к первой БД
$mysql2->query("SELECT ..."); //Запрос ко второй БД
#457 #1091104
>>1091099
Теперь понял.

Попытался сделать функцию поиска по БД. В итоге, не запускается сам сайт.
https://ideone.com/BPkJFw
#458 #1091113
Я тут немного иначе выполнил задачку из http://archive-ipq-co.narod.ru/l1/functions.html
https://ideone.com/r8YS3J

Это верная мысль, что в return нельзя указать имя переменной, которая не была передана функции?
#459 #1091116
>>1090979
Спасибо, почитаю. Хотя я не совсем это имел ввиду весь этот процесс не я ведь устанавливаю.

Еще такой вопрос. У меня, как я сказал, не было опыта работы погромистом. Это норма, что мне порой целый день нихуя не дают заданий? Сижу весь день, под конец рабочего дня дадут пару правок на 2 минуты и все?

Поначалу ссался показаться ленивым хуйлом, самостоятельно что-то дофиксивал и уведомлял, что мол поправил то-то и то-то, но как понял заебую их этим. Необходимо просто забить хуй и смотреть смишные видосики пока заданий нет?
#460 #1091136
>>1091104
В добавок к вопросу, спрошу ещё вот что.
Я написал часть кода, где должна производиться запись в БД и столкнулся с разными трактовками того, как должна быть сделана запись.
Сейчас вообще ничего не записывается в БД. Мой код https://ideone.com/gTvALX , но вот при гуглинге я заметил, что в БД делают запись не строкой

$succeess = $mysqli-> query ("INSERT INTO 'sef' ('id', 'alias', 'link') VALUES ( '123', '$content' '123')" );
А вот на сайте https://daruse.ru/zapis-v-bazu-dannyix-mysql-php-formu указано так:
$result = mysql_query ("INSERT INTO ".$db_table." (name,text) VALUES ('$name','$text')");

Как правильно тогда?
#461 #1091144
>>1091136
Все заработало

Актуален только вопрос, почему тут используется $result = mysql_query , а не $succeess = $mysqli-> query
#462 #1091154
>>1091144
Процедурный и ООПшный стили.
А вообще mysql_... не стоит использовать...
#463 #1091158
>>1091136

>mysql_query


Это устаревшая функция. В php 7 она кажется вообще больше не работает.

Есть еще функция
$result = mysqli_query($mysqli, "INSERT...")
которая идентична по эффекту объектной записи
$result = $mysqli->query("INSERT...").

Это не говоря уже о том, что работать с базой данных можно еще и при помощи PDO класса. Т.е. это третий вариант.
Doctrine DBAL #464 #1091179
Почему в Doctrine DBAL когда передаю данные в MYSQL через dbal->prepare($sql) то все значения сохраняются как "0", а когда использую QueryBuilder то все сохраняется норм? Не могу понять в чем проблема. Кодировка таблицы utf8_unicode_ci, в настройках доктрины указана 'charset' => 'UTF8'.

Код https://pastebin.com/6u8AcKH4
#465 #1091208
Анчоус, может рассказать, как магия Докера работает?
#466 #1091246
>>1091208
двачую
#467 #1091248
>>1091208
Ну короче есть Докер, да? И он творит магию!
#468 #1091293
>>1082507 (OP)
Может можете посоветовать годные онлайн курсы по php?
#469 #1091311
Кто-то работал с Soap? Как сделать запрос из xml файлика?
#470 #1091359
>>1091068
задание то тестовое , не я то его придумал , ясен хрен что по 1 форме нормализации данных это булщит , хотя если там будут FK id то особо дело это не рещает , энивей через 3 юниона и джойны сделал
#471 #1091390
>>1091311
запрос нужно делать из файлика php
#472 #1091411
>>1091208

Что именно ты называешь магией? Насколько я знаю, магического в Докере ничего нету.

>>1091179

Судя по мануалу http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/data-retrieval-and-manipulation.html#dynamic-parameters-and-prepared-statements первый вариант кода должен работать, а во втором ошибка - нумерованные плейсхолдеры нумеруются с единицы, а не с нуля.

Однако, мне кажется, у тебя ошибка в SQL. Посмотри внимательно синтаксис оператора INSERT: https://dev.mysql.com/doc/refman/5.7/en/insert.html

Вместо значений ты передаешь результат сравнения (хотя я не очень понимаю, почему MySQL это разрешает, надо написать в багтрекер. Можешь скинуть результат запроса SHOW CREATE TABLE users\G ? ).

Указывать user_id, если у него там по умолчанию значение NULL, не надо.

В первом варианте нужно явно указать имена колонок, иначе корректность запроса зависит от порядка, в котором они идут в таблице.
#473 #1091421
В теме ооп есть задание: сделать подсказку. Какой подсказка должна быть? Я просто не очень понимаю..
#474 #1091431
Вопрос от нуба: зачем некоторые кодеры называют переменные, начиная со знака нижнего подчеркивания (например $_var)? Загуглил, что это вроде нужно чтобы обозначить переменную как глобальную. Почему тогда иногда свойства класса так иногда называют? Нужно ли так делать?
#475 #1091480
>>1090908
с точки зрения бизнеса не выгодно давать макаке гранату

>>1091116
необходимо развиваться дальше, если есть свободное время, а то потом поймешь, что тебе ужасно надоело это костыляние, а ты уже 2 года проработал и уровень у тебя чуть лучше, чем в начале работы

>>1091293
Из шапки. Отвечаю, то как ОП будет придрачиваться к каждой строчке, ни на каких курсах такого нет. 99% курсов по PHP - это то, что ты бы нагуглил за пару недель сам. Ну или опять же выполнил бы все начальные задания из шапки.

Я вот сейчас прохожу курсы по Symfony от самих разработчиков. И да, они классные, но они на уровне "В symfony есть такие-то возможности, давайте воспользуемся каждой по минимуму". То есть ознакомительные. Всё равно потом при работе над своим проектом нужно будет читать доки, да спрашивать советы
#476 #1091484
Что если главная страница будет на штмл, а сервер на пхп? это не смертельно? много возможностей теряю? нужно чтобы при отправке и получении запросов менялось содержимое сайта без перезгрузки. могу на ajax выполнить, на пхп внятных и простых в освоении способов не нашёл
#477 #1091502
>>1091116
Предъявляй претензии и постоянно напоминай о том, что у тебя нет задач. А иначе зачем они тебя взяли? Я вот джуном задалбывал тимлидов и менеджеров, жалуясь на отсутствие задач. И спустя время меня за это похвалили. Будет ситуация, когда руководитель компании у тимлида/менеджера спросит, что сделал тот новичок за пару недель, хорошо ли справляется с задачами. Как думаешь, тимлиду/менеджеру будет что рассказать, если ты частенько просто сидел без работы или фиксил мелкие баги?

>>1091431
Когда-то в PHP не было спецификаторов доступа (private, protected, public) и чтобы пометить для пользователя класса, что свойство или метод является приватным, использовали нижнее подчёркивание. Сейчас в PHP есть спецификаторы доступа и использовать нижнее подчёркивание категорически не следует (почитай исходники современных фреймворков - Laravel/Symfony, там никто это не использует). Кстати, в таких языках как JS и Python часто используют нижнее подчёркивание и по сей день, так как спецификаторов доступа там нет. Правда в JS можно использовать паттерн модуль и экспортировать не все данные - например только один метод. Всё остальное не будет видно за пределами модуля, а значит будет "приватным".

>>1091480
Про ОПа не согласен с тобой, неудачное ты слово подобрал - его замечания очень ценные и совсем не дотошные. Мне они пригодились когда-то на собеседовании и пригождаются сейчас на работе.
#478 #1091508
У кого-нибудь есть пример решения задачи "Экранирование" отсюда https://github.com/codedokode/pasta/blob/master/soft/web-server.md
#479 #1091512
>>1091502

>неудачное ты слово подобрал


Я в положительном смысле
#480 #1091519
https://ideone.com/R9FRMp

Сделал домашнее по ООП. Прошу проверить. Подсказка+ подсчет баллов
#481 #1091521
>>1091158
>>1091154
Ого! Т.е. я все это время работал с классами!
Спасибо!
#482 #1091522
>>1091113
Бамп вопросу! Анон, я правильно выполнил задание? У меня часть кода отличается от того, что было написано в примере.
#483 #1091529
>>1091113
мысль неверная. Вернуть можно что угодно. Можно переменную, можно число, можно строку, можно функцию или класс, а можно ничего не возвращать.
#484 #1091531
>>1091529
Т.е. в такой форме https://ideone.com/v0GguR все также верно и без разницы, что в ретурне локальная переменная?
#485 #1091536
#486 #1091538
Накалякал калькулятор https://ideone.com/yEFzJi Выглядит страшненько, но, вроде, работает. Хотя от хитро расставленных скобок наверняка поломается.
#487 #1091550
>>1090534

Я тут еще кое-что вспомнил про тесты. Вот случаи, когда без тестов никак:

- ты пишешь приложение, поддерживающее несколько типов СУБД (MySQL, Postgres, Sqlite). Очевидно, что ты скорее всего работаешь с какой-то одной из них и не заметишь, что написал SQL запрос, который не поддерживается какой-то другой СУБД. Автоматический прогон тестов против всех 3 СУБД позволит обнаружить ошибку (либо тебе надо нанимать толпу ручных тестировщиков, которые будут каждую неделю выполнять одни и те же действия)

- большие рефакторинги. Вот например, я как-то адаптировал PHP7 для запуска на Windows XP. Как это сделать? Там море кода и вообще неочевидно, что именно надо менять, где код, который не поддерживает старые ОС. Но там, к счастью, есть тесты, которые тестируют различный функционал и при их запуске (когда возникает ошибка) становится видно, в каком месте проблема.

Ну и если продолжить: вот допустим, фейсбук решил написать свой компилирующий интерпретатор PHP (HHVM). Чтобы проверить, что он совместим с PHP, они могли бы использовать написанные на PHP тесты для оригинального PHP - программы должны выдавать одинаковый результат под любым из интерпретаторов.
#488 #1091551
>>1091071

Тебе стоит изучить хотя бы основы ООП. $mysql это объект, представляющий одно соединение с БД, и логично, что, имея соединение, ты можешь отправлять по нему в БД SQL запросы.

> Почему класс переходит в запрос


Не очень понял, что значит "переходит". И $mysql это не класс, а переменная, хранящая ссылку на объект.

>>1091074

Ну и зря. Где тут передаются параметры соединения с БД? Они откуда-то берутся неявно, а явная передача зависимостей делает код более понятным.

>>1091076

Тогда тебе надо сначала изучить функции и ООП, а только потом браться за работу с БД.

>>1091136

Для начала лучше почитать документацию, а не статьи рандомных анонимов из интернета. Для взаимодействия с БД есть разные расширения и библиотеки (mysql, mysqli, PDO) - потому и код разный. Открой мануал и посмотри:

http://php.net/manual/ru/mysql.php

Далее, ты допускаешь в своем коде возможность SQL инъекции, когда подставляешь данные напрямую в запрос:

> VALUES ('$name','$text')");



У меня есть урок по теме, как от этой уязвимости защититься: https://github.com/codedokode/pasta/blob/master/security/sql-injection.md

Также, функции, которые начинаются с mysql_ - они вообще устарели и в PHP7 по моему отключены.

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

Если ты работаешь с mysqli, то надо после каждого вызова метода проверять, не произошла ли ошибка. Иначе ошибки останутся незамеченными.

Урок на daruse написал человек, который в программировании вообще ничего не понимает, в коде уязвимости и используются устаревшие функции.

Я могу для ознакомления посоветовать начать с этой статьи https://habrahabr.ru/post/137664/ + офиц. мануала по PDO.
#488 #1091551
>>1091071

Тебе стоит изучить хотя бы основы ООП. $mysql это объект, представляющий одно соединение с БД, и логично, что, имея соединение, ты можешь отправлять по нему в БД SQL запросы.

> Почему класс переходит в запрос


Не очень понял, что значит "переходит". И $mysql это не класс, а переменная, хранящая ссылку на объект.

>>1091074

Ну и зря. Где тут передаются параметры соединения с БД? Они откуда-то берутся неявно, а явная передача зависимостей делает код более понятным.

>>1091076

Тогда тебе надо сначала изучить функции и ООП, а только потом браться за работу с БД.

>>1091136

Для начала лучше почитать документацию, а не статьи рандомных анонимов из интернета. Для взаимодействия с БД есть разные расширения и библиотеки (mysql, mysqli, PDO) - потому и код разный. Открой мануал и посмотри:

http://php.net/manual/ru/mysql.php

Далее, ты допускаешь в своем коде возможность SQL инъекции, когда подставляешь данные напрямую в запрос:

> VALUES ('$name','$text')");



У меня есть урок по теме, как от этой уязвимости защититься: https://github.com/codedokode/pasta/blob/master/security/sql-injection.md

Также, функции, которые начинаются с mysql_ - они вообще устарели и в PHP7 по моему отключены.

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

Если ты работаешь с mysqli, то надо после каждого вызова метода проверять, не произошла ли ошибка. Иначе ошибки останутся незамеченными.

Урок на daruse написал человек, который в программировании вообще ничего не понимает, в коде уязвимости и используются устаревшие функции.

Я могу для ознакомления посоветовать начать с этой статьи https://habrahabr.ru/post/137664/ + офиц. мануала по PDO.
#489 #1091552
>>1091116

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

Также, можешь изучать код проекта, чтобы, когда придет задача, быстрее найти нужное место.

Алсо, "эффективный менеджер" тут сказал бы что-нибудь вроде "не жди, пока тебе дадут задачу, найди ее сам".

>>1091113

В return можно указать любое выражение, не обязательно даже переменную. Нет, ты ошибаешься.

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

>>1091421

Ну например, есть вопрос "во сколько раз длина окружности больше, чем диаметр круга?". Посказка может быть "Это математическая константа, начинается на букву П". Можешь написать что угодно.

>>1091099

В URL базы данных разве можно указывать протокол HTTP? Думаю, там должно стоять просто имя сервера (fu.ru), так как MySQL использует свой бинарный протокол, а не HTTP.

Ты путаешь URL и доменное имя/IP адрес сервера.

>>1091098

> count($matches[2]) - это очень плохо писать в цикле. Правильно писать так:


У count() сложность O(1) и оно очень быстрое. Но насчет foreach согласен, правильнее использовать его для обхода массива.

> $sql запрос в таком виде как у тебя не безопасен. Нужно все параметры вводимые пользователем, предварительно обезвреживать при помощи следующей конструкции


Удобнее использовать плейсхолдеры.
#489 #1091552
>>1091116

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

Также, можешь изучать код проекта, чтобы, когда придет задача, быстрее найти нужное место.

Алсо, "эффективный менеджер" тут сказал бы что-нибудь вроде "не жди, пока тебе дадут задачу, найди ее сам".

>>1091113

В return можно указать любое выражение, не обязательно даже переменную. Нет, ты ошибаешься.

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

>>1091421

Ну например, есть вопрос "во сколько раз длина окружности больше, чем диаметр круга?". Посказка может быть "Это математическая константа, начинается на букву П". Можешь написать что угодно.

>>1091099

В URL базы данных разве можно указывать протокол HTTP? Думаю, там должно стоять просто имя сервера (fu.ru), так как MySQL использует свой бинарный протокол, а не HTTP.

Ты путаешь URL и доменное имя/IP адрес сервера.

>>1091098

> count($matches[2]) - это очень плохо писать в цикле. Правильно писать так:


У count() сложность O(1) и оно очень быстрое. Но насчет foreach согласен, правильнее использовать его для обхода массива.

> $sql запрос в таком виде как у тебя не безопасен. Нужно все параметры вводимые пользователем, предварительно обезвреживать при помощи следующей конструкции


Удобнее использовать плейсхолдеры.
#490 #1091554
>>1091088

Тебе надо почитать мануал, начиная с обзорной статьи http://php.net/manual/ru/mysql.php

> регулярное выражение для поиска ссылок в тексте.


Вообще, HTML код лучше разбирать в дерево DOM и искать ссылки в дереве. Твой код, например, найдет ссылку внутри HTML комментария, которая, очевидно, не выведется на странице. Также, твой код найдет не только тег <a>, но и любой, начинающийся с этой буквы. Он вообще довольно кривой.

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

> у переменной индекс равен 2, потому-что в БД создано 3 строки


Нет. Посмотри мануал по preg_match_all и в каком формате она возвращает результат. Это результат функции preg_match_all, а не данные из БД.

> $result_set - это специальный класс для получения данных из БД


Это объект, который представляет собой результат выполнения SQL запроса.

> превращаем класс в массив


нет

> это означает, что если $result_set ничего не будет найдено, то цикл просто не случится и соединение закроется.


Нет.

У меня ощущение, что тебе стоило бы получше изучить сам PHP, в частности ООП.

>>1091001

Ок, пока что решение неправильное. Есть ощущение, что ты просто наугад ставишь разные функции экранирования, толком не понимая, как они должны использоваться.

Ну вот рассмотрим кусочек кода:

> $text = htmlspecialchars($_GET["text"]);


В $text хранится экранированный для вывода в HTML текст

> $linkText = htmlspecialchars("?text={$text}&lt=1");


Этот экранированный текст вставляется в ссылку без правильного кодирования спецсимволов и затем ссылка экранируется второй раз.

Я тебе советую прочитать про URL, там написано про кодирование данных в параметрах ссылок:

https://github.com/codedokode/pasta/blob/master/network/urls.md

> $linkText = str_replace(array("\r\n", "\r", "\n", "\t", ' ', ' ', ' '), '', $linkText);


Это просто неправильно. Требуется сохранять все символы, а не удалять их.

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

То есть должно быть так:

$text = ...;
echo функция-экранирования-для-html($text);
$url = функция-экранирования-для-параметров-ссылок($text);

И тд.

Попробуй исправить и покажи исправленную версию, если что-то непонятно, задавай еще вопросы.

Дописал подсказки в саму задачу.
#490 #1091554
>>1091088

Тебе надо почитать мануал, начиная с обзорной статьи http://php.net/manual/ru/mysql.php

> регулярное выражение для поиска ссылок в тексте.


Вообще, HTML код лучше разбирать в дерево DOM и искать ссылки в дереве. Твой код, например, найдет ссылку внутри HTML комментария, которая, очевидно, не выведется на странице. Также, твой код найдет не только тег <a>, но и любой, начинающийся с этой буквы. Он вообще довольно кривой.

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

> у переменной индекс равен 2, потому-что в БД создано 3 строки


Нет. Посмотри мануал по preg_match_all и в каком формате она возвращает результат. Это результат функции preg_match_all, а не данные из БД.

> $result_set - это специальный класс для получения данных из БД


Это объект, который представляет собой результат выполнения SQL запроса.

> превращаем класс в массив


нет

> это означает, что если $result_set ничего не будет найдено, то цикл просто не случится и соединение закроется.


Нет.

У меня ощущение, что тебе стоило бы получше изучить сам PHP, в частности ООП.

>>1091001

Ок, пока что решение неправильное. Есть ощущение, что ты просто наугад ставишь разные функции экранирования, толком не понимая, как они должны использоваться.

Ну вот рассмотрим кусочек кода:

> $text = htmlspecialchars($_GET["text"]);


В $text хранится экранированный для вывода в HTML текст

> $linkText = htmlspecialchars("?text={$text}&lt=1");


Этот экранированный текст вставляется в ссылку без правильного кодирования спецсимволов и затем ссылка экранируется второй раз.

Я тебе советую прочитать про URL, там написано про кодирование данных в параметрах ссылок:

https://github.com/codedokode/pasta/blob/master/network/urls.md

> $linkText = str_replace(array("\r\n", "\r", "\n", "\t", ' ', ' ', ' '), '', $linkText);


Это просто неправильно. Требуется сохранять все символы, а не удалять их.

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

То есть должно быть так:

$text = ...;
echo функция-экранирования-для-html($text);
$url = функция-экранирования-для-параметров-ссылок($text);

И тд.

Попробуй исправить и покажи исправленную версию, если что-то непонятно, задавай еще вопросы.

Дописал подсказки в саму задачу.
#491 #1091555
>>1091070

Ну во-первых, не только кириллица, а любые символы не из ASCII (вот, что если там например, неразрывный пробел?). Во-вторых, не только в тексте, но и в самом регулярном выражении. Все же по моему, проще этот флаг везде использовать.

>>1090962

> public function getSalary(){


Раз уж ты используешь PHP7, используй и возможность указывать тип возвращаемого функцией значения ( http://php.net/manual/ru/functions.returning-values.php ):

public function getSalary(): float

Обрати внимание, что в 7.1 добавили возможность также указать, что функция ничего не возвращает: http://php.net/manual/ru/migration71.new-features.php

Это поможет тебе обнаружить ошибки в своем коде и сделает его понятнее для чтения.

> abstract class AbstractWorker{


В классах и методах скобка ставится на новой строке (а в if/for - на той же самой).

> $pages *= 0;


Лучше написать $pages = 0, иначе можно подумать, что это какой-то хитрый хак. То есть непонятно на первый взгляд, зачем тут стоит умножение.

> abstract function getBasicSalary();


Тут стоило добавить public

> public function addWorkersToDepartment(string $profession, int $count, int $rang, int $isBoss){


Это лучше убрать из Департамента и вынести отдельно, так как это не совсем его задача - создавать работников.

> if ($profession == "Manager"){


Тут удобнее использовать имя класса, которое можно получить из специальной встроенной константы class ( http://php.net/manual/ru/language.oop5.constants.php ):

if ($profession == Manager::class)

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

> calculatiotOfOutput


Имя метода должно начинаться с глагола, плюс этот метод ничего не считает, а только выводит, потому логичнее его было назвать не calculate, а printRow.

В коде вывода много раз повторяются однотипные громоздкие конструкции вроде $departmentInformation["name"] = ...

Тут было лучше написать:

$departmentData = [
'name' => ...,
'coffee' => ....,
...
];

Также, тут не очень много колонок и можно было в функции вывода просто сделать 6 аргументов:

function printRow($name, $count, $salary, $coffee, ...)

Также, можно было использовать массив с числовыми индексами:

$departmentData = [
$dep->getName(),
$dep->getCoffee(),
....
];

В общем, сделано неплохо, но получится ли у тебя так же хорошо сделать антикризисные меры?
#491 #1091555
>>1091070

Ну во-первых, не только кириллица, а любые символы не из ASCII (вот, что если там например, неразрывный пробел?). Во-вторых, не только в тексте, но и в самом регулярном выражении. Все же по моему, проще этот флаг везде использовать.

>>1090962

> public function getSalary(){


Раз уж ты используешь PHP7, используй и возможность указывать тип возвращаемого функцией значения ( http://php.net/manual/ru/functions.returning-values.php ):

public function getSalary(): float

Обрати внимание, что в 7.1 добавили возможность также указать, что функция ничего не возвращает: http://php.net/manual/ru/migration71.new-features.php

Это поможет тебе обнаружить ошибки в своем коде и сделает его понятнее для чтения.

> abstract class AbstractWorker{


В классах и методах скобка ставится на новой строке (а в if/for - на той же самой).

> $pages *= 0;


Лучше написать $pages = 0, иначе можно подумать, что это какой-то хитрый хак. То есть непонятно на первый взгляд, зачем тут стоит умножение.

> abstract function getBasicSalary();


Тут стоило добавить public

> public function addWorkersToDepartment(string $profession, int $count, int $rang, int $isBoss){


Это лучше убрать из Департамента и вынести отдельно, так как это не совсем его задача - создавать работников.

> if ($profession == "Manager"){


Тут удобнее использовать имя класса, которое можно получить из специальной встроенной константы class ( http://php.net/manual/ru/language.oop5.constants.php ):

if ($profession == Manager::class)

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

> calculatiotOfOutput


Имя метода должно начинаться с глагола, плюс этот метод ничего не считает, а только выводит, потому логичнее его было назвать не calculate, а printRow.

В коде вывода много раз повторяются однотипные громоздкие конструкции вроде $departmentInformation["name"] = ...

Тут было лучше написать:

$departmentData = [
'name' => ...,
'coffee' => ....,
...
];

Также, тут не очень много колонок и можно было в функции вывода просто сделать 6 аргументов:

function printRow($name, $count, $salary, $coffee, ...)

Также, можно было использовать массив с числовыми индексами:

$departmentData = [
$dep->getName(),
$dep->getCoffee(),
....
];

В общем, сделано неплохо, но получится ли у тебя так же хорошо сделать антикризисные меры?
#492 #1091556
>>1090954

Что значит "не предназначен для запуска на ПК"? Не компилируется в exe-файл? Да, это верно, но тогда так и надо говорить "не предназначен для компиляции в exe под Windows". Запускать на ПК его можно в командной строке, в линуксе даже команду php для этого писать не требуется.

Алсо, есть сторонние "компиляторы", которые как-то упаковывают php и скрипт в общий exe файл, но на него потом ругаются антивирусы.

>>1090928

Наверно, лучше на свой сервер. Тогда, даже если доступ к CDN заблокируют или с CDN что-то случится, сайт будет корректно работать.
#493 #1091561
>>1091531

Ты возвращаешь из функции не переменную, а значение выражения (число, строку, массив, объект). Потому неважно, что она локальная, недоступна снаружи и будет уничтожена при выходе из функции.
#494 #1091564
>>1091529

Поправлю: объект можно, класс нельзя, так как в PHP нет значений, представляющих класс.
#495 #1091569
>>1091529

Исчерпывающий список типов значений в PHP (для всех любопытных анонов): http://php.net/manual/ru/language.types.php
#496 #1091574
>>1091556

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


Не соглашусь. Вот тут объяснено на примере jQuery
https://stackoverflow.com/questions/2180391/why-should-i-use-googles-cdn-for-jquery
#497 #1091582
>>1091574

Ну давай разберем, что там понаписали:

> It increases the parallelism available.


> (Most browsers will only download 3 or 4 files at a time from any given site.)


Верно, в HTTP/1.1 есть ограничение - можно использовать максимум 6 параллельных на 1 домен. Но в HTTP/2 ограничение сильно поднято, до десятков и сотен запросов и задается настройкой сервера. То есть проблема неактуальна.

> It increases the chance that there will be a cache-hit.


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

> It ensures that the payload will be as small as possible.


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

> It ensures that the user will get a geographically close response.


Здесь есть важный момент: не факт, что для твоего сайта в Челябинске рядом окажется узел CDN. Все же CDN рассчитаны на весь мир, и для России там будут узлы в Москве в лучшем случае (хотя конечно, тут надо смотреть на конкретный CDN). А если пользователь китайского сайта в Китае? Там вообще иностранные сервера плохо доступны.

> They will automatically keep your scripts up to date.


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

Теперь поговорим про недостатки:

1) ты кладешь на CDN единственную библиотеку, в то время как все остальное на твоем сервере. Велик ли выигрыш? Стоит ли мучаться?
2) Добавление еще одного сервера снижает (пусть и пренебрежительно мало) общую надежность кода. В сети ты можешь увидеть даже примеры, где jquery грузится сначала с CDN , а при ошибке - локально, и эти примеры кривые, так как там будет очень большой таймаут при ошибке (минуты).
3) В некоторых странах (кхм) размещение кода на иностранных серверах повышает риски недоступности сайта. В Китае доступ к иностранным серверам медленнее из-за фаерволла.
4) при запросе файла с внешнего сервера владелец сервера может получить информацию о пользователе: время, IP адрес, referer (URL страницы, при загрузке которой сделан запрос). Он может установить 3rd party cookie для дальнейшего отслеживания того же пользователя. Давайте не будем скрывать: многие не удержатся от соблазна накапливать и продавать информацию о пользователях, особенно в странах где слабо защищаются персональные данные (то есть везде, кроме Евросоюза).

Бороться с этим в новых браузерах можно с помощью анонимных запросов: https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_settings_attributes

Некоторые браузеры в некоторых случаях блокируют 3rd party cookies.

Однако, судя по https://html.spec.whatwg.org/multipage/scripting.html#attr-script-crossorigin для классических скриптов вроде jQuery это может не работать.

Если бы они отключили куки и реферер, может я бы и отказался от этой претензии.

5) владелец CDN может подменить скрипт. Защита: https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity

Также, когда-то (тогда у jquery еще не было нормального CDN) я подключил на сайт загрузку jquery с его сайта. И надо же - буквально на следующий день, когда сайт надо было показывать заказчику, сайт jquery лег и положил мой сайт.

Тут конечно еще многое зависит от способ подключения. При асинхронном подключении и проблеме с CDN сайт загрузится, но без скриптов. При классическом подключении сайт подвиснет на строчке с подключением скрипта.

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

Ты бы мог привести в пример подключение шрифтов - шрифты с google fonts подключать проще, чем конвертировать вручную. Но и тут есть минус - так ты не научишься конвертировать шрифты и не изучишь их форматы.
#497 #1091582
>>1091574

Ну давай разберем, что там понаписали:

> It increases the parallelism available.


> (Most browsers will only download 3 or 4 files at a time from any given site.)


Верно, в HTTP/1.1 есть ограничение - можно использовать максимум 6 параллельных на 1 домен. Но в HTTP/2 ограничение сильно поднято, до десятков и сотен запросов и задается настройкой сервера. То есть проблема неактуальна.

> It increases the chance that there will be a cache-hit.


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

> It ensures that the payload will be as small as possible.


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

> It ensures that the user will get a geographically close response.


Здесь есть важный момент: не факт, что для твоего сайта в Челябинске рядом окажется узел CDN. Все же CDN рассчитаны на весь мир, и для России там будут узлы в Москве в лучшем случае (хотя конечно, тут надо смотреть на конкретный CDN). А если пользователь китайского сайта в Китае? Там вообще иностранные сервера плохо доступны.

> They will automatically keep your scripts up to date.


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

Теперь поговорим про недостатки:

1) ты кладешь на CDN единственную библиотеку, в то время как все остальное на твоем сервере. Велик ли выигрыш? Стоит ли мучаться?
2) Добавление еще одного сервера снижает (пусть и пренебрежительно мало) общую надежность кода. В сети ты можешь увидеть даже примеры, где jquery грузится сначала с CDN , а при ошибке - локально, и эти примеры кривые, так как там будет очень большой таймаут при ошибке (минуты).
3) В некоторых странах (кхм) размещение кода на иностранных серверах повышает риски недоступности сайта. В Китае доступ к иностранным серверам медленнее из-за фаерволла.
4) при запросе файла с внешнего сервера владелец сервера может получить информацию о пользователе: время, IP адрес, referer (URL страницы, при загрузке которой сделан запрос). Он может установить 3rd party cookie для дальнейшего отслеживания того же пользователя. Давайте не будем скрывать: многие не удержатся от соблазна накапливать и продавать информацию о пользователях, особенно в странах где слабо защищаются персональные данные (то есть везде, кроме Евросоюза).

Бороться с этим в новых браузерах можно с помощью анонимных запросов: https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_settings_attributes

Некоторые браузеры в некоторых случаях блокируют 3rd party cookies.

Однако, судя по https://html.spec.whatwg.org/multipage/scripting.html#attr-script-crossorigin для классических скриптов вроде jQuery это может не работать.

Если бы они отключили куки и реферер, может я бы и отказался от этой претензии.

5) владелец CDN может подменить скрипт. Защита: https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity

Также, когда-то (тогда у jquery еще не было нормального CDN) я подключил на сайт загрузку jquery с его сайта. И надо же - буквально на следующий день, когда сайт надо было показывать заказчику, сайт jquery лег и положил мой сайт.

Тут конечно еще многое зависит от способ подключения. При асинхронном подключении и проблеме с CDN сайт загрузится, но без скриптов. При классическом подключении сайт подвиснет на строчке с подключением скрипта.

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

Ты бы мог привести в пример подключение шрифтов - шрифты с google fonts подключать проще, чем конвертировать вручную. Но и тут есть минус - так ты не научишься конвертировать шрифты и не изучишь их форматы.
#498 #1091584
>>1091574

По твоей же ссылке, кстати, описаны те же недостатки. В том числе про Китай.
#499 #1091603
Что такое $this ? В этом коде https://ideone.com/v0C99M
https://github.com/Qevg/Student-list #500 #1091604
Обещанного 3 года ждут, как говорится.

>>1074848


>>1082512

> `firstname` varchar(255) NOT NULL,


255 символов - не слишком много? Алсо, ограничение на 256 символов в MySQL нету.

Длина поля влияет на размер индексов по этому полю.

> firstname


> groupNum


Логично тогда и первое поле назвать firstName.

> `hash` varchar(255) NOT NULL,


Тут нужен комментарий (COMMENT '...')

> DEFAULT CHARSET=utf8;


Советую utf8mb4, так как utf8 (несмотря на название) - это не полноценный utf-8, а только символы из Basic Multilingual Plane и он не включает, например, популярные в последнее время эмодзи.

https://medium.com/@adamhooper/in-mysql-never-use-utf8-use-utf8mb4-11761243e434

Из минусов: под строки в utf8mb4 резервируется 4 байта на символ, а не 3, как в utf8.

> $router = new Router;


> $router->start($container);



Было бы логично передавать $container в конструктор в рамках DI. Также, роутер можно было бы сам засунуть в контейнер. Ну и такой роутер можно еще назвать Front Controller: http://design-pattern.ru/patterns/front-controller.html

> Hide alert alert in 3 seconds


Вообще, это плохая идея, так как пользователь мог на что-то отвлечься и не увидеть уведомление.

https://github.com/Qevg/Student-list/blob/master/app/container.php#L10
Тут можно было бы добавить проверку, так как json_decode вернет null при ошибке синтаксиса.

https://github.com/Qevg/Student-list/blob/master/app/Router.php
Если передан неверный URL, твой роутер все равно попытается вызвать контроллер. Ну, например, возьмем URL

/register/index/1/2/3

Он приведет к вызову того же контроллера, что и /register или /register/index или /register/index/. Но это плохо - ведь URL является указателем на страницу и не очень хорошо, когда у одной страницы много разных URL. И с точки зрения логики плохо, и поисковые системы это негативно воспримут.

Также, эта схема - жесткая привязка к именам контроллеров и методов - не оченть хорошая. Зачем себя ставить в рамки? Можно просто делать произвольные URL любой структуры, у меня даже урок есть по теме: https://gist.github.com/codedokode/772a4ccc03e41d6b7cba

При ошибке ты выбрасываешь throw new NotFoundException(). Но его у тебя никто не ловит, и это приведет к тому, что PHP отобразит белую страницу с HTTP кодом 200. А должно быть 404. Подробнее - в моем уроке про обработку исключений.

В базовом классе Controller стоило сделать конструктор, который получает на вход контейнер и View. А в наследниках - вызывать его.

> $countStudent = $this->c['StudentGateway']->getCountStudent($search);


Это (тем более, оно повторяется несколько раз) смотрится довольно некрасиво, лучше поместить studentGateway в отдельную переменную или поле.

https://github.com/Qevg/Student-list/blob/master/app/Validators/Validator.php#L9

> validateSearch($studentGW, $data)


Неудачно выбран формат аргументов. studentGW не используется (его лучше внедрять через DI), а data почему-то представляет собой массив, из которого берется один элемент. Не проще его и передавать?

Также, метод валидации почему-то ничего не возвращает, а меняет только состояние объекта. Не логичнее ли сразу возвращать "исправленное" значение? Или метод логичнее назвать setSearchQuery().

Также, не логичнее ли вместо массива $value сделать отдельные свойства? Что у тебя вообще представляет объект Validator? Набор параметров для вывода студентов? Набор параметров для вывода произвольной таблицы? Тогда его так и надо было назвать, ViewParameters например или DisplayOptions или StudentFilter или TableFilter. Правда, cookie сюда не вписывается никак.

Можно было бы добавить тогда метод parseFromArray, который бы сразу задавал все параметры поиска из массива.

То есть, надо бы еще подумать над этим классом. А то пока как минимум названия сбивают с толку.

В контроллере объект валидатора логичнее хранить в простой переменной, а не в поле. Зачем там поле?

Авторизация не вынесена полностью в объект Authorisation. Получение и проверка куки помещены в контроллер. Не лучше ли было это как-то все засунуть в класс?

> if (isset($_GET['logout'])) {


> $this->authorization->logOut($hash);


Зачем это в контроллере главной страницы? для этого лучше сделать отдельный роут и отдельный action.

> $this->authorization->logOut($hash);


> header("Location: home");


У тебя скрипт не завершается после редиректа.

> session_start();


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

> $this->view->render(


> compact(


> 'students',


> 'urlGenerator',


> 'isAuth',


> 'userName',


> 'message',


> 'countStudent',


> 'countPage',



Многовато параметров для такой простой страницы. Если у тебя есть объект, представляющий параметры отображения таблицы, можно передавать его, а не параметры по отдельности.

https://github.com/Qevg/Student-list/blob/master/app/Databases/StudentDataGateway.php#L11

> public function __construct($db)


Нужен тайп хинт. Ты, кстати, PHP7 или PHP5 как мин. требование поставил? Если PHP7, то нужно поставить их везде. И в идеале, тайп хинт на возвращаемые значения.

Минимальную версию PHP стоит прописать в composer.json.

https://github.com/Qevg/Student-list/blob/master/app/Databases/StudentDataGateway.php#L52
Зачем тут JOIN на подзапрос?

> if ($this->getCountStudent($search) > 0) {


> $stmt->execute();


Не вижу особого смысла ставить такую проверку, так как это ведь по сути лишний запрос.

В поиске я бы рекомендовал еще в поисковой фразе сжимать пробелы и спецсимволы и заменять их на % тоже.

> $stmt->bindValue(':hash', $hash, \PDO::PARAM_STR);


> $stmt->execute()


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

> public function editStudent(Student $student)


Правильнее наверно updateStudent.

https://github.com/Qevg/Student-list/blob/master/app/Entity/Student.php#L23

> public function setValue($value)


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

https://github.com/Qevg/Student-list/blob/master/app/Exceptions/BadRequestException.php
Исключение реализовано неправильно. Исключение - это объект, который представляет (хранит) информацию об ошибке. Он не должен при создании выдавать заголовки и что-то выводить - мы этого не просили. Представь, что мы например из базы данных загрузили информацию о предыдущей ошибке и создали для нее объект исключения.

Почитай мой урок про исключения https://github.com/codedokode/pasta/blob/master/php/exceptions.md

https://github.com/Qevg/Student-list/blob/master/app/Helpers/UrlGenerator.php
Название не очень точное, можно подумать, это генератор любых URL, а нет, только URL для таблицы со списком.

https://github.com/Qevg/Student-list/blob/master/app/Helpers/CSRFProtection.php#L9
Тут по моему ошибка. Почему токен берется из POST? Правильный токен хранитя в куках, а в POST приходит токен, которому мы не доверяем, и который должны проверить.

> if (!isset($_COOKIE['token'])


Мало это проверить, надо бы еще проверить, что он не равен пустой строке.

> $_COOKIE['token'] != $_POST['token'])


Использовано нестрогое сравнение. Почитай мануал про == и ===.
https://github.com/Qevg/Student-list #500 #1091604
Обещанного 3 года ждут, как говорится.

>>1074848


>>1082512

> `firstname` varchar(255) NOT NULL,


255 символов - не слишком много? Алсо, ограничение на 256 символов в MySQL нету.

Длина поля влияет на размер индексов по этому полю.

> firstname


> groupNum


Логично тогда и первое поле назвать firstName.

> `hash` varchar(255) NOT NULL,


Тут нужен комментарий (COMMENT '...')

> DEFAULT CHARSET=utf8;


Советую utf8mb4, так как utf8 (несмотря на название) - это не полноценный utf-8, а только символы из Basic Multilingual Plane и он не включает, например, популярные в последнее время эмодзи.

https://medium.com/@adamhooper/in-mysql-never-use-utf8-use-utf8mb4-11761243e434

Из минусов: под строки в utf8mb4 резервируется 4 байта на символ, а не 3, как в utf8.

> $router = new Router;


> $router->start($container);



Было бы логично передавать $container в конструктор в рамках DI. Также, роутер можно было бы сам засунуть в контейнер. Ну и такой роутер можно еще назвать Front Controller: http://design-pattern.ru/patterns/front-controller.html

> Hide alert alert in 3 seconds


Вообще, это плохая идея, так как пользователь мог на что-то отвлечься и не увидеть уведомление.

https://github.com/Qevg/Student-list/blob/master/app/container.php#L10
Тут можно было бы добавить проверку, так как json_decode вернет null при ошибке синтаксиса.

https://github.com/Qevg/Student-list/blob/master/app/Router.php
Если передан неверный URL, твой роутер все равно попытается вызвать контроллер. Ну, например, возьмем URL

/register/index/1/2/3

Он приведет к вызову того же контроллера, что и /register или /register/index или /register/index/. Но это плохо - ведь URL является указателем на страницу и не очень хорошо, когда у одной страницы много разных URL. И с точки зрения логики плохо, и поисковые системы это негативно воспримут.

Также, эта схема - жесткая привязка к именам контроллеров и методов - не оченть хорошая. Зачем себя ставить в рамки? Можно просто делать произвольные URL любой структуры, у меня даже урок есть по теме: https://gist.github.com/codedokode/772a4ccc03e41d6b7cba

При ошибке ты выбрасываешь throw new NotFoundException(). Но его у тебя никто не ловит, и это приведет к тому, что PHP отобразит белую страницу с HTTP кодом 200. А должно быть 404. Подробнее - в моем уроке про обработку исключений.

В базовом классе Controller стоило сделать конструктор, который получает на вход контейнер и View. А в наследниках - вызывать его.

> $countStudent = $this->c['StudentGateway']->getCountStudent($search);


Это (тем более, оно повторяется несколько раз) смотрится довольно некрасиво, лучше поместить studentGateway в отдельную переменную или поле.

https://github.com/Qevg/Student-list/blob/master/app/Validators/Validator.php#L9

> validateSearch($studentGW, $data)


Неудачно выбран формат аргументов. studentGW не используется (его лучше внедрять через DI), а data почему-то представляет собой массив, из которого берется один элемент. Не проще его и передавать?

Также, метод валидации почему-то ничего не возвращает, а меняет только состояние объекта. Не логичнее ли сразу возвращать "исправленное" значение? Или метод логичнее назвать setSearchQuery().

Также, не логичнее ли вместо массива $value сделать отдельные свойства? Что у тебя вообще представляет объект Validator? Набор параметров для вывода студентов? Набор параметров для вывода произвольной таблицы? Тогда его так и надо было назвать, ViewParameters например или DisplayOptions или StudentFilter или TableFilter. Правда, cookie сюда не вписывается никак.

Можно было бы добавить тогда метод parseFromArray, который бы сразу задавал все параметры поиска из массива.

То есть, надо бы еще подумать над этим классом. А то пока как минимум названия сбивают с толку.

В контроллере объект валидатора логичнее хранить в простой переменной, а не в поле. Зачем там поле?

Авторизация не вынесена полностью в объект Authorisation. Получение и проверка куки помещены в контроллер. Не лучше ли было это как-то все засунуть в класс?

> if (isset($_GET['logout'])) {


> $this->authorization->logOut($hash);


Зачем это в контроллере главной страницы? для этого лучше сделать отдельный роут и отдельный action.

> $this->authorization->logOut($hash);


> header("Location: home");


У тебя скрипт не завершается после редиректа.

> session_start();


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

> $this->view->render(


> compact(


> 'students',


> 'urlGenerator',


> 'isAuth',


> 'userName',


> 'message',


> 'countStudent',


> 'countPage',



Многовато параметров для такой простой страницы. Если у тебя есть объект, представляющий параметры отображения таблицы, можно передавать его, а не параметры по отдельности.

https://github.com/Qevg/Student-list/blob/master/app/Databases/StudentDataGateway.php#L11

> public function __construct($db)


Нужен тайп хинт. Ты, кстати, PHP7 или PHP5 как мин. требование поставил? Если PHP7, то нужно поставить их везде. И в идеале, тайп хинт на возвращаемые значения.

Минимальную версию PHP стоит прописать в composer.json.

https://github.com/Qevg/Student-list/blob/master/app/Databases/StudentDataGateway.php#L52
Зачем тут JOIN на подзапрос?

> if ($this->getCountStudent($search) > 0) {


> $stmt->execute();


Не вижу особого смысла ставить такую проверку, так как это ведь по сути лишний запрос.

В поиске я бы рекомендовал еще в поисковой фразе сжимать пробелы и спецсимволы и заменять их на % тоже.

> $stmt->bindValue(':hash', $hash, \PDO::PARAM_STR);


> $stmt->execute()


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

> public function editStudent(Student $student)


Правильнее наверно updateStudent.

https://github.com/Qevg/Student-list/blob/master/app/Entity/Student.php#L23

> public function setValue($value)


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

https://github.com/Qevg/Student-list/blob/master/app/Exceptions/BadRequestException.php
Исключение реализовано неправильно. Исключение - это объект, который представляет (хранит) информацию об ошибке. Он не должен при создании выдавать заголовки и что-то выводить - мы этого не просили. Представь, что мы например из базы данных загрузили информацию о предыдущей ошибке и создали для нее объект исключения.

Почитай мой урок про исключения https://github.com/codedokode/pasta/blob/master/php/exceptions.md

https://github.com/Qevg/Student-list/blob/master/app/Helpers/UrlGenerator.php
Название не очень точное, можно подумать, это генератор любых URL, а нет, только URL для таблицы со списком.

https://github.com/Qevg/Student-list/blob/master/app/Helpers/CSRFProtection.php#L9
Тут по моему ошибка. Почему токен берется из POST? Правильный токен хранитя в куках, а в POST приходит токен, которому мы не доверяем, и который должны проверить.

> if (!isset($_COOKIE['token'])


Мало это проверить, надо бы еще проверить, что он не равен пустой строке.

> $_COOKIE['token'] != $_POST['token'])


Использовано нестрогое сравнение. Почитай мануал про == и ===.
https://github.com/Qevg/Student-list #501 #1091606

>>1074848


>>1082512

https://github.com/Qevg/Student-list/blob/master/app/Helpers/Util.php#L28

> public static function sort($name, $sort)


Непонятно (глядя на функцию), почему здесь в $sort передается массив, а не 2 аргумента по отдельности. Непонятно, почему использован усложенный вариант.

https://github.com/Qevg/Student-list/blob/master/app/Helpers/Util.php#L14

> random_bytes($lenthHash / 2);


Здесь может получиться дробное число при делении.

https://github.com/Qevg/Student-list/blob/master/app/Helpers/Util.php#L20

> if ($search != null) {


Нестрогое сравнение с null значит что там может пройти пустая строка или 0.

https://github.com/Qevg/Student-list/blob/master/app/Helpers/Authorization.php#L14
Имя домена можно не указывать, см. мануал. По умолчанию там как раз будет текущий домен.

https://github.com/Qevg/Student-list/blob/master/app/Helpers/Authorization.php#L9

> return $studentGW->checkHash($cookie) > 0 ?


Почему checkHash не возвращает булево значение сразу?

https://github.com/Qevg/Student-list/blob/master/app/Helpers/AddRandomStudent.php
Можно было использовать готовую библиотеку Faker. https://github.com/fzaninotto/Faker - учти на будущее.

https://github.com/Qevg/Student-list/blob/master/app/Validators/StudentValidator.php
Здесь опять проблема: неочевидные способы передачи данных. Данные передаются в один метод, из другого метода берется список ошибок... Почему бы не сделать это прямолинейнее? Есть какая-то выгода от хранения состояния (ошибки, данные) в полях валидатора?

Ты попытался обобщить правила валидации с помощью массива. Неплохо. Но не хочешь попробовать вместо массива сделать нормальную, расширяемую ООП-модель? Ну например, сделать объект для каждого "правила валидации" или сделать объект вроде "валидатор длины строки"... Тут можно хорошо поломать голову и подучить проектирование классов. Я бы советовал попробовать.

https://github.com/Qevg/Student-list/blob/master/app/Validators/StudentValidator.php#L162

> public function getRegexpForClient($name)


Здесь надо кое-что учесть. В PHP используется диалект выражений PCRE ( http://php.net/manual/ru/pcre.pattern.php ), в то время как в JS - свой диалект из стандарта JS ( http://www.regular-expressions.info/javascript.html ). Они различаются в мелких деталях. Следовательно, ты должен писать выражения, которые эквиваленты в обоих диалектах. Об этом надо хотя бы комментарий написать в коде. Или же делать по 2 версии каждого выражения.

Еще, если ты используешь IDE, ты можешь улучшить автодополнение за счет phpDoc ( https://docs.phpdoc.org/guides/index.html ) , например:

/** @var Validator */
private $validator;

Тогда при наборе $this->validator появится автодополнение. Вообще-то phpDoc придумывался для генерации документации из кода (пример сгенерированной документации: http://api.symfony.com/2.8/Symfony/Component/Form.html ), но IDE тоже умеют использовать аннотации для своих целей.

https://github.com/Qevg/Student-list/blob/master/app/Views/View.php
Шаблоны можно было положить в отдельную папку, это все таки не классы.

extract() лучше поместить в класс View.

> <p style="margin-bottom: 0px">


Это лучше выносить в CSS файл.

> <div class="form-group col-lg-10 col-md-10 col-sm-10 col-xs-10">


Там если ширина всегда одинаковая, можно использовать какой-то один общий класс, может быть col-10 или как-то так.

> &laquo


Точки с запятой не хватает.

Для таблицы адаптивность конечно не очень хорошо работает сужением колонок, нереально ли просто переформатировать все, например, выводить в одной строке - Имя/фамилию, а под ней мелким шрифтом группу и число баллов. А то получается механическая адаптивность, формальная, не продуманная. Не хочешь попробовать?

Я протестировал даже: https://jsfiddle.net/mx01cLzd/ (попробуй менять ширину окошка) - в новых браузерах (не знаю, с какого момента. попробуй выяснить), можно с помощью display убрать у элементов таблиц значение вроде table, table-cell и они "превратятся" в (будут отображаться как) обычные дивы.

Еще, по адпативности, не старайся поддерживать слишком много разрешений - это увеличивает трудоемкость. Вот таблица размеров экранов мобильных устройств: https://mydevice.io/devices/

Код пагинации сложный и его можно вынести в отдельный шаблон для повторного использования. Может даже можно какие-то функции вынести в PHP-код, вроде определения, что надо и не надо выводить.

https://github.com/Qevg/Student-list/blob/master/app/Controllers/RegisterController.php
тут $student не лучше ли сделать просто переменной, а не полем?

Для вывода формы и валидации - не лучше ли использовать объект Student, а не массив?

> type="email" work only in Latin


Ага, баг видимо. Но тип email имеет свои преимущества - где-то, может быть будет возможность вставлять email из контактов (хотя не знаю, есть ли такое, если у тебя есть мобильные устройства, можешь проверить).

Так, если ты начинающий, то сделано хорошо, но есть что улучшить.

Если будешь делать следующую задачу, то советую попробовать использовать в ней другой шаблонизатор, другую СУБД (postgres например или sqlite) и тд.
https://github.com/Qevg/Student-list #501 #1091606

>>1074848


>>1082512

https://github.com/Qevg/Student-list/blob/master/app/Helpers/Util.php#L28

> public static function sort($name, $sort)


Непонятно (глядя на функцию), почему здесь в $sort передается массив, а не 2 аргумента по отдельности. Непонятно, почему использован усложенный вариант.

https://github.com/Qevg/Student-list/blob/master/app/Helpers/Util.php#L14

> random_bytes($lenthHash / 2);


Здесь может получиться дробное число при делении.

https://github.com/Qevg/Student-list/blob/master/app/Helpers/Util.php#L20

> if ($search != null) {


Нестрогое сравнение с null значит что там может пройти пустая строка или 0.

https://github.com/Qevg/Student-list/blob/master/app/Helpers/Authorization.php#L14
Имя домена можно не указывать, см. мануал. По умолчанию там как раз будет текущий домен.

https://github.com/Qevg/Student-list/blob/master/app/Helpers/Authorization.php#L9

> return $studentGW->checkHash($cookie) > 0 ?


Почему checkHash не возвращает булево значение сразу?

https://github.com/Qevg/Student-list/blob/master/app/Helpers/AddRandomStudent.php
Можно было использовать готовую библиотеку Faker. https://github.com/fzaninotto/Faker - учти на будущее.

https://github.com/Qevg/Student-list/blob/master/app/Validators/StudentValidator.php
Здесь опять проблема: неочевидные способы передачи данных. Данные передаются в один метод, из другого метода берется список ошибок... Почему бы не сделать это прямолинейнее? Есть какая-то выгода от хранения состояния (ошибки, данные) в полях валидатора?

Ты попытался обобщить правила валидации с помощью массива. Неплохо. Но не хочешь попробовать вместо массива сделать нормальную, расширяемую ООП-модель? Ну например, сделать объект для каждого "правила валидации" или сделать объект вроде "валидатор длины строки"... Тут можно хорошо поломать голову и подучить проектирование классов. Я бы советовал попробовать.

https://github.com/Qevg/Student-list/blob/master/app/Validators/StudentValidator.php#L162

> public function getRegexpForClient($name)


Здесь надо кое-что учесть. В PHP используется диалект выражений PCRE ( http://php.net/manual/ru/pcre.pattern.php ), в то время как в JS - свой диалект из стандарта JS ( http://www.regular-expressions.info/javascript.html ). Они различаются в мелких деталях. Следовательно, ты должен писать выражения, которые эквиваленты в обоих диалектах. Об этом надо хотя бы комментарий написать в коде. Или же делать по 2 версии каждого выражения.

Еще, если ты используешь IDE, ты можешь улучшить автодополнение за счет phpDoc ( https://docs.phpdoc.org/guides/index.html ) , например:

/** @var Validator */
private $validator;

Тогда при наборе $this->validator появится автодополнение. Вообще-то phpDoc придумывался для генерации документации из кода (пример сгенерированной документации: http://api.symfony.com/2.8/Symfony/Component/Form.html ), но IDE тоже умеют использовать аннотации для своих целей.

https://github.com/Qevg/Student-list/blob/master/app/Views/View.php
Шаблоны можно было положить в отдельную папку, это все таки не классы.

extract() лучше поместить в класс View.

> <p style="margin-bottom: 0px">


Это лучше выносить в CSS файл.

> <div class="form-group col-lg-10 col-md-10 col-sm-10 col-xs-10">


Там если ширина всегда одинаковая, можно использовать какой-то один общий класс, может быть col-10 или как-то так.

> &laquo


Точки с запятой не хватает.

Для таблицы адаптивность конечно не очень хорошо работает сужением колонок, нереально ли просто переформатировать все, например, выводить в одной строке - Имя/фамилию, а под ней мелким шрифтом группу и число баллов. А то получается механическая адаптивность, формальная, не продуманная. Не хочешь попробовать?

Я протестировал даже: https://jsfiddle.net/mx01cLzd/ (попробуй менять ширину окошка) - в новых браузерах (не знаю, с какого момента. попробуй выяснить), можно с помощью display убрать у элементов таблиц значение вроде table, table-cell и они "превратятся" в (будут отображаться как) обычные дивы.

Еще, по адпативности, не старайся поддерживать слишком много разрешений - это увеличивает трудоемкость. Вот таблица размеров экранов мобильных устройств: https://mydevice.io/devices/

Код пагинации сложный и его можно вынести в отдельный шаблон для повторного использования. Может даже можно какие-то функции вынести в PHP-код, вроде определения, что надо и не надо выводить.

https://github.com/Qevg/Student-list/blob/master/app/Controllers/RegisterController.php
тут $student не лучше ли сделать просто переменной, а не полем?

Для вывода формы и валидации - не лучше ли использовать объект Student, а не массив?

> type="email" work only in Latin


Ага, баг видимо. Но тип email имеет свои преимущества - где-то, может быть будет возможность вставлять email из контактов (хотя не знаю, есть ли такое, если у тебя есть мобильные устройства, можешь проверить).

Так, если ты начинающий, то сделано хорошо, но есть что улучшить.

Если будешь делать следующую задачу, то советую попробовать использовать в ней другой шаблонизатор, другую СУБД (postgres например или sqlite) и тд.
43 Кб, 662x752
#502 #1091624
Парни, дайте совет.
Уже 10 лет пишу на PHP + верстаю, наговнокодил уйму движков под всякую поебень с нуля: файлообменники, бложики, полноценные CMS, форумы.
Года три назад меня всё заебало. Я стал посылать клиентов нахер, и теперь на мне висит лишь один проект - но на 20 тысяч строк моего говнокода. Бросить я его не могу, мне платят хорошую зарплату просто за поддержку.
Но есть проблема. У меня есть список из около сотни фич, которые туда надо впилить до 2019 года. Но в проекте уже столько костылей и говна, что я уже сам в нем не разбираюсь. Он писался и рефакторился в течение 8 лет.

А теперь главное. Всю жизнь я пишу лапшекод. Даже когда я начал вкатываться в ООП - это было 3 года назад - я просто создал несколько объектов, и также продолжил писать длинные спагетти, где вместо переменных теперь объекты.
Я не хочу осваивать фреймворки, PHP сам по себе очень мощный язык. Но я хочу научиться программировать красиво. Так, чтобы я сам спустя годы мог понять, что тут происходит, читая код. И чтобы мой код теоретически могли поддерживать другие люди.

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

Ну и для иллюстрации - пикрелейтед функция get_image_resource_from_original_image_path($image_path, &$http_code), куда могут прилетать как локальные пути, так и ссылки, возвращает по ссылке &$http_code специальное значение empty_local_file, если файл существует, но пуст (такое бывает).
И такой херни 20000 строк.
#503 #1091628
>>1091411

>>нумерованные плейсхолдеры нумеруются с единицы, а не с нуля


В prepared statement нумеруются с 1 а в query-builder с 0 , пишут что это баг, который они не смогли исправить.

Due to an API design error the numerical parameters in the QueryBuilder API start with the needle 0, not with 1 as in the PDO API. This is very unfortunate, but we have found no BC way to fix this.
http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/query-builder.html

>>Вместо значений ты передаешь результат сравнения


спасибо, помогло. В INSERT into TABLE VALUES (val1, val2) не нужно указывать название колонок перед каждым val.

>>SHOW CREATE TABLE users



| users | CREATE TABLE `users` (
`user_id` int(11) NOT NULL AUTO_INCREMENT,
`first_name` varchar(80) COLLATE utf8_unicode_ci DEFAULT 'Stan',
`last_name` varchar(80) COLLATE utf8_unicode_ci DEFAULT 'Smith',
`email` varchar(63) COLLATE utf8_unicode_ci NOT NULL,
`pass_hash` char(32) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`user_id`),
UNIQUE KEY `email` (`email`)
) ENGINE=InnoDB AUTO_INCREMENT=25 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_c

>>Указывать user_id, если у него там по умолчанию значение NULL, не надо.


Ты про второй вариант кода, где user_id берется из свойств объекта юзера?

>>В первом варианте нужно явно указать имена колонок


Где именно, а то я и так их указывал но не там где нужно?
Вот так?
$stmt->bindValue(':first_name', 'Jack');
#503 #1091628
>>1091411

>>нумерованные плейсхолдеры нумеруются с единицы, а не с нуля


В prepared statement нумеруются с 1 а в query-builder с 0 , пишут что это баг, который они не смогли исправить.

Due to an API design error the numerical parameters in the QueryBuilder API start with the needle 0, not with 1 as in the PDO API. This is very unfortunate, but we have found no BC way to fix this.
http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/query-builder.html

>>Вместо значений ты передаешь результат сравнения


спасибо, помогло. В INSERT into TABLE VALUES (val1, val2) не нужно указывать название колонок перед каждым val.

>>SHOW CREATE TABLE users



| users | CREATE TABLE `users` (
`user_id` int(11) NOT NULL AUTO_INCREMENT,
`first_name` varchar(80) COLLATE utf8_unicode_ci DEFAULT 'Stan',
`last_name` varchar(80) COLLATE utf8_unicode_ci DEFAULT 'Smith',
`email` varchar(63) COLLATE utf8_unicode_ci NOT NULL,
`pass_hash` char(32) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`user_id`),
UNIQUE KEY `email` (`email`)
) ENGINE=InnoDB AUTO_INCREMENT=25 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_c

>>Указывать user_id, если у него там по умолчанию значение NULL, не надо.


Ты про второй вариант кода, где user_id берется из свойств объекта юзера?

>>В первом варианте нужно явно указать имена колонок


Где именно, а то я и так их указывал но не там где нужно?
Вот так?
$stmt->bindValue(':first_name', 'Jack');
66 Кб, 500x375
#504 #1091639
>>1091624

>Я не хочу осваивать фреймворки, PHP сам по себе очень мощный язык.


Нет ни одной вакансии на http://hh.ru и в поисковых машинах вроде http://rabota.yandex.ru где бы требовали только похапэ — всем нужны фреймворки. Очнитесь сэээр вы застряли в 2007 году, сейчас вас не взяли бы даже подметайлом, полы подметать.

>Но я хочу научиться программировать красиво. Так, чтобы я сам спустя годы мог понять, что тут происходит, читая код.


Это вам нужны Ruby / Erlang / Elixir и книжки вроде «The Four Rules of Simple Design» (Corey Haines).

>И чтобы мой код теоретически могли поддерживать другие люди.


Да что случилось? Осеннее обострение там у вас?..
#505 #1091644
>>1091639
Я никуда не устраиваюсь, у меня есть работа.
Как красиво писать на PHP? Хочешь сказать, никак?
95 Кб, 611x561
#506 #1091648
Решил последовать указаниям мудрого ОП-а и пройти главу с ООП.
Наткнулся на эту часть и завис.

>заводить на каждый вопрос новую переменную — неудобно, со временем мы можем сбиться и перепутать их номера


Ок, т.е. неудобно иметь n переменных, начинающихся с $q .

>Давай лучше сделаем массив и будем добавлять объекты-вопросы в него по одному


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

>Второе улучшение — мы завернем код создания объектов в функцию


И вот тут, когда я глянул на код, то повис.

Почему функция не принимает никаких значений? Как тогда вообще будет выглядеть вызов? Так?
$x = createQuestions();

>$q = new Question;


>$q->text = ...


Тут уже не понял. Надо в функции прописать текст вопросов или как?
#507 #1091650
>>1091644

>красиво


Этот пункт ломает все. Дай объяснение, что ты имеешь ввиду под словом "красиво"?
#508 #1091651
>>1091603
this значит "этот".

Class User
{
private $name;

public function getName() {
return $this->name;
}
}

$alex = new User();
$linda = new User();

Вот для объекта $alex this будет ссылаться на $alex, а для $linda - на $linda.
7 Кб, 406x465
#509 #1091655
>>1091644

>Как красиво писать на PHP? Хочешь сказать, никак?


Да.

Теперь подробнее. Ты совершил коммерческое самоубийство.

Мало того, что выбрал язык с глобальными переменными, без типов данных, привязанный к одной-единственной нише, но ещё и отстал на десять лет от всех остальных, даже от тех, кто пишет на том же языке (от современного C++ отстал на двадцать лет, считая от времени появления STL). Твои конкуренты работают за корыто отрубей, но у них есть ещё и JS, им есть что показать работодателям, а у тебя жуткий-страшный говнокод.

Прощай, жывое дышащее олицетворение того, что называют ошибкой выжившего, больше уж не увидимся. Вероятность что ты доживёшь до весны, исчезающе мала.
#510 #1091667
>>1091650
Так, чтобы обслуживать проект на 20000 строк, не вспоминая мучительно, как это работает. Сейчас неочевидная лапша. Хочу чтобы было стройное ООП.
Неужели нет мастрид самоучителя "Хороший стиль на похапе" или что-то такое.
#511 #1091706
>>1091667
Дело не в красоте должно быть, а в архитектуре проекта. Именно от нормальной архитектуры зависит его поддерживаемость, а не от красивости твоего говнокода. Ты хотя бы современные PSR-стандарты то знаешь?
#512 #1091718
>>1091706
Как видно на том скриншоте, код я оформляю по стандартам.
Ты подскажешь книжку или курс?
#513 #1091725
>>1091667
Очевидно, у тебя абстракции текут, если ты вынужден вспоминать как это работает. Нужно делать так, чтобы знать только ООФ и ОДЗф. А что внутри функции, или метода, или обьекта тебе должно быть похуй. СИКП почитай. Пиши так, как будто разные куски программы пишут разные программсты, придумай правильные интерфейсы между кусками.
#514 #1091735
>>1091648
Бамп вопросу!
#515 #1091750
>>1091655
на php в приличных проектах глобальные переменные не используют уже лет пять. и типы данных указываются давно в аннотациях и явно в семерке. тебе лучше посмотреть, как в данный момент пишутся серьезные проекты, прежде чем с видом знатока что-то вещать.

>>1091624
нельзя прочитать одну книгу "как писать хороший ооп на php". но можно прочитать много книг, на курсы сходить, почитать уроки ОПа, поработать джуном в компании с нормальным аудитом. вот есть хорошая книга с адаптацией для пхп: https://github.com/jupeter/clean-code-php автор там как раз пишет, что лучше избегать вложенных условий, которые у тебя на скриншоте.
еще полезный сайт http://www.phptherightway.com/ там скорее обзор технологий, которые сейчас в основном применяются (хотя pear вряд ли кто-то использует). плюс ооп - такая штука, которую нельзя понять, прочитав книгу. нужно несколько раз написать проекты-монстры, а потом посравнивать их с открытыми опенсорсными, например.

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

еще мне показалось, что ты так говоришь про 20 тысяч строк, как будто это много. это совсем не много, это при необходимых навыках можно переписать за пару недель, попутно написав тесты.
#516 #1091753
>>1091655

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

#517 #1091755
>>1091718
Речь идет не о стандартах code-style.
Давай по порядку, как ты реализовываешь автолоадинг классов в своем проекте? Я так понимаю, не через composer.
#518 #1091767
>>1091755
расскажи, пожалуйста, каким образом автолоадер композера (ты же автолоадер имел в виду?) может помочь подгружать классы, которые находятся вне папки vendor?
#519 #1091785
https://ideone.com/4GwlYm
Вопрос про ООП из задачки ОПа, предупреждаю что некоторые участки кода оче кривые, но дело пока не в них. Короче есть абстрактный класс Работник, в котором есть методы, которые что-то там высчитывают. Есть дочерние классы типа Менеджер, Аналитик, Инженер, в которых есть такие же поля, как и в классе Работник, но с конкретными значениями. Больше в них ничего нет. То есть всю работу делает абстрактный класс, а дочерние просто задают определенные значения для расчета. Так вообще делается или я придумал ненужный велосипед?
#520 #1091841
>>1091785
так делается. ты мог бы конечно делать все в одном классе типа manager = new Employee(salary = 500), но если у тебя есть предопределенные сущности, удобнее их вынести в отдельные классы.
#521 #1091851
>>1091785
$this->isBoss = 'Ошибка';
В чем смысл записывать слово 'Ошибка' туда, где ему совсем не место и откуда его никто не прочитает?
Намного целесообразнее было бы кинуть Exception, или использовать по дефолту false.
#522 #1091859
>>1091851
Я на самом деле сам не знаю почему я тогда так написал. В голове я явно подразумевал другое, да и писал это с мыслью "Вот тут в реальном коде будет проверка данных и обработка ошибок, а пока просто напишу 'Ошибка', потому что не умею по другому."
#523 #1091900
>>1091648
Просто я не понимаю, как можно создать функцию по созданию объектов, если каждый из них - самостоятельный предмет с отличающимися свойствами.
Это же не массив из случайных данных!
26 Кб, 406x364
#524 #1091919
>>1082507 (OP)
https://ideone.com/7CTCqF

Вроде решил задачу на палиндром, по крайней мере всё работает. Долго думал как сделать цикл без добавления переменной $u, а только с одной переменной $i и чтобы всё работало, но так и не смог ничего придумать, что бы ни делал он мне выдавал не то что нужно.
#525 #1091928
Я правильно понимаю, что магические методы требуют аргументы от объектов?

https://ideone.com/fork/VV8hib
#526 #1091948
>>1091767
ОМАЙГАД! Ты серьезно?
"autoload": {
"psr-4": {
"": "mysuperapp",
"MySuperNamespace\\": "mysuperapp/mysupernamespace"
}
},

Ты в конфиги композера хотя бы раз заглядывал?
#527 #1091950
>>1091948
В симфони отказались от своего автолоадера в пользу композера, но ВасянПро из Урюпинска придумает более мощное решение.
#528 #1091954
>>1091648

Вообще-то массивы как раз и придуманы для ситуаций, когда у нас есть несколько однотипных переменных. Ну например, если нам надо хранить температуру по дням, то вместо того, чтобы создавать переменные $temp1, $temp2, $temp3 и так далее, проще просто создать массив $temp с несколькими элементами ($temp = [10, 4, -10];). Передавать куда-то (в функцию или из функции) ОДИН массив удобнее, чем 10 отдельных переменных. Посчитать сумму элементов тоже удобнее, когда они в массиве, а не в виде 10 отдельных переменных. Добавить 1 новый элемент в массив легко, а чтобы добавить еще одну переменную, придется делать правки по всему коду.

Тут у нас есть тест. Он состоит из N однотипных вопросов. Каждый вопрос представлен объектом класса Question. Мы бы могли сделать переменные $q1, $q2, $q3, и так далее, но сделать массив $questions, который содержит N объектов, по моему, удобнее.

Разумеется, в массив в качестве значений можно класть объекты. Не только числа, строки, другие массивы, но и объекты.

Ну представь, например, что нам надо вернуть все вопросы их функции. В случае с массивом мы пишем return $questions. А что в случае, когда у тебя 10 переменных? Как ты их вернешь?

У меня ощущение, что ты как-то не очень внимательно изучил тему про массивы и из-за этого путаешься.

Функция createQuestions должна создать и вернуть массив, содержащий несколько объектов-вопросов. То есть она должна создать эти объекты, заполнить их свойства и поместить в массив. Мы выносим создание вопросов в функцию, чтобы разбить код на отдельные части, чтобы программа не была длинной стеной кода, которую тяжело читать. Потому мы разбиваем ее на части - одна функция создает вопросы, другая выводит их на экран, третья, может быть, будет проверять ответы.

> Как я помню, с объектом можно обращаться, как с переменной


Нет. Объект (ссылку на него) можно поместить в переменную. Переменная - это что-то вроде "ящика", в который можно положить какое-то одно значение (то есть например, строку, число, объект, массив).

Не путай понятия "значение" (строка, число, массив, ссылка на объект) и "переменная". Переменная - это хранилище для одного значения.

Массив - это "значение", которое может хранить в себе много других значений (строк, чисел, и тд).

> с объектом можно обращаться, как с переменной или массивом


Это некорректное высказывание. С объектом нельзя обращаться как с массивом, например, нельзя написать $object[0].

> и объединять его в массивы.


Объект (ссылку на объект) можно поместить в массив, да.

> Почему функция не принимает никаких значений?


А что она должна принимать? Функция не обязана иметь аргументы.

> Как тогда вообще будет выглядеть вызов? Так?


Да, пустые скобки.

> Надо в функции прописать текст вопросов или как?


Да. вопросы надо "захардкодить" в коде.
#528 #1091954
>>1091648

Вообще-то массивы как раз и придуманы для ситуаций, когда у нас есть несколько однотипных переменных. Ну например, если нам надо хранить температуру по дням, то вместо того, чтобы создавать переменные $temp1, $temp2, $temp3 и так далее, проще просто создать массив $temp с несколькими элементами ($temp = [10, 4, -10];). Передавать куда-то (в функцию или из функции) ОДИН массив удобнее, чем 10 отдельных переменных. Посчитать сумму элементов тоже удобнее, когда они в массиве, а не в виде 10 отдельных переменных. Добавить 1 новый элемент в массив легко, а чтобы добавить еще одну переменную, придется делать правки по всему коду.

Тут у нас есть тест. Он состоит из N однотипных вопросов. Каждый вопрос представлен объектом класса Question. Мы бы могли сделать переменные $q1, $q2, $q3, и так далее, но сделать массив $questions, который содержит N объектов, по моему, удобнее.

Разумеется, в массив в качестве значений можно класть объекты. Не только числа, строки, другие массивы, но и объекты.

Ну представь, например, что нам надо вернуть все вопросы их функции. В случае с массивом мы пишем return $questions. А что в случае, когда у тебя 10 переменных? Как ты их вернешь?

У меня ощущение, что ты как-то не очень внимательно изучил тему про массивы и из-за этого путаешься.

Функция createQuestions должна создать и вернуть массив, содержащий несколько объектов-вопросов. То есть она должна создать эти объекты, заполнить их свойства и поместить в массив. Мы выносим создание вопросов в функцию, чтобы разбить код на отдельные части, чтобы программа не была длинной стеной кода, которую тяжело читать. Потому мы разбиваем ее на части - одна функция создает вопросы, другая выводит их на экран, третья, может быть, будет проверять ответы.

> Как я помню, с объектом можно обращаться, как с переменной


Нет. Объект (ссылку на него) можно поместить в переменную. Переменная - это что-то вроде "ящика", в который можно положить какое-то одно значение (то есть например, строку, число, объект, массив).

Не путай понятия "значение" (строка, число, массив, ссылка на объект) и "переменная". Переменная - это хранилище для одного значения.

Массив - это "значение", которое может хранить в себе много других значений (строк, чисел, и тд).

> с объектом можно обращаться, как с переменной или массивом


Это некорректное высказывание. С объектом нельзя обращаться как с массивом, например, нельзя написать $object[0].

> и объединять его в массивы.


Объект (ссылку на объект) можно поместить в массив, да.

> Почему функция не принимает никаких значений?


А что она должна принимать? Функция не обязана иметь аргументы.

> Как тогда вообще будет выглядеть вызов? Так?


Да, пустые скобки.

> Надо в функции прописать текст вопросов или как?


Да. вопросы надо "захардкодить" в коде.
#529 #1091958
>>1091948
я из дс, лол.

спасибо. век живи, век учись
#530 #1091962
>>1091624

Во-первых, откуда такая неприязнь к фреймворкам? Если говорить о той же Симфони, то ее пишут опытные люди и у них тебе (судя по твоим же словам) явно есть чему поучиться, потому что в Симфони хороший код. Однозначно, Симфони тебе стоит изучить, причем не на уровне новичка.

Тебе фреймворки кажутся сложными и непонятными? Это может быть потому, что у тебя недостаточно знаний для их понимания.

> я просто создал несколько объектов, и также продолжил писать длинные спагетти, где вместо переменных теперь объекты


Ну так надо сделать из этого вывод и перестать писать длинные спагетти. Набери в гугле "длина функций в коде" и найдешь множество рассуждений по этой теме (а еще лучше искать на английском).

Если ты, для начала, научишься "видеть" проблемы в коде, понимать, откуда они берутся, и подумаешь, как с этим бороться, то может быть, ты сам дойдешь до тех правил, которые перечислены в книгах и статьях.

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

Вот простой вопрос: в твоем проекте есть какая-то документация (readme), рассказывающая, как развернуть проект, как запускать тесты, описывающая архитектуру? Если ты пишешь один, ты ведь даже не задумаешься о том, что она нужна.

Если ты хочешь книгу, пожалуйста: "Идеальный код". Довольно большая книга, не привязана к конкретному языку программирования.

Также нескромно посоветую свою маленнькую статью с советами по PHP: https://github.com/codedokode/pasta/blob/master/good-code.md

Далее, посоветую гайд "PHP: правильный путь" - http://getjump.me/ru-php-the-right-way/

Далее, я бы тебе посоветовал хотя бы почитать комментарии (их там много) к моей задаче про студентов, а в идеале, решить ее: https://github.com/codedokode/pasta/blob/master/student-list.md

Разумеется, код надо оформлять по стандарту. Неудобно, когда один человек пишет по-своему, а другой - по совему. Изучи PSR-1 и PSR-2, я вижу по твоему примеру кода, что ты их не соблюдаешь.

Что касается архитектуры - тут давно все придумано, MVC, сервисы, у меня есть урок https://github.com/codedokode/pasta/blob/master/arch/mvc.md

Есть еще у Фаулера краткая статья про сервисы: https://martinfowler.com/eaaCatalog/serviceLayer.html

> возвращает по ссылке &$http_code


ну вот уже на этом месте можно остановиться и подумать, а не лучше ли результаты возвращать через return.

> Даже когда я начал вкатываться в ООП - это было 3 года назад - я просто создал несколько объектов,


Ну скорее всего ты просто их сделал, потому что другие делают. А надо было подумать - какая выгода от использования ООП, где оно может быть полезно и тд. Какие плюсы и минусы такого подхода.

У меня в учебнике в ОП посте есть глава про ООП, там есть задача про ООО Вектор. На ней как раз видны преимущества ООП - без ООП ее решать будет тяжело и получится, скорее всего, та самая лапша.
#530 #1091962
>>1091624

Во-первых, откуда такая неприязнь к фреймворкам? Если говорить о той же Симфони, то ее пишут опытные люди и у них тебе (судя по твоим же словам) явно есть чему поучиться, потому что в Симфони хороший код. Однозначно, Симфони тебе стоит изучить, причем не на уровне новичка.

Тебе фреймворки кажутся сложными и непонятными? Это может быть потому, что у тебя недостаточно знаний для их понимания.

> я просто создал несколько объектов, и также продолжил писать длинные спагетти, где вместо переменных теперь объекты


Ну так надо сделать из этого вывод и перестать писать длинные спагетти. Набери в гугле "длина функций в коде" и найдешь множество рассуждений по этой теме (а еще лучше искать на английском).

Если ты, для начала, научишься "видеть" проблемы в коде, понимать, откуда они берутся, и подумаешь, как с этим бороться, то может быть, ты сам дойдешь до тех правил, которые перечислены в книгах и статьях.

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

Вот простой вопрос: в твоем проекте есть какая-то документация (readme), рассказывающая, как развернуть проект, как запускать тесты, описывающая архитектуру? Если ты пишешь один, ты ведь даже не задумаешься о том, что она нужна.

Если ты хочешь книгу, пожалуйста: "Идеальный код". Довольно большая книга, не привязана к конкретному языку программирования.

Также нескромно посоветую свою маленнькую статью с советами по PHP: https://github.com/codedokode/pasta/blob/master/good-code.md

Далее, посоветую гайд "PHP: правильный путь" - http://getjump.me/ru-php-the-right-way/

Далее, я бы тебе посоветовал хотя бы почитать комментарии (их там много) к моей задаче про студентов, а в идеале, решить ее: https://github.com/codedokode/pasta/blob/master/student-list.md

Разумеется, код надо оформлять по стандарту. Неудобно, когда один человек пишет по-своему, а другой - по совему. Изучи PSR-1 и PSR-2, я вижу по твоему примеру кода, что ты их не соблюдаешь.

Что касается архитектуры - тут давно все придумано, MVC, сервисы, у меня есть урок https://github.com/codedokode/pasta/blob/master/arch/mvc.md

Есть еще у Фаулера краткая статья про сервисы: https://martinfowler.com/eaaCatalog/serviceLayer.html

> возвращает по ссылке &$http_code


ну вот уже на этом месте можно остановиться и подумать, а не лучше ли результаты возвращать через return.

> Даже когда я начал вкатываться в ООП - это было 3 года назад - я просто создал несколько объектов,


Ну скорее всего ты просто их сделал, потому что другие делают. А надо было подумать - какая выгода от использования ООП, где оно может быть полезно и тд. Какие плюсы и минусы такого подхода.

У меня в учебнике в ОП посте есть глава про ООП, там есть задача про ООО Вектор. На ней как раз видны преимущества ООП - без ООП ее решать будет тяжело и получится, скорее всего, та самая лапша.
#531 #1091963
>>1091624

Насчет ООП и архитектуры: в нашем треде были люди, которые вообще ООП не знали (начинающие), а через какое-то время, решая мои задачи, освоили и компоненты Симфони, и настраивали автоматические тесты. Так что все возможно при наличии мотивации.
#532 #1091966
>>1091624

> Я не хочу осваивать фреймворки, PHP сам по себе очень мощный язык.


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

А теперь подумай, в каком проекте будет проще разобраться другому разработчику: написанном на известном фреймворке с документацией и вопросами на stackoverflow, который поддерживается и разрабатывается, или в самописаном кривом фреймворке без документации, поддержки и тестов?
#533 #1091970
>>1091603

$this это "псевдопеременная" (выглядит как переменная, но не является ей). Его можно использовать ТОЛЬКО внутри обычного, не статического, метода объекта. Она указывает на тот объект, на котором был вызван метод (надеюсь, ты знаешь что такое метод).

То есть если мы пишем

$a = new Person;
$a->doSomething();

То в коде метода doSomething $this будет указывать на объект $a.

И ты можешь в doSomething писать что-то такое:

public function doSomething()
{
// равносильно $x = $a->name
$x = $this->name;
}
#534 #1091973
>>1091655

Вот ты начал вроде хорошо, с критики PHP, но когда ты предложил альтернативу, она оказалась еще хуже.

> от современного C++ отстал


У меня крайне негативное отношение к языку. Начнем с простого вопроса: что вы используется в Си++ вместо композера? То есть как мне в проекте на гитхабе указать зависимости, которые надо установить, и как их может установить скачавший мой проект? И чтобы это было кроссплатформенно?

То же самое касается системы сборки. Я видел CMake, он кроссплтформенный и неплохой, но сколько же там нагроможено всего поверх всяких легаси технологий. Под той же виндой замучается качать, скачай Cmake, скачай Windows SDK нужной версии, скачай библиотеки.

Что насчет сборки мусора? Ты всерьез предлагаешь язык без сборки мусора как ЗАМЕНУ языку со сборкой? Я понимаю, если бы ты написал C# - мощный, хороший язык, но C+= - это несерьезно.

В языке куча легаси. Прототипы функций и методов надо писать по 2 раза. Модулей нет, проект компилируется путем склейки тысяч файлов в один, и так много раз.

Что насчет отладки? Есть кроссплатформенные интерактивные отладчики? У нас по крайней мере в интерпретатор встроен отладочный протокол. А при исключении выводится стектрейс.

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

У меня есть задача про студентов: https://github.com/codedokode/pasta/blob/master/student-list.md Подумай, на чем ее будет быстрее написать. Я думаю, не на Си++.
#535 #1091975
>>1091655

Ну и стандартный вопрос: как правильно в Си++ написать строку, возвращающую результат в виде строки или в виде массива целых чисел неизвестной длины? Вопрос с подвохом, хотя в PHP даже думать о таких вещах не надо.
#536 #1091979
Новичок-кун репортин ин

>- Далее простая, но полезная задача сделать список студентов, в ней много полезных советов: https://github.com/codedokode/pasta/blob/master/student-list.md



Почитал это ПРОСТУЮ задачку, обоссался от страха, как с этим справиться?
#537 #1091984
>>1091979

Берешь и делаешь. Если ты задачи отсюда решил https://github.com/codedokode/pasta/blob/master/soft/web-server.md и перед этим прочел мой или любой другой нормальный учебник, включающий ООП, то сможешь добавиться успеха.

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

Ну вот возьмем задачу "вывести список студентов". Ее ведь можно разбить на части:

- получить данные о студентах из БД
- преобразовать их в список объектов-студентов
- с помощью шаблона (у меня есть урок по ним) вывести этот список студентов в виде HTML кода

Ты можешь не знать, как работать с БД, не беда, можно тогда просто создать этот список студентов в коде вручную, а позже заменить это на загрузку из БД. В моем уроке по MVC например так и сделано, там не использется база данных.

То есть если разбивать задачу на части, то ты увидишь, что часть ты точно можешь сделать. А для оставшегося надо немного почитать другие уроки.
#538 #1092005
Класс роутера можно прописывать в маленьких проектах в директории Helpers? Я просто заметил, что обычно так никто не делает и обычно просто в папку с приложением отдельным файлом кидают.
ньюфаг
50 Кб, 410x415
#539 #1092023
>>1091750
Спасибо за чтиво. Поработать джуном, увы, для меня роскошь.

>>1091755

> автолоадинг классов


Слышь, ты чего ругаешься?
Где нужен класс, там я его и объявляю. А потом использую. У меня один файл может быть и на 4 тысячи строк кода.

>>1091962

>Во-первых, откуда такая неприязнь к фреймворкам?


Со времен обильного использования jQuery для сложения двух чисел. Мне кажется, что любой внешний фреймворк или библиотека - это куча чужого кода, большую часть которого я никогда не буду использовать. А память он жрать будет.

>ну вот уже на этом месте можно остановиться и подумать, а не лучше ли результаты возвращать через return


А вот этому меня уже научил PHP. Достаточно стандартных функций, возвращающих булев статус успеха, а подробности - по ссылке. Тот же preg_match.
Я открыл все твои ссылки, накликал по ссылкам внутри, и теперь у меня 15 вкладок с текстом. Это перегруз. Спасибо.
Я постараюсь решить задачу про студентов. Я могу решить ее с наскоку как умею - но постараюсь сделать это по твоим гайдам. Класс-верификатор для меня вообще что-то неземное. Я бы уже строчил портянки, которые жонглируют переменными, какие к черту классы.
#540 #1092029
>>1091900
аналогия из реальной жизни. фасованная охложденная курица. Объект получается латок. у каждого лотка свой вес и срок годности. Выпускает все один конвеер. Тут точно так же.
#541 #1092045
>>1091954
Аааа. Я понял! Функция создает объекты, как элементы массива с пустым текстом, а потом уже, по желанию, в это поле и забиваются необходимые данные!

>>1092029
Твой пример только затруднил процесс, но я все понял.
#542 #1092049
>>1092045
Однако, меня теперь интересует вот что:

// Создаем и заполняем первый объект
$q = new Question;
$q->text = ...
...
// Кладем вопрос в массив
$questions[] = $q;
// Создаем второй объект
$q = new Question;

Почему у двух объектов в массиве одинаковые имена?
Или первому будет присвоен id 0, а второму id 1 и они оба будут записаны без проблем?
#543 #1092092
>>1092049

У объектов нет имен (хотя и есть уникальные идентификаторы). $q - это не имя объекта, а переменной. Мы сначала кладем в нее ссылку на первый объект, заполняем его, кладем объект в массив. Затем кладем в эту же переменную ссылку на второй объект (и старое значение переменной теряется).

То есть у нас одна переменная, в которую мы по очереди кладем разные объекты (точнее, ссылки на них).

Я выше написал: не путай переменную и значение, которое в ней хранится. Переменная - это просто хранилище и мы можем всегда положить в нее новое значение.
#544 #1092096
>>1091900

А мы все значения свойств жестко прописываем в функции. То есть она всегда будет создавать одинаковый массив, содержащий заранее известное число объектов с заранее известными значениями их свойств.
#545 #1092099
>>1091900

Вот тебе пример функции, которая при каждом вызове создает и возвращает новый объект:

function createOneObject()
{
$q = new Question;
$q->text = 'Текст вопроса';
$q->anser = 'ответ';
return $q;
}

Хотя она и создает каждый раз при вызове новый объект, но в его свойства помещаются одни и те же значения.
#546 #1092102
>>1092045

Вообще, нет, там эта функция не только создает, но сразу же заполняет свойства этих объектов, как в примере тут >>1092099
#547 #1092106
>>1092049

new Question создает новый объект где-то в памяти и возвращает ссылку на него (его идентификатор). Команда $q = ... помещает эту ссылку в переменную $q, удаляя из нее старое значение.

То есть:

// Создает новый объект в памяти, сохраняет ссылку на него в переменную
$q = new Question;
// Заполняет свойства объекта
$q->text = ...;
// Копирует ссылку на объект в новый элемент массива
$questions[] = $q;
// Создает новый объект, сохраняет ссылку на него в переменную, удаляя из переменной ссылку на предыдущий объект
$q = new Question;
#548 #1092116
>>1092023

Ну вот видишь, в итоге оказывается, что ты просто сильно переоценил свой уровень. Тебе бы не помешало изучить в итоге Симфони, в ОП посте есть задача про TestHub, если задача про студентов кажется простой для тебя и захочется что-то посложнее.

> Мне кажется, что любой внешний фреймворк или библиотека - это куча чужого кода, большую часть которого я никогда не буду использовать


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

> А память он жрать будет.


А когда у тебя была последний раз нехватка памяти на сервере? Сейчас по моему память недорогая. Если твой бизнес завязан на сайт, ты вряд ли будешь использовать нищехостинг за 70 рублей в месяц.

Да и мерял ли ты реально это потребление памяти? На сколько больше, на байт, на килобайт, на мегабайт, на гигабайт?

Ты делаешь ошибку, когда пытаешься оптимизировать только потребление памяти. Есть производительность кода, а есть производительность разработки. Посмотри на это со стороны бизнеса: есть расходы на аренду/покупку сервера, а есть расходы на оплату труда разработчиков. Экономия на времени разработки может перевесить стоимость памяти.

И подумай, что выберет бизнес: оплатить разработку своего проприетарного фреймворка или взять бесплатный открытый готовый код?

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

Также, есть еще фактор времени. Иногда какую-то фичу надо добавить быстро и нет времени на написание с нуля.

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

Есть конечно и случаи, когда потребление памяти важно. Если твой JS код потребляет гигабайт памяти, то сайт вряд ли будет работать быстро, а на мобильных просто не откроется. Ты ведь не можешь купить память всем посетителям, в отличие от случая с сервером.
#548 #1092116
>>1092023

Ну вот видишь, в итоге оказывается, что ты просто сильно переоценил свой уровень. Тебе бы не помешало изучить в итоге Симфони, в ОП посте есть задача про TestHub, если задача про студентов кажется простой для тебя и захочется что-то посложнее.

> Мне кажется, что любой внешний фреймворк или библиотека - это куча чужого кода, большую часть которого я никогда не буду использовать


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

> А память он жрать будет.


А когда у тебя была последний раз нехватка памяти на сервере? Сейчас по моему память недорогая. Если твой бизнес завязан на сайт, ты вряд ли будешь использовать нищехостинг за 70 рублей в месяц.

Да и мерял ли ты реально это потребление памяти? На сколько больше, на байт, на килобайт, на мегабайт, на гигабайт?

Ты делаешь ошибку, когда пытаешься оптимизировать только потребление памяти. Есть производительность кода, а есть производительность разработки. Посмотри на это со стороны бизнеса: есть расходы на аренду/покупку сервера, а есть расходы на оплату труда разработчиков. Экономия на времени разработки может перевесить стоимость памяти.

И подумай, что выберет бизнес: оплатить разработку своего проприетарного фреймворка или взять бесплатный открытый готовый код?

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

Также, есть еще фактор времени. Иногда какую-то фичу надо добавить быстро и нет времени на написание с нуля.

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

Есть конечно и случаи, когда потребление памяти важно. Если твой JS код потребляет гигабайт памяти, то сайт вряд ли будет работать быстро, а на мобильных просто не откроется. Ты ведь не можешь купить память всем посетителям, в отличие от случая с сервером.
#549 #1092120
>>1092023

Насчет стоимости разработки, хочу дополнить. Вот одно дело, если ты битрикс и нанимаешь в Калининграде студентов за 20-30 тыс в месяц (сколько это, 150 рублей в час?). Другое дело, если ты платишь разработчику хотя бы 1000 рублей в час. Третье дело, если ты стартап в Калифорнии и сжигаешь $100 000+ в год на человека ($100 000 в год = $50 в час ~ 3000 российской валюты).

Чем больше ты платишь разработчику, тем дороже тебе обходится велосипедостроение.
#550 #1092121
Выдает ошибку потому что я функцию padRight и padLeft должен дописать? Но какие условия у них? Простите, за глупые вопросы
#551 #1092122
#552 #1092126
>>1092121

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

Ты можешь не писать эти функции, а вывести таблицу как-нибудь по-другому.

>>1092005

Можно.

>>1091767

Есть урок https://github.com/codedokode/pasta/blob/master/php/autoload.md (я думаю, тебе все же придется мой гитхаб целиком прочесть в итоге).

>>1091928

Не очень понял вопрос. Магический метод - это конструктор?

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

>>1091919

$u вычисляется из $i. (-$i - 1).

Решено верно.

>>1091859

Ты можешь писать в таких случаях

throw new Exception("Пояснение о причине ошибки");

Это выбросит исключение, которое завершит программу и выведет сообщение.

Подробнее https://github.com/codedokode/pasta/blob/master/php/exceptions.md

>>1091785

Тут можно использовать наследование, а можно не использовать. Оба варианта годятся.

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

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

Для департаментов наследование применять смысла нет вообще. Так как они ничем друг от друга в плане свойств не отличаются.

>>1091718

Увы, у тебя какие-то самодельные стандарты оформления кода, а не общепринятый PSR.
#552 #1092126
>>1092121

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

Ты можешь не писать эти функции, а вывести таблицу как-нибудь по-другому.

>>1092005

Можно.

>>1091767

Есть урок https://github.com/codedokode/pasta/blob/master/php/autoload.md (я думаю, тебе все же придется мой гитхаб целиком прочесть в итоге).

>>1091928

Не очень понял вопрос. Магический метод - это конструктор?

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

>>1091919

$u вычисляется из $i. (-$i - 1).

Решено верно.

>>1091859

Ты можешь писать в таких случаях

throw new Exception("Пояснение о причине ошибки");

Это выбросит исключение, которое завершит программу и выведет сообщение.

Подробнее https://github.com/codedokode/pasta/blob/master/php/exceptions.md

>>1091785

Тут можно использовать наследование, а можно не использовать. Оба варианта годятся.

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

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

Для департаментов наследование применять смысла нет вообще. Так как они ничем друг от друга в плане свойств не отличаются.

>>1091718

Увы, у тебя какие-то самодельные стандарты оформления кода, а не общепринятый PSR.
#553 #1092127
>>1092120
Я согласен, но стоит заметить, что из такого принципа в итоге может вырасти программный монстр, типа как сейчас стал Хром. Он у меня минуты две запускается. Зато, я уверен, программистам на высоких уровнях абстракции было очень просто его писать. А под капотом жрутся гигабайты памяти, забивается целое ядро у проца и на кой-то хрен постоянно теребится медленный жесткий диск. Хочешь быстрее? Купи новый комп, епта!
Как интересно, стимулируется вся экономика. Фреймворки на страже запланированного устаревания.
#554 #1092130
>>1092127

Он у тебя так долго запускается из-за установленных тобой же расширений, проприетарных гугловских расширений или просто из-за захламленного и давно не чищенного профиля. У меня Хромиум, где-то 1-2 годичной давности и такой проблемы с запуском нет.
#555 #1092132
>>1092127

Пользователи и вебмастера хотят видео на фоне и CSS3 анимации. Терпи. Скоро на webasembly начнут писать сайты и тебе нынешняя ситуация раем покажется.
#556 #1092139
>>1092130
У меня на компе с XP крашатся что Огнелис, что Вивальди, даже на чистой установке. И только старая Опера не только работает, но еще и достаточно шустро. Тот же Огнелис может зафризиться на полминуты, например.
#557 #1092154
>>1091554

Спасибо за советы!

Пока получается так:
Файл index.php

<form action="" method="get">
<textarea name="text" cols="30" rows="10">

</textarea>
<p><input type="submit"></p>
</form>

<?php
$text = $_GET["text"]; //получаю значение из формы
$htmlText = htmlspecialchars($text); //экранирую значение
echo "<pre>$htmlText</pre>"; //вывожу значение с переносами и пробелами
$link = http_build_query(['text' => $text, 'lt' => 1]); // создаю URL

Дальше не понимаю как сделать так чтобы по ссылке открывалась страница,
то есть например, при таком варианте:
echo "<a href='$link'>Ссылка</a>";
Мне выдает 404 ошибку, что правильно. Но как добавить URL к странице и чтобы потом можно было им управлять?
#557 #1092154
>>1091554

Спасибо за советы!

Пока получается так:
Файл index.php

<form action="" method="get">
<textarea name="text" cols="30" rows="10">

</textarea>
<p><input type="submit"></p>
</form>

<?php
$text = $_GET["text"]; //получаю значение из формы
$htmlText = htmlspecialchars($text); //экранирую значение
echo "<pre>$htmlText</pre>"; //вывожу значение с переносами и пробелами
$link = http_build_query(['text' => $text, 'lt' => 1]); // создаю URL

Дальше не понимаю как сделать так чтобы по ссылке открывалась страница,
то есть например, при таком варианте:
echo "<a href='$link'>Ссылка</a>";
Мне выдает 404 ошибку, что правильно. Но как добавить URL к странице и чтобы потом можно было им управлять?
#558 #1092160
>>1092126

>Добивает строку справа или слева пробелами до указанной длины. Чтобы таблицы выглядела ровной.


>


>Ты можешь не писать эти функции, а вывести таблицу как-нибудь по-другому.



Я не совсем понимаю. Как это можно осуществить?
#559 #1092164
>>1092160
Это метод получается будет. Это нужно в классе писать?
#560 #1092175
На ideone mb_strlen не работает?
#561 #1092178
>>1092175
>>1092160
>>1092164

Я хотел с помощью mb_strlen сделать цикл, чтобы составить таблицу, но что-то ничего не получается. Ужас D:
Извините за спам. Я не специально.
#562 #1092199
Парни вот у меня есть несколько форм, с которых получаю данные и мне надо эти данные из форм впихнуть заменой в таблицу, как сделать все одним запросом? А если форм 200, на каждую форму писать отдельный update?
#563 #1092206
На ideone не работает mb_stlen()
На phpfiddle пустые строки не считает
<?php
echo " a ";
?>

Выдает просто "a".
На локальном тоже mb_strlen() не работает.
Поэтому делал вслепую. Правильно ли сделал функции?
Спасибо большое за ответы.

Решение:
https://ideone.com/q9bd9E

А я пошел настраивать локальный сервер, чтобы mb_stlen() работал
107 Кб, 1579x787
#564 #1092210
Пытаюсь сделать так, чтобы mb_strlen работал. В гайде написано https://php-myadmin.ru/learning/instrument-php.html переименовать php.ini-development в php.ini и расскоментить extension=php_mbstring.dll. Я все сделал. Сервер перезапускал. Ничего не работает, почему может так происходить?
#565 #1092211
>>1092210

Выводи phpinfo() и посмотри, есть ли там mbstring и полный путь к использованному php.ini.
9 Кб, 610x176
#566 #1092213
>>1092211
Это? У меня на диск D если что установлен php, а апач на C
#568 #1092216
>>1092215
Спасибо. К сожалению, ничего не могу понять. Буду перечить сейчас, но вообще ничего не понятно. У меня есть php.ini-production и php.ini-development это те ini или нет?
#569 #1092217
>>1092216

Там написано php.ini, а не php.ini-production. Это просто образец.
#570 #1092218
>>1092217
У меня ничего не получается тогда. Нету никакого php.ini, я по ссылке не понимаю терминологию. у меня есть апач на диске D: и PHP на диске C:

Я могу редактировать код и он будет компилироваться, отображаться в браузере. Но не работает команда mb_strlen. Извини за глупость. Я правда не понимаю, где находится php.ini. По гайду я его создал, переименовав другой файл в папке на диске D, где у меня установлен PHP. И расскоментил там строчку, но ничего не работает. Я вернул все обратно и закомментировал строчку, а также переименовал файл обратно.
#571 #1092219
>>1092218

Ты невнимательно прочел мануал. Там написана последовательность, в которой PHP ищет файл php.ini.

> Директория веб-сервера (для SAPI модулей), или директория PHP (иначе в директории Windows).


SAPI-модули - это например mod_php, то есть по сути значит, когда PHP запущен из-под Апача (немного про SAPI описано тут https://stackoverflow.com/questions/9948008/what-is-sapi-and-when-would-you-use-it ).

Если мы положим файл в директорию PHP, то он найдется. Но только при запуске из командной строки, а не из-под Апача (в этом случае он будет искаться в папке с Апачом, где его нету).

Чтобы он нашелся и при запуске из Апача, надо обратить внимание на этот пункт

> По месту расположения модуля SAPI (PHPIniDir директива Apache 2, -c параметр командной строки CGI и CLI, php_ini параметр в NSAPI, PHP_INI_PATH переменная среды в THTTPD)



> PHPIniDir директива Apache 2



И прописать путь дополнительно в указанной директиве в конфиге Апача.

Этот вариант самый удобный, класть php.ini в ту же папку, что и Апач.

Где взять php.ini? Сделать из php.ini-development
#572 #1092220
>>1092218

Алсо, расшифровал пункты из мануала:

> По месту расположения модуля SAPI...


Первый вариант поиска - по месту, заданному программой-хозяином. Если PHP запущен как модуль Апача mod_php, то определяется из директивы в конфиге Апача, если PHP запущен из ком. строки, то параметром -c и тд.

> Переменная среды PHPRC


Что такое переменные среды: https://ru.wikipedia.org/wiki/Переменная_среды

> Как и в PHP 5.2.0, местоположение файла php.ini может быть указано для различных версий PHP. Корневой ключ реестра....


Под Windows путь можно прописать в реестре.

> [HKEY_LOCAL_MACHINE\SOFTWARE\PHP] или [HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\PHP], значение IniFilePath (только для Windows).


В реестре.

> Текущая директория (исключая CLI).


Что такое текущая директория: https://ru.wikipedia.org/wiki/Рабочий_каталог

> Директория веб-сервера (для SAPI модулей), или директория PHP (иначе в директории Windows).


Директория, где размещена программа-хозяин, из которой запущен PHP.

> В директории Windows (C:\windows или C:\winnt) (для Windows), или --with-config-file-path с выбором при компиляции.


Тут тоже понятно.
#572 #1092220
>>1092218

Алсо, расшифровал пункты из мануала:

> По месту расположения модуля SAPI...


Первый вариант поиска - по месту, заданному программой-хозяином. Если PHP запущен как модуль Апача mod_php, то определяется из директивы в конфиге Апача, если PHP запущен из ком. строки, то параметром -c и тд.

> Переменная среды PHPRC


Что такое переменные среды: https://ru.wikipedia.org/wiki/Переменная_среды

> Как и в PHP 5.2.0, местоположение файла php.ini может быть указано для различных версий PHP. Корневой ключ реестра....


Под Windows путь можно прописать в реестре.

> [HKEY_LOCAL_MACHINE\SOFTWARE\PHP] или [HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\PHP], значение IniFilePath (только для Windows).


В реестре.

> Текущая директория (исключая CLI).


Что такое текущая директория: https://ru.wikipedia.org/wiki/Рабочий_каталог

> Директория веб-сервера (для SAPI модулей), или директория PHP (иначе в директории Windows).


Директория, где размещена программа-хозяин, из которой запущен PHP.

> В директории Windows (C:\windows или C:\winnt) (для Windows), или --with-config-file-path с выбором при компиляции.


Тут тоже понятно.
59 Кб, 986x651
#573 #1092222
>>1092219
У меня так было(пик). Если я перетащу php.ini в папку апача и PHPIniDir задам директорию новую, то все заработает и php будет тоже работать? apache на d. php на c
#574 #1092223
>>1092222
точнее наоборот в спойлере! апач на c, а php на d
#575 #1092224
>>1092222

Ты вписал директиву внутрь IfModule.
#577 #1092228
>>1092225

phpinfo()
#579 #1092231
>>1092230

Не понял вопрос, но да.
54 Кб, 910x567
sage #580 #1092232
>>1092231
Тогда почему не работает?
#581 #1092234
>>1092232
Случайно нажал sage, вместо загрузки фото.
#582 #1092236
>>1092232

Должно работать. Сделай поиск на странице phpinfo по mbstring.
#585 #1092239
>>1092237

Смотри логи ошибок Апача. Также, проверь прописан ли extension_dir или как-то так в php.ini.
#586 #1092261
Поясните за трейты в пхп, типа горизонтальное наследование. Я правильно понимаю, что это осуждаемая ересь? Для чего они нужны?
#587 #1092265
>>1092116
Смысл его переубеждать? Пусть человек кодит как привык. Его проблемы. Пусть поддерживает свое говно мамонта с кучей инклудов из 4к строк в файле, считая, что оно работает лучше, безопаснее и производительнее, чем опен-сурс фреймворк с нормальной подгрузкой классов и проверенный большим сообществом более опытных программистов.
#588 #1092270
>>1092261
Трейты хорошая тема в прямых руках. В пыхе нет множественного наследования и некоторые задачи хорошо решаются именно трейтами.
MySQL #589 #1092316
Имеется таблица в БД на млн+ строк. В этой таблице есть поле с типом TEXT.

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

+хотят чтоб это работало быстро.

Делаю и проверяю на таблице в 200 срок - работает нормально. Проверяю на таблице в мнл+ строк - очень долго думает и в конце концов падает (504 Gateway Time-out)

В базе развесил всевозможные внешние ключи, индексы, типы полей. Поле TEXT является FULLTEXT.

От меня требуют невозможного или я что-то делаю не так?
#590 #1092338
>>1092126

>$u вычисляется из $i. (-$i - 1).



И где это написать надо?

Я пробовал в моём коде писать $stroka2 = mb_substr($text, -$i, -1), но он мне всё-равно неправильные результаты выдавал
#591 #1092341
>>1092338
Всё, разобрался. Спасибо за ответ.
#592 #1092373
Кто практикует автотесты, вы когда пишете тест для файловой системы (типа некий файл содержит корректные данные), используете библиотеки типа vfsStream или тупо создаете файлы в setUp и удаляете в tearDown?

Я попробовал этот vfsStream, но не смог корректно научить его дублировать реальные пути (т.е. __DIR__). то есть, в кофиге у меня указан параметр rootDir, который типа __DIR__ . '/..' и получается удобно, т.к. везде корректные пути относительно этого пааметра, который лежит в файле конфига. Но проблема в том, что по-модному не потестировать такую конструкцию с моком файловой системы.
#593 #1092375
>>1091484
У тебя проблемы с пониманием того, какая технология за что отвечает.
#594 #1092388
ОП, почему ты помогаешь в рамках чанов, а не идешь создавать собственный ресурс-чатик или в телегу?
Ты задумывался о созданий какого нибудь бэкап-сайтика с IRC?
#595 #1092394
Сейчас начал постепенно пилить задачу на список студентов. И внезапно задумался, а какая альтернатива есть у паттерна фронт контроллер. Можно как-нибудь по другому сделать?
ньюфаг и нуб
#596 #1092421
>>1092316
Попробуй использовать OFFSET
sage #598 #1092454
Ладно. Я сдался. Попробую переустановить апач вместе с php и сделать все снова по гайдам
#599 #1092455
>>1092454
приклеилось
#600 #1092473
>>1092394

>а какая альтернатива есть у паттерна фронт контроллер.


Можно использовать особый паттерн под названием "коппипаста".
#601 #1092476
Аноны в задаче о считалке она решается через объявление массива и удалении из него каждого 5-ого элемента или по другому можно?
#602 #1092503
В каких ситуациях нужны отражения? В мануале про них прочел, понял, что они делают и и как работают, но пока плохо понимаю, зачем они могут понадобиться.
#603 #1092507
>>1092503

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

class User
{
/** @json */
private $email;
/** @json */
private $name;
private $birthday;
}

$user = new User;
$json = toJson($user);

// { email: 'test@x.y', name: 'xxxx' }

Также, Reflection полезен , если ты хочешь написать data mapper, который может автоматически сохранять и загружать объекты из БД.

Но конечно, эти задачи можно решить и без него.
#604 #1092517
Так. Я установил Apache на диск C: (C:/Apache24)

Запускаю через httpd.exe
Вопрос: Не будет ли из-за этого у меня проблем?

Далее я создаю папку php, куда распаковываю архив php.

Открываю httpd.conf и прописываю LoadModule php5_module "c:/php/php7apache2_4.dll"
Вопрос:1) Правильно ли я прописал. В гайде написано LoadModule php5_module "c:/php/php5apache2.dll", а у меня нету такого файла, есть php7apache2_4.
2) Не нужно ли менять в LoadModule php5_module цифру 5 на 7?

Далее прописываю AddHandler application/x-httpd-php .php
и PHPIniDir "C:/php"

Сохраняю и запускаю через командую строчку. Вот что выдает httpd.exe: Syntax error on line 181 of C:/Apache24/conf/httpd.conf: Can't locate API module structure `php5_module' in file C:/php/php7apache2_4.dll: No error

Окей. Захоу обратно в httpd.conf и меняю в LoadModule php5_module цифру 5 на 7. Теперь запускаю и пишет
AH00558: httpd.exe: Could not reliably determine the server's fully qualified domain name, using тут шестнадцатеричные числа. Set the 'ServerName' directive globally to suppress this message Но теперь сервер работает.
Вопрос: все ли я правильно делаю? Нужно ли было менять цифру 5 на цифру 7?

Теперь проверяю и вижу, что php работает на вебсервере.

Далее создаю копию php.ini-production под названием php.ini

Захожу туда и расскоменчиваю строчк( пик )
Сохраняю и запускаю сервер. Вижу путь ини файла, который я создал. (пик)

Ввожу код <?php
$a = mb_strlen("aaa");
echo $a;
?>

И.... Все заработало. Ураааа! (пик)
Все ли я правильно сделал? Что стоит еще доделать?
Извините, что сюда так много написал, без этого я бы не смог заново копаться в апаче, потому что вчера очень много времени с ним потратил
#604 #1092517
Так. Я установил Apache на диск C: (C:/Apache24)

Запускаю через httpd.exe
Вопрос: Не будет ли из-за этого у меня проблем?

Далее я создаю папку php, куда распаковываю архив php.

Открываю httpd.conf и прописываю LoadModule php5_module "c:/php/php7apache2_4.dll"
Вопрос:1) Правильно ли я прописал. В гайде написано LoadModule php5_module "c:/php/php5apache2.dll", а у меня нету такого файла, есть php7apache2_4.
2) Не нужно ли менять в LoadModule php5_module цифру 5 на 7?

Далее прописываю AddHandler application/x-httpd-php .php
и PHPIniDir "C:/php"

Сохраняю и запускаю через командую строчку. Вот что выдает httpd.exe: Syntax error on line 181 of C:/Apache24/conf/httpd.conf: Can't locate API module structure `php5_module' in file C:/php/php7apache2_4.dll: No error

Окей. Захоу обратно в httpd.conf и меняю в LoadModule php5_module цифру 5 на 7. Теперь запускаю и пишет
AH00558: httpd.exe: Could not reliably determine the server's fully qualified domain name, using тут шестнадцатеричные числа. Set the 'ServerName' directive globally to suppress this message Но теперь сервер работает.
Вопрос: все ли я правильно делаю? Нужно ли было менять цифру 5 на цифру 7?

Теперь проверяю и вижу, что php работает на вебсервере.

Далее создаю копию php.ini-production под названием php.ini

Захожу туда и расскоменчиваю строчк( пик )
Сохраняю и запускаю сервер. Вижу путь ини файла, который я создал. (пик)

Ввожу код <?php
$a = mb_strlen("aaa");
echo $a;
?>

И.... Все заработало. Ураааа! (пик)
Все ли я правильно сделал? Что стоит еще доделать?
Извините, что сюда так много написал, без этого я бы не смог заново копаться в апаче, потому что вчера очень много времени с ним потратил
#605 #1092518
>>1092507

>class User


>{


>/** @json */


>private $email;


>/** @json */


>private $name;


>private $birthday;


>}


Лучей добра за задачу. А эти поля по условию строки?
#606 #1092545
>>1092518

Давай сделаем так: по умолчанию, они должны содержать скалярные значения, например int, float, bool, null.

Если они содержат массив, то он должен превратиться в JSON-массив.

Если они содержат объект, то он обрабатывается по такой же логике, то есть экспортируются поля с аннотацией @json. Если таких полей нет, выдается ошибка при попытке сконвертировать объект в JSON.
#607 #1092607
#608 #1092613
>>1092373
По хорошему нужно использовать готовую абстракцию Flysystem: https://flysystem.thephpleague.com/

Это абстракция позволит в тестах подменить хранилище на in-memory: https://flysystem.thephpleague.com/adapter/memory/

То есть в сервис, который работает с ФС передаёшь Filesystem:

class FileUploader
{
public function __construct(Filesystem $filesystem)
{
$this->filesystem = $filesystem;
}

public function upload(File $file)
{
...
}
}

А в тестах можно так:
$filesystem = new Filesystem(new MemoryAdapter());
$fileUploader = new FileUploader($filesystem);
$fileUploader->upload($file);
$this->assertTrue($fileUploader->has($file->getPath));

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

>>1092388
Я не ОП, сайт архивач-для-php-тредов пилится усилиями обитателей треда. Очень тормозил процесс тот факт, что в старых тредах криво сохранённый HTML. Как до конца поправим и задеплоим - напишем об этом тут.

>>1092503
Рефлексией в повседневных задачах пользоваться не нужно, но нужно понимать как работают библиотеки, которые её используют. На рефлексии например работают DI контейнеры с auto-wiring: http://php-di.org/doc/autowiring.html (думаю ты хорошо разберёшься с рефлексией если напишешь свой DI контейнер с автовайрингом - примитивная реализация вряд ли будет больше ~200 строк).
#608 #1092613
>>1092373
По хорошему нужно использовать готовую абстракцию Flysystem: https://flysystem.thephpleague.com/

Это абстракция позволит в тестах подменить хранилище на in-memory: https://flysystem.thephpleague.com/adapter/memory/

То есть в сервис, который работает с ФС передаёшь Filesystem:

class FileUploader
{
public function __construct(Filesystem $filesystem)
{
$this->filesystem = $filesystem;
}

public function upload(File $file)
{
...
}
}

А в тестах можно так:
$filesystem = new Filesystem(new MemoryAdapter());
$fileUploader = new FileUploader($filesystem);
$fileUploader->upload($file);
$this->assertTrue($fileUploader->has($file->getPath));

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

>>1092388
Я не ОП, сайт архивач-для-php-тредов пилится усилиями обитателей треда. Очень тормозил процесс тот факт, что в старых тредах криво сохранённый HTML. Как до конца поправим и задеплоим - напишем об этом тут.

>>1092503
Рефлексией в повседневных задачах пользоваться не нужно, но нужно понимать как работают библиотеки, которые её используют. На рефлексии например работают DI контейнеры с auto-wiring: http://php-di.org/doc/autowiring.html (думаю ты хорошо разберёшься с рефлексией если напишешь свой DI контейнер с автовайрингом - примитивная реализация вряд ли будет больше ~200 строк).
#609 #1092677
>>1092613
ну по сути vfsStream - это такой же аналог Flysystem. хотя про последнюю не знал, спасибо.

код у меня образно говоря такой:
class Settings
{
const LIB_ROOT = __DIR__ . '/..';
private $cookiePath = LIB_ROOT . '/../var/cookie.txt'; // это библиотека-клиент
public function getCookiePath // это используем везде в библиотеке
public function setCookiePath($path)
{
$this->cookiePath = self::LIB_ROOT . $path;
}

class Auth
{
// тут всякая логика
}

class AuthTest
{
protected function setUp()
{
$this->settings = new Settings();
$this->settings->setCookiePath('/var/test_cookie.txt');
}

и далее создаем этот файл и тестируем его

моя задача - определять путь к куки как постоянный, т.е. чтобы мы могли определить его в любом месте проекта и он был одинаковым независимо от расположения файла, где мы его определили, в иерархии папок. Но возникла проблема - не протестировать с использованием того же vfsstream. видимо надо рефакторить, но я не понимаю как. может, кто-то подскажет?
#609 #1092677
>>1092613
ну по сути vfsStream - это такой же аналог Flysystem. хотя про последнюю не знал, спасибо.

код у меня образно говоря такой:
class Settings
{
const LIB_ROOT = __DIR__ . '/..';
private $cookiePath = LIB_ROOT . '/../var/cookie.txt'; // это библиотека-клиент
public function getCookiePath // это используем везде в библиотеке
public function setCookiePath($path)
{
$this->cookiePath = self::LIB_ROOT . $path;
}

class Auth
{
// тут всякая логика
}

class AuthTest
{
protected function setUp()
{
$this->settings = new Settings();
$this->settings->setCookiePath('/var/test_cookie.txt');
}

и далее создаем этот файл и тестируем его

моя задача - определять путь к куки как постоянный, т.е. чтобы мы могли определить его в любом месте проекта и он был одинаковым независимо от расположения файла, где мы его определили, в иерархии папок. Но возникла проблема - не протестировать с использованием того же vfsstream. видимо надо рефакторить, но я не понимаю как. может, кто-то подскажет?
#610 #1092684
Анончики, не смейтесь надо мной, я очень далек от кодинга и тут решил почитать составленный вводный курс для чайников. Там мне попалась задачка, цитирую: "Некто кладет в банк 10000 р. Банк начисляет 10% годовых (то есть, каждый год на счету становится на 10% больше, чем в прошлом году). Напиши программу, считающую, через сколько лет в банке будет миллион? Сколько лет будет этому некто? Доживет ли некто до этого дня, если сегодня ему 16 лет?"

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

<?php

for ($x = 10000; $x == 1000000; $x = $x+($x*10/100)) {

for ($y = 16; $x == 1000000; $y ++) {

echo "В $y будет $x на счете \n";
}
}

?>

А дальше ничего не происходит. Вы, наверное, улыбаетесь, читая этот пост, мол, такую простоту не может решить, но я нахожусь в тупике, программа выполнена успешно, пишется, но ничего не происходит. Никакого подсчета и вывода сообщений. В чем заключается моя ошибка? Заранее благодарю. Писал и запускал это на айдеоне.
#611 #1092685
>>1092684
Upd: перед вторым for в коде нет \t, не знаю, откуда она тут при постинге появилась.
#612 #1092687
>>1092684

>$x == 1000000



Условие у тебя: пока $x равен 1000000
#613 #1092691
>>1092687
http://archive-ipq-co.narod.ru/l1/loops.html

Там справа есть таблица Условия( как в операторе if) посмотри её
#614 #1092692
>>1092691
>>1092684
промазал
#615 #1092702
>>1092687
Поменял на <=, никакого ответа. "Пишет, Превышено ограничение на время". Боюсь, я где-то еще допустил ошибку.
#616 #1092703
>>1082636

Вопрос с собеседования? Можешь начать с обзора для начинающих: https://ruhighload.com/post/Работа+с+индексами+в+MySQL

Потом почитать про деревья: https://ru.wikipedia.org/wiki/Двоичное_дерево_поиска

https://ru.wikipedia.org/wiki/B-дерево

Потом есть такая статья на англ: http://www.vertabelo.com/blog/technical-articles/all-about-indexes-part-2-mysql-index-structure-and-performance

Продолжить статьей про индексы в postgres, чтобы вообще лучше разобраться в этой теме: https://habrahabr.ru/company/postgrespro/blog/326096/

И закончить можно документацией на англ: https://dev.mysql.com/doc/refman/5.7/en/optimization-indexes.html

https://dev.mysql.com/doc/refman/5.7/en/innodb-indexes.html

Задавай вопросы, если что-то непонятно.
#617 #1092704
https://ideone.com/aldnLW

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

И почему то он русскую а не заменяет в последнем слове.
#618 #1092721
>>1092092

>$q - это не имя объекта, а переменной


Вот кажется этого я не уловил в примере.

// Создадим три объекта (так как у нас будет 3 вопроса в тесте), и сохраним их в трех переменных:
$q1 = new Question;
$q2 = new Question;
$q3 = new Question;

Т.е. объекты (предметы) - это просто значения, которые можно вкладывать в переменные?

// Вопрос 1
$q1 = new Question;
$q1->text = "Какая планета располагается четвертой по счету от Солнца?";
$q1->points = 10; // 10 баллов за ответ
$q1->answers = array('a' => 'Венера', 'b' => 'Марс', 'c' => 'Юпитер', 'd' => 'Меркурий'); // Варианты ответа
$q1->correctAnswer = 'b'; // Правильный ответ

// Вопрос 2
$q2 = new Question;
$q2->text = 'Какой город является столицей Великобритании?';
$q2->points = 5;
$q2->answers = array('a' => 'Париж', 'b' => 'Москва', 'c' => 'Нью-Йорк', 'd' => 'Лондон');
$q2->correctAnswer = 'd';

// Вопрос 3
$q3 = new Question;
$q3->text = 'Кто придумал теорию относительности?';
$q3->points = 30;
$q3->answers = array('a' => 'Джон Леннон', 'b' => 'Джим Моррисон', 'c' => 'Альберт Эйнштейн', 'd' => 'Исаак Ньютон');
$q3->correctAnswer = 'c';

Значит здесь мы берем перменные $q1, $q2, $q3 и у каждой пишем:
"Отныне ты у нас хранишь ссылку на объект new Question и вот твои поля".

>>1092096

> У объектов нет имен (хотя и есть уникальные идентификаторы).


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

>>1092099>>1092102>>1092106
Спасибо! Теперь я понял.

Но вот что теперь меня смущает:

// Создаем пустой массив
$questions = [];

// Создаем и заполняем первый объект
$q = new Question;
$q->text = ...

// Кладем вопрос в массив
$questions[] = $q;

// Создаем второй объект
$q = new Question;

Вот мы поместили ссылку на объект в массив. Далее мы перезаписываем ссылку при создании второго объекта и добавляем её в массив.
У нас ведь просто получится [0]=>$q;[1]=>$q;[2]=>$q; ?
#618 #1092721
>>1092092

>$q - это не имя объекта, а переменной


Вот кажется этого я не уловил в примере.

// Создадим три объекта (так как у нас будет 3 вопроса в тесте), и сохраним их в трех переменных:
$q1 = new Question;
$q2 = new Question;
$q3 = new Question;

Т.е. объекты (предметы) - это просто значения, которые можно вкладывать в переменные?

// Вопрос 1
$q1 = new Question;
$q1->text = "Какая планета располагается четвертой по счету от Солнца?";
$q1->points = 10; // 10 баллов за ответ
$q1->answers = array('a' => 'Венера', 'b' => 'Марс', 'c' => 'Юпитер', 'd' => 'Меркурий'); // Варианты ответа
$q1->correctAnswer = 'b'; // Правильный ответ

// Вопрос 2
$q2 = new Question;
$q2->text = 'Какой город является столицей Великобритании?';
$q2->points = 5;
$q2->answers = array('a' => 'Париж', 'b' => 'Москва', 'c' => 'Нью-Йорк', 'd' => 'Лондон');
$q2->correctAnswer = 'd';

// Вопрос 3
$q3 = new Question;
$q3->text = 'Кто придумал теорию относительности?';
$q3->points = 30;
$q3->answers = array('a' => 'Джон Леннон', 'b' => 'Джим Моррисон', 'c' => 'Альберт Эйнштейн', 'd' => 'Исаак Ньютон');
$q3->correctAnswer = 'c';

Значит здесь мы берем перменные $q1, $q2, $q3 и у каждой пишем:
"Отныне ты у нас хранишь ссылку на объект new Question и вот твои поля".

>>1092096

> У объектов нет имен (хотя и есть уникальные идентификаторы).


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

>>1092099>>1092102>>1092106
Спасибо! Теперь я понял.

Но вот что теперь меня смущает:

// Создаем пустой массив
$questions = [];

// Создаем и заполняем первый объект
$q = new Question;
$q->text = ...

// Кладем вопрос в массив
$questions[] = $q;

// Создаем второй объект
$q = new Question;

Вот мы поместили ссылку на объект в массив. Далее мы перезаписываем ссылку при создании второго объекта и добавляем её в массив.
У нас ведь просто получится [0]=>$q;[1]=>$q;[2]=>$q; ?
#619 #1092722
>>1092703
А такой же подборки вопросов по собеседованию на PHP-жуниора тут не завалялось?
#620 #1092723
>>1092721

> Вот мы поместили ссылку на объект в массив. Далее мы перезаписываем ссылку при создании второго объекта и добавляем её в массив.



Условно, это можно записать так (если представить, что ссылка на объект это строка с номером):

$q = 'object#1'; // new Question ...
...
$questions[] = $q;
$q = 'object#2'; // new Question..
$questions[] = $q;

В итоге массив $questions хранит ссылки на все объекты: ['object#1', 'object#2'], в чем легко удедиться, сделав var_dump($questions);

> У нас ведь просто получится [0]=>$q;[1]=>$q;[2]=>$q; ?


Ты по прежнему не отличаешь переменной от объекта. У нас получится [0 => Объект№1, 1 => Объект#2, ...] в чем легко убедиться, сделав var_dump.
#621 #1092724
>>1092721

И поясню на всякий случай.

Строка

$questions[] = $q;

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

То есть в массив кладется не переменная, а ссылка на объект, которая в ней хранилась.
#622 #1092726
Задачки-кун, насчет твоей статьи про CSRF. Без кук ты советуешь использовать nonce. Но его всегда нужно писать в базу с IP пользователя, чтобы затем проверить, с той же ли подсети отправлена форма (для надежности маску подсети стоит брать /16).
Если форма доступна без авторизации, ничто не мешает злоумышленнику при запросе на его сайт сходить на сайт с формой и выдрать токен, затем поместить в свою форму.
#623 #1092728
>>1092726

Точно! Молодец, ты внимательный.

Но привязка к IP - плохой вариант для динамического IP. Это будет давать "гейзенбаги", когда у пользователей иногда не работает отправка формы.

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

Также, слишком большая маска позволяет проводить атаку, получив доступ к хотя бы одному IP из подсети (например: атака на пользователей VPN провайдера).

Куки как раз и позволяют не привязываться к IP, чем они и хороши.

Вообще, конечно, если бы в протоколе по умолчанию были запрещены кроссдоменные отправки форм, насколько было бы все проще! Увы, формы появились раньше, чем авторизация.

Тут почему-то отговаривают от варианта с кукой ( https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF) )

Тут описаны разные варианты защиты: https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet#General_Recommendations_For_Automated_CSRF_Defense

Вариант с кукой называется "Double Submit Cookie".

Видимо, без кук никак. Можешь посмотреть статью по ссылке, вроде без кук вариантов нету.

"Если форма доступна без авторизации" - если кук нет, то и авторизацию сделать почти нереально.
#624 #1092730
>>1092726

А вот мне интересно, можно ли обойти проверку Referer/Origin, если на атакуемом сайте есть откртый редиректор?

То есть идея такая:

bad.example.com отправляет форму на target.example.com/redirect?to=target.example.com/form. Браузер получает ответ с кодом 301, 303 , 307 и тд и постит форму на полученный URL, возможно, используя в качестве Referer или Origin URL жертвы.

Ты не хочешь попроверять поведение браузеров в этом случае? Постят ли они форму на новый URL при редиректе, что отправляют в заголовке Referer/Origin?
#625 #1092731
>>1092726

Я просто вспомнил, когда-то в соцсетях фильтр на ссылки обходили через редиректоры, вставляя ссылку вида vk.com/redirect?to=evil.example.com

Это и сейчас наверно где-то работает. Открытый редирект - потенциальная уязвимость.
#626 #1092732
>>1092723
Ха. У меня просто разрывается шаблон немного. Раньше мне объясняли, что переменная - это такая ячейка памяти, в которой хранится что-то (строка, число, массив) и, соответственно, без ячейки не будет места для какой-то сущности.
Теперь же получается, что переменная - это просто ссылка на сущность, а эта сущность может существовать без какой-то именной ссылки.

>>1092724
Ну т.е. ссылкой было $q, а стал индекс в массиве?
#627 #1092733
Аноны, а хотите интересные, головоломные задачки на DOM? У меня есть.

1) Дан HTML код. Нужно удалить из него определенные теги вместе с их содержимым. Например, удаляем тег em.

Было: Hello <em>world</em> 123
Стало: Hello 123

2) Нужно удалить указанные теги, но оставить их содержимое.

Было: <em>Hello <em>world</em> 123 </em>
Стало: Hello world 123

3) Нужно заменить тег ссылки на текстовый URL

Было: Welcome to <a href="//example.com/123">my site</a>
Стало: Welcome to my site [//example.com/123]

4) Нужно удалить теги ссылок (но оставить содержимое), если в URL содержится домен из черного списка

Было: Welcome to <a href="//bad.example.com/123">my bad site</a> and <a href="//good.example.com/123">my good site</a>
Стало: Welcome to <del>my bad site</del> and <a href="//good.example.com/123">my good site</a>

Регулярки не подходят, только если на них не реализован полноценный парсинг грамматики HTML5.
#628 #1092734
>>1092732

> ссылкой было $q, а стал индекс в массиве?


Плохо сформулировано. Ссылка [на объект] хранилась в переменной $q, а затем была дополнительно скопирована в массив.

> Теперь же получается, что переменная - это просто ссылка на сущность


Это только у объектов так. Числа, строки - хранятся "прямо" в переменной. Объекты хранятся как бы в отдельной области памяти, а в переменной хранится его идентификатор.

Пруф:

$a = new Question;
$a->text = '1';
$b = $a; // !!! важное место
$b->text = '2';
var_dump($a->text); // что тут выведется?

Ответь, что выведет этот код?

Если он выведет 1, значит в переменной хранится объект, и команда $b = $a создает вторую копию объекта.

Если он выведет 2, значит в переменных $b и $a хранится ссылка (идентификатор) на один и тот же объект, хранящийся где-то в памяти.
#629 #1092735
>>1092734

> Плохо сформулировано. Ссылка [на объект] хранилась в переменной $q, а затем была дополнительно скопирована в массив.


Ну да. Ссылку скопировали в индекс, но она осталась в переменной, а потом уже перезаписали переменную.

Но меня теперь смущает вот что: что это за ссылка такая и как она выглядит? Просто у меня была ассоциация, что сама переменная и есть ссылка, а тут получается, что нет. Типа "бери значения из ячейки памяти, которая помечена как $q", а теперь получается, что сама ссылка существует в какой-то другой форме.

Короч, это как думать, что твоя имя из вконтакта = твоему ИНН.

https://ideone.com/RuLe26
Да, действительно. Выводится 2-ка.

Получается, что тут
$b = $a; // !!! важное место

Просто копируется ссылка.
#630 #1092738
>>1092735

Ссылка никак не выглядит. Если ты попытаешься сдампить содержимое переменной

var_dump($q);

То он сдмапит сам объект. Хотя в дампе будет указан его уникальный идентификатор.

Если тебе все равно хочется знать, как выглядит эта ссылка, придется почитать статьи про zval

https://habrahabr.ru/post/162713/
https://habrahabr.ru/company/mailru/blog/257999/
https://habrahabr.ru/company/mailru/blog/255237/
http://www.phpinternalsbook.com/zvals/basic_structure.html

Предупрежу, что без знания языка Си понять будет трудно.
#631 #1092740
>>1092738
Понятно. Пожалуй, не буду вскрывать эту тему.

Премного благодарен за помощь!
#632 #1092741
>>1092735

Ты можешь представить, что в переменной хранится 2 вещи:

- метка, что в ней хранится идентификатор объекта (а не число или строка)
- сам идентификатор, указывающий, где в памяти можно найти объект

Это вместе и является "значением". Или тем самым zval, о котром написано в статьях. То есть в PHP "значение" - это сложная структура, которая кроме самого значения или указателя на его положение в памяти, содержит и тип значения (строка? число? массив? объект?).
#633 #1092742
>>1092741

>- метка, что в ней хранится идентификатор объекта (а не число или строка)


>- сам идентификатор, указывающий, где в памяти можно найти объект


Понятно. Это просто специально спрятано под капот для ПХП-бояр.
#634 #1092743
>>1092728

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



У кого выключены куки, тому к ограничениям не привыкать. Можно во время заполнения формы вообще впн поднять, страницу запросить с России, отправить с Германии. Даже у мобильных операторов питерские-московские подсетки /18-/19, так что это с запасом. Да, сосед по подсети сможет подсунуть валидный токен.
Все зависит от того, насколько нужно форму защитить. Можно разрешить один IP, либо включай куки.

Нет, при редиректе форма отправится только один раз, на good.example.com/ redirect?to=good.com. Далее good.com будет запрошен без данных формы.
#635 #1092745
А без кук авторизация делается старым-добрым ID сессии в каждой ссылке.
#636 #1092746
Кстати, насчет смены IP. Та же капча почти всегда вяжется к IP в анонимных формах, как на имиджбордах как раз. Никто не жалуется. Так что токен можно и нуэно вязать к ип, не стоит отговаривать от этого.
#637 #1092750
>>1092741
И тут ещё один вопрос про переменные и объекты. Если ссылка на объект не будет храниться ни в одной переменной/массиве/чем-либо ещё - он просто исчезнет?
#638 #1092756
Где правильнее оборачивать переменные в htmlspecialchars - в классе HtmlWriter, либо в самих шаблонах?
#639 #1092784
Начинаю ненавидеть php. Я одним скриптом создаю процесс, мне необходимо использовать этот процесс другим скриптом, для этого нужно как-то передать переменную resource. Как сукаблядь это сделать? Почему php такой уёбищьный?
#640 #1092793
Аноны, я жду ответа. Нормальным путем я пойти не могу по ряду причин, мне необходимо каким-то хуем использовать переменную resource в другом скрипте.
6 Кб, 672x69
#641 #1092795
Не могу понять, почему на нектороых серверах интепритатор ругается на второй аргумент в system(). В http://php.net/manual/en/function.system.php ответ на вопрос не нашел, в php 5.6 так же должны поддерживаться 2 аргумента
#642 #1092796
>>1092793
$_GET / $_POST
#643 #1092799
>>1092796
Через гет можно передать resource? Она не трансформируется в какоето уёбище? Еще я читал что использовать resource по каким то неведомым причинам в другом скрипте невозможно.
#644 #1092825
Скажите хотя бы, как строку преобразовать в resource?
#645 #1092830
Сука, бесполезный тред.
#646 #1092841
Сап. Делаю Soap Request на Веб-Сервис с помощью SoapClient класса от php.
Запрос типа
<segmentControlDetails>
<quantity>1</quantity>
<numberOfUnits>2</numberOfUnits>
</segmentControlDetails>

я могу послать просто делая это массивом
"segmentControlDetails" => [
"quantity" => "1" ........

Но в другом запросе мне нужно сделать что-то вроде
<Criterion ExactMatch="true">
<HotelRef HotelCityCode="PAR">

Есть такие кто работал с этим классом?
Как можно это оформить?
32 Кб, 435x431
#647 #1092876
php все засерает вот этим, при каждом использовании shmop_open
Как это исправить? Помогите, прошу.
#648 #1092884
>>1092745

Это небезопасно, так как id сессии остается в Referer при переходе на другой сайт, фиксируется в логах, также возможна атака "фиксации сессии", когда злоумышленник передает жертве УРЛ со своим id сессии.

В поисковике тоже могут индексироваться ссылки с сессией.
#649 #1092885
>>1092738

>ZEND_ENDIAN_LOHI


Почему эти сраные расисты называют индейцев лохами?
#650 #1092886
>>1092795

Ты используешь двойные кавычки, а bash делает подстановку переменных в них и удаляет retval. Попробуй поставь echo перед php и увидишь что осталось от твоей команды.

Используй одиночные кавычки.

>>1092799

Нельзя. Resource может представлять собой идентификатор открытого файла. Его нельзя никуда передать, так как он не имеет смысла в другом процессе ОС.

>>1092825

Нельзя
#651 #1092888
>>1092886
Как тогда сделать так, что бы shmop_open открывался одним файлом, а shmop_write использовался другим если переменную ресур передать нельзя? Мне нужно каждые 50 милисекунд записывать данные в разделяемую память, а php при каждом использовании shmop_open независимо от параметров засерает память.
50 Кб, 317x372
#652 #1092948
>>1092876
Понял суть проблемы, функции shmop_delete и shmop_close не работают совсем. Но теперь непонятно хули они не работают, почему я нихуя не могу нагуглить по этому поводу.
#653 #1092960
>>1092876

Ты тут много постов написал, не можешь тогда еще написать (кратко), как ты используешь этот shmop? И для каких целей (может, я смогу подсказать другой вариант решения)? И краткий пример кода.

То, что я вижу на урезанном скриншоте - это скорее всего операции с критическими секциями (блокировки в Windows). Ничего ненормального в них нет.

Также, пробовал ли ты смотреть исходники расширения shmop? https://github.com/php/php-src/tree/master/ext/shmop
#654 #1092966
>>1092960
За ссылку больше спасибо, не мог подобного сам нагуглить.
Извиняюсь за истерику, я не могу закрыть участок который использовал, так как shmop_close() и shmop_delete() непонятно почему не работает.
Для чего использую: я несколько раз в секунду php получаю переменную, и мне нужно записывать её в разделяемую память. Каким бы я образом не использовал shmop_open - оно создаёт новую херню что на скриншоте, а старую удалить не выходит, и в итоге память засирается. Мне нужно либо закрывать старые штуки, либо открыть один раз и использовать уже открытый участок не обращаясь каждый раз через функцию open, но я понял уже что это невозможно. Уже около двух недель трахаюсь.
#655 #1092968
>>1092966

> так как shmop_close() и shmop_delete() непонятно почему не работает.



В чем это проявляется?

Покажи простой пример кода, который у тебя работает с памятью.

И ты читал, как ей пользоваться? Ты должен в скрипте "открыть" сегмент памяти, записать значение и закрыть.

Также, если ты будешь код разбирать, то для кода под виндой надо смотреть еще тут: https://github.com/php/php-src/blob/master/TSRM/tsrm_win32.c#L640
#656 #1092976
>>1092968
<?php
$id_ask = 1117;

$resource = shmop_open($id_ask, 'w', 0, 0);
if($resource == false)
{
$resource = shmop_open($id_ask, 'n', 0, 1000); //Создаёт новый, если его нет
if($resource == false)
{
echo "<br/>";
echo "feil";
echo "<br/>";
}
else
{
echo "<br/>";
echo "удача";
echo "<br/>";
}
}
else
{
echo "<br/>";
echo "Открыли существующий участок";
echo "<br/>";
}

shmop_write($resource, 1.445, 0);

shmop_close($resource);

if(!shmop_delete($resource)) {
echo "<br/>";
echo "Невозможно отметить участок памяти для освобождения.";
echo "<br/>";
}
?>

Результат:

>Открыли существующий участок



>Warning: shmop_delete(): supplied resource is not a valid shmop resource in Z:\home\localhost\www\TestMapp\CloseHendleTest.php on line 32



>Невозможно отметить участок памяти для освобождения.

#656 #1092976
>>1092968
<?php
$id_ask = 1117;

$resource = shmop_open($id_ask, 'w', 0, 0);
if($resource == false)
{
$resource = shmop_open($id_ask, 'n', 0, 1000); //Создаёт новый, если его нет
if($resource == false)
{
echo "<br/>";
echo "feil";
echo "<br/>";
}
else
{
echo "<br/>";
echo "удача";
echo "<br/>";
}
}
else
{
echo "<br/>";
echo "Открыли существующий участок";
echo "<br/>";
}

shmop_write($resource, 1.445, 0);

shmop_close($resource);

if(!shmop_delete($resource)) {
echo "<br/>";
echo "Невозможно отметить участок памяти для освобождения.";
echo "<br/>";
}
?>

Результат:

>Открыли существующий участок



>Warning: shmop_delete(): supplied resource is not a valid shmop resource in Z:\home\localhost\www\TestMapp\CloseHendleTest.php on line 32



>Невозможно отметить участок памяти для освобождения.

#657 #1092978
>>1092976

Во-первых, результат операции write надо проверять. Во-вторых, почитай мануал по shmop_delete очень внимательно - ты делаешь это неправильно.

В-третьих, я не понимаю, в чем смысл записать значение в память и сразу же удалить этот сгемент.
#658 #1092980
<?php
$id_ask = 1117;

$resource = shmop_open($id_ask, 'w', 0, 0);
if($resource == false)
{
$resource = shmop_open($id_ask, 'n', 0, 1000); //Создаёт новый, если его нет
if($resource == false)
{
echo "<br/>";
echo "feil";
echo "<br/>";
}
else
{
echo "<br/>";
echo "удача";
echo "<br/>";
}
}
else
{
echo "<br/>";
echo "Открыли существующий участок";
echo "<br/>";
}

shmop_write($resource, 1.445, 0);

shmop_close($resource);

if(!shmop_delete($resource)) {
echo "<br/>";
echo "Невозможно отметить участок памяти для освобождения.";
echo "<br/>";
}
?>
#658 #1092980
<?php
$id_ask = 1117;

$resource = shmop_open($id_ask, 'w', 0, 0);
if($resource == false)
{
$resource = shmop_open($id_ask, 'n', 0, 1000); //Создаёт новый, если его нет
if($resource == false)
{
echo "<br/>";
echo "feil";
echo "<br/>";
}
else
{
echo "<br/>";
echo "удача";
echo "<br/>";
}
}
else
{
echo "<br/>";
echo "Открыли существующий участок";
echo "<br/>";
}

shmop_write($resource, 1.445, 0);

shmop_close($resource);

if(!shmop_delete($resource)) {
echo "<br/>";
echo "Невозможно отметить участок памяти для освобождения.";
echo "<br/>";
}
?>
#659 #1092981
>>1092978

>почитай мануал по shmop_delete очень внимательно - ты делаешь это неправильно


А ссылку на мануал можно? А то я находил очень короткий, к сожалению.

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


Я не знаю что ещё делать, что бы функция shmop_open память не захламляла.

>результат операции write надо проверять


Почему? Ну, я проверил что значение записалось другим скриптом.
#660 #1092983
>>1092978
Вот максимум что я находил http://php.net/manual/ru/function.shmop-delete.php
#661 #1092989
https://github.com/kichiweb123/students

Опчик, вот проект со студентами чекай буду рад услышать все недостатки. И еще это реализовано без PDO, MVC, но с ООП все в одном классе, потому что я не понимаю как их группировать, урок читал всё равно не понимаю, объясните мне на пальцах на моём коде как я должен был всё разгруппировать с ООП И MVC. Или почитать чего.
ньюфаня
#663 #1093009
>>1092989

Читал https://github.com/codedokode/pasta/blob/master/arch/mvc.md ? Там есть пример кода.

Читал комментарии к задаче про студентов?
#664 #1093030
>>1093009
Да, не понимаю хоть убей, есть где более подробно это разжевывается?
#665 #1093164
>>1093008
Кстати

>$shm_id = shmop_open(0xff3, "c", 0644, 100);


А что это

>0644


за херня, и для чего она нужна?
204 Кб, 1366x768
#666 #1093178
>>1093008
Код выполнил по образцу, ошибок вроде как нету, но эта херня всё равно никуда не исчезает, и если 20 раз в секунду вызывать 20 каналов разделяемой памяти, это очень быстро всю память засрёт.
#667 #1093184
>>1093164

Это права доступа. Я думаю, они актуальны только в линуксе. Тебе было бы полезно открыть линуксовый мануал по shared memory так как расширение PHP -это по сути обертка над функциями ядра линукс.

http://man7.org/linux/man-pages/man7/shm_overview.7.html

http://man7.org/linux/man-pages/man3/shm_open.3.html

> Create the shared memory object if it does not exist. The


> user and group ownership of the object are taken from the


> corresponding effective IDs of the calling process, and


> the object's permission bits are set according to the low-


> order 9 bits of mode, except that those bits set in the


> process file mode creation mask (see umask(2)) are cleared


> for the new object.



Задают разрешения для владельца, группы владельца и прочих. Аналогично с разрешениями на файлы.
#668 #1093187
>>1093178

Вообще, я вижу только 3 сегмента, а не 20.

Нужно проверить так: напиши PHP скрипт, который в цикле бесконечно создает/осовбождает кусок памяти с одинаковым id и запусти его в командной строке. А Затем process explorer'ом можешь посмотреть, сожрет ли он всю память или нет.

Для проверки, можно сделать еще второй скрипт, который будет постоянно пытаться читать этот кусок памяти.

Ты запускаешь PHP в рамках Апача, но Апач многопоточный и может там каждый поток использует свой объект Windows. Так мы ничего не выясним.
#669 #1093193
>>1093187

>Вообще, я вижу только 3 сегмента, а не 20.


Речь не про этот код.

>напиши PHP скрипт, который в цикле бесконечно создает/осовбождает кусок памяти с одинаковым id и запусти его в командной строке


Сейчас сделаю.
200 Кб, 1366x768
#670 #1093202
>>1093187

>напиши PHP скрипт, который в цикле бесконечно создает/осовбождает кусок памяти с одинаковым id и запусти его в командной строке

#671 #1093219
>>1093184

> The file descriptor is normally used in subsequent calls to


ftruncate(2) (for a newly created object) and mmap(2). After a call
to mmap(2) the file descriptor may be closed without affecting the
memory mapping.
Как это мне может помочь?
#672 #1093229
>>1093202

Ты запускаешь из-под Апача, где есть таймауты и прочее. Я про командную строку.

https://github.com/codedokode/pasta/blob/master/soft/php-install.md

Тут в конце написано, как запустить скрипт.

c:\......\php.exe d:\....\file.php

>>1093219

Мануал тебе объясняет, что за права доступа указываются у блоков разделяемой памяти.
#673 #1093241
>>1093229
Я конечно попробую, но проблему то это не решит, мне нужно что бы оно из под апача работало.
#674 #1093242
https://github.com/kichiweb123/students

Опчик, вот с ОПП MVC, кроме PDO. Поясни за ошибки и прочее, правильно я сделал с MVC? Вроде всё прочёл.
#675 #1093243
>>1093242
проект студентов
https://github.com/kichiweb123/students #677 #1093270
>>1093242

То, что сейчас, нужно переделывать. Это не MVC ООП приложение. Вот с чего можно начать исправление (после того, как сделаешь то, что написано в конце поста):

1) Самое важное - нужно сделать нормальную структуру файлов. Вот у тебя в корневой папке накидана куча файлов, и непонятно вообще, для чего они все нужны. В одном какие-то куски HTML кода, в другом куски PHP кода - их надо разложить по папочкам с соответствующими названиями. Если у тебя проблема с придумыванием названия, объясни мне, зачем нужен тот или иной файл, и я помогу придумать название.

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

Очень важно, чтобы проект был понятный другому человеку. А для этого должна быть логика в том, как разложены файлы.

2) У тебя все свалено в корневую папку и к любому из скриптов можно обратиться напрямую (набрав его имя в адресной строке браузера). Вот например к скрипту https://github.com/kichiweb123/students/blob/master/check_and_update_profile.php . Но это ведь просто выдаст ошибку. Раз к нему нельзя обратиться, зачем делать такую возможность?

У меня в комментариях к задаче написано про публичную папку. Нужно выделить такую папку и в нее положить только те файлы, к которым можно обращаться напрямую. Все остальные файлы должны быть за пределами публичной папки. Если с этим какие-то сложности, напиши, в чем именно проблема.

3) У меня в уроке есть ссылка на урок про автозагрузку и PSR-4. Почему ты не используешь рекомендацию PSR-4 при выборе имен файлов, а придумываешь какие-то свои нестандартные имена?

4) Там есть такой код в файле https://github.com/kichiweb123/students/blob/master/index.php

> and ($_SERVER['QUERY_STRING'] == "id=registration"))


В такой ситуации нужно использовать массивы $_POST и $_GET. Более того, у меня в уроке ( https://github.com/codedokode/pasta/blob/master/soft/web-server.md ) недавно добавлено объяснение про массив $_GET. Прочитай про него.

5) В файле https://github.com/kichiweb123/students/blob/master/index.php

Тут смешана логика работы программы (вроде автозагрузки) и HTML-код. Этого не должно быть, у меня в комментариях написано про шаблоны и есть урок на эту тему. Весь HTML-код надо вынести в шаблоны.

6) Зачем там ob_start в index.php?

7) Тут https://github.com/kichiweb123/students/blob/master/edit_profile.php и тут https://github.com/kichiweb123/students/blob/master/registration.php повторяется одна и та же форма, нужно избавиться от дублирования кода. Это только раздувает объем проекта (и в нем труднее разбираться), и при каких-то правках их приходится делать в нескольких местах.

8) В файле edit_profile.php

> <label for="second_name">Фамилия: <?php echo $editProf[0]['second_name']; ?></label>



Здесь может быть уязвимость. Прочитай урок про XSS, который так же упомянут в комментариях и исправь.

9) В файле https://github.com/kichiweb123/students/blob/master/model/TableModel.class.php

> WHERE login = '{$login}'


> AND pass = '{$pass}'";


Прочитай на моем гитхабе урок про уязвимость "SQL инъекция" и исправь их.

10) В файле registration.php код как-то криво выровнен. Отформатируй его, например, на сайте htmlformatter.com

11) В файле registration.php ошибка:

> id="exampleRadios1"



id должен быть уникальным и не должен повторяться. Тебе надо проверить твой HTML-код (который генерирует твое приложение) на правильность. Для этого открой страницу своего приложения в браузере, сохрани ее (Ctrl + S) как HTML-файл без картинок, и загрузи этот файл в валидатор: https://html5.validator.nu/ . Он даст список ошибок, с ними надо разобраться.

Если что-то с валидатором непонятно, задавай вопросы.

12) Нужно давать более хорошие имена классам и функциям, чтобы в коде было проще разобраться.

Ну например, есть class TableModel. "модель таблицы". Трудно понять, какой таблицы? И что значит "модель таблицы"? Это ведь явно реализация паттерна TableDataGateway для таблицы студентов, значит правильно назвать класс StudentDataGateway.

Ну или возьмем класс "TableControllerRegistration". "регистрация контроллера таблицы"? Смысл понять трудно. Этот класс явно представляет собой информацию из формы регистрации, то есть информацию о студенте, введенную в форму. Значит, можно его назвать "данные формы регистрации студента" или StudentRegistrationFormData. Но у нас есть еще и форма редактирования, потому лучше убрать "регистарцию" и оставить просто StudentFormData.

Теперь по другим вопросам.

По поводу PDO - можно использовать mysqli, если ты будешь использовать его правильно.

По поводу ООП - не надо делать классы "чтобы были". Если ты не знаешь, где использовать класс, не используй. Если ты плохо знаешь ООП и не решал задачу про "Вектор", то надо ее решить. Если решал, то можешь еще решить задачу "Гостиница" из этого поста >>1087072
https://github.com/kichiweb123/students #677 #1093270
>>1093242

То, что сейчас, нужно переделывать. Это не MVC ООП приложение. Вот с чего можно начать исправление (после того, как сделаешь то, что написано в конце поста):

1) Самое важное - нужно сделать нормальную структуру файлов. Вот у тебя в корневой папке накидана куча файлов, и непонятно вообще, для чего они все нужны. В одном какие-то куски HTML кода, в другом куски PHP кода - их надо разложить по папочкам с соответствующими названиями. Если у тебя проблема с придумыванием названия, объясни мне, зачем нужен тот или иной файл, и я помогу придумать название.

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

Очень важно, чтобы проект был понятный другому человеку. А для этого должна быть логика в том, как разложены файлы.

2) У тебя все свалено в корневую папку и к любому из скриптов можно обратиться напрямую (набрав его имя в адресной строке браузера). Вот например к скрипту https://github.com/kichiweb123/students/blob/master/check_and_update_profile.php . Но это ведь просто выдаст ошибку. Раз к нему нельзя обратиться, зачем делать такую возможность?

У меня в комментариях к задаче написано про публичную папку. Нужно выделить такую папку и в нее положить только те файлы, к которым можно обращаться напрямую. Все остальные файлы должны быть за пределами публичной папки. Если с этим какие-то сложности, напиши, в чем именно проблема.

3) У меня в уроке есть ссылка на урок про автозагрузку и PSR-4. Почему ты не используешь рекомендацию PSR-4 при выборе имен файлов, а придумываешь какие-то свои нестандартные имена?

4) Там есть такой код в файле https://github.com/kichiweb123/students/blob/master/index.php

> and ($_SERVER['QUERY_STRING'] == "id=registration"))


В такой ситуации нужно использовать массивы $_POST и $_GET. Более того, у меня в уроке ( https://github.com/codedokode/pasta/blob/master/soft/web-server.md ) недавно добавлено объяснение про массив $_GET. Прочитай про него.

5) В файле https://github.com/kichiweb123/students/blob/master/index.php

Тут смешана логика работы программы (вроде автозагрузки) и HTML-код. Этого не должно быть, у меня в комментариях написано про шаблоны и есть урок на эту тему. Весь HTML-код надо вынести в шаблоны.

6) Зачем там ob_start в index.php?

7) Тут https://github.com/kichiweb123/students/blob/master/edit_profile.php и тут https://github.com/kichiweb123/students/blob/master/registration.php повторяется одна и та же форма, нужно избавиться от дублирования кода. Это только раздувает объем проекта (и в нем труднее разбираться), и при каких-то правках их приходится делать в нескольких местах.

8) В файле edit_profile.php

> <label for="second_name">Фамилия: <?php echo $editProf[0]['second_name']; ?></label>



Здесь может быть уязвимость. Прочитай урок про XSS, который так же упомянут в комментариях и исправь.

9) В файле https://github.com/kichiweb123/students/blob/master/model/TableModel.class.php

> WHERE login = '{$login}'


> AND pass = '{$pass}'";


Прочитай на моем гитхабе урок про уязвимость "SQL инъекция" и исправь их.

10) В файле registration.php код как-то криво выровнен. Отформатируй его, например, на сайте htmlformatter.com

11) В файле registration.php ошибка:

> id="exampleRadios1"



id должен быть уникальным и не должен повторяться. Тебе надо проверить твой HTML-код (который генерирует твое приложение) на правильность. Для этого открой страницу своего приложения в браузере, сохрани ее (Ctrl + S) как HTML-файл без картинок, и загрузи этот файл в валидатор: https://html5.validator.nu/ . Он даст список ошибок, с ними надо разобраться.

Если что-то с валидатором непонятно, задавай вопросы.

12) Нужно давать более хорошие имена классам и функциям, чтобы в коде было проще разобраться.

Ну например, есть class TableModel. "модель таблицы". Трудно понять, какой таблицы? И что значит "модель таблицы"? Это ведь явно реализация паттерна TableDataGateway для таблицы студентов, значит правильно назвать класс StudentDataGateway.

Ну или возьмем класс "TableControllerRegistration". "регистрация контроллера таблицы"? Смысл понять трудно. Этот класс явно представляет собой информацию из формы регистрации, то есть информацию о студенте, введенную в форму. Значит, можно его назвать "данные формы регистрации студента" или StudentRegistrationFormData. Но у нас есть еще и форма редактирования, потому лучше убрать "регистарцию" и оставить просто StudentFormData.

Теперь по другим вопросам.

По поводу PDO - можно использовать mysqli, если ты будешь использовать его правильно.

По поводу ООП - не надо делать классы "чтобы были". Если ты не знаешь, где использовать класс, не используй. Если ты плохо знаешь ООП и не решал задачу про "Вектор", то надо ее решить. Если решал, то можешь еще решить задачу "Гостиница" из этого поста >>1087072
https://github.com/kichiweb123/students #678 #1093271
>>1093242

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

Модель не обязана вообще быть классами, это может быть например набор функций. А может и набор классов. В моем уроке по MVC в коде модель - это классы PostService и Post.

Вот давай подумаем, какие функции есть в нашем приложении? Что должно быть в модели? И есть ли это в твоей модели? Попробуй у себя в коде найти функции, которые это делают (в одно действие):

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

Далее, у нас есть такое понятие, как "авторизация", пусть и без паролей. После регистрации пользователь оказывается "залогиненным" под определенным "аккаунтом" и может редактировать инфорамцию о себе. Раз так, где-то должен быть код, отвечающий за функционал авторизации:

- узнать, залогинен ли текущий пользователь?
- если да, идентифицировать пользователя (кто он?)
- залогиниться под аккаунтом студента X
- разлогиниться

Далее, в задаче написано, что таблицу можно сортировать по разным колонкам, делать в ней поиск по слову и переходить по страницам. Значит, нам нужна функция, которая получает на вход параметры вывода таблицы (сортировка, слово для поиска, страница) и формирует URL. Мы можем этот URL вывести на странице как ссылку, например "отсортировать по имени" или "перейти на 2-ю страницу с сортировкой по имени".

У каждой из этих функций должен быть определенный набор аргументов, которые она получает, и тип результата, который она возвращает. Ну, проще всего с функцией подсчета числа студентов - ей передавать ничего не надо, а вернуть она должна целое число (я использую тайп хинты из PHP7):

function getStudentCount():int { ... }

Такую функцию я у тебя вижу (TableModel::numOfRows), но она названа неправильно. Имена функций и методв начинаются с глагола, сделатьЧтоТо. В данном случае надо назвать её получитьКоличествоСтудентов, getStudentCount.

Но если мы посмотрим на твою функцию добавления студента (TableModel::saveTable), мы видим, что она спроектирована неправильно. В нее ничего не передается. А откуда тогда она знает, какую информацию надо вставить в базу? Она откуда-то ее берет сама. Это неудобно и неправильно. Ну например, если ты захочешь сгенерировать 100 случайных студентов скриптом - ты не сможешь использовать эту функцию. А надо, чтобы мог. Суть MVC как раз в том, что функция модели не пытается сама откуда-то брать данные, а получает их явно.

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

Функция добавления студента (без проверки данных) должна выглядеть так:

Входные данные: информация о студенте
Выходные данные: ничего

Разумеется, в коде, тем более в модели, не должны использоваться глобальные переменные (global), не должно быть обращений к $_GET, $_SERVER, $_POST, не должно ничего выводиться с помощью echo. Все, что нужно функции, ты передаешь ей явно, все, что она хочет вернуть, она возвращает через return. Я ведь по моему писал это в уроке про MVC.

Чтобы привести твой код к MVC, надо для начала сделать модель, то есть взять функции модели, которые я перечислил выше, определить их входные параметры и результаты, сделать их в коде. А потом уже писать View и Controller. Чтобы убедиться, что ты все понял, давай ты напишешь заголовки функций, которые я перечислил выше (без тела, только название, аргументы и тип результата). А я проверю и скажу, что не так. Список функций вверху примерный, можно его изменить при желании.

Жду от тебя список функций.

Что касается классов - перед каждым классом надо написать комментарий, для чего он нужен, что представляет объект этого класса, как его использовать. Если ты не можешь сформулировать это, то, наверно, этот класс не нужен.

Если что-то из написанного непонятно, или есть какие-то вопросы, задавай.
https://github.com/kichiweb123/students #678 #1093271
>>1093242

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

Модель не обязана вообще быть классами, это может быть например набор функций. А может и набор классов. В моем уроке по MVC в коде модель - это классы PostService и Post.

Вот давай подумаем, какие функции есть в нашем приложении? Что должно быть в модели? И есть ли это в твоей модели? Попробуй у себя в коде найти функции, которые это делают (в одно действие):

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

Далее, у нас есть такое понятие, как "авторизация", пусть и без паролей. После регистрации пользователь оказывается "залогиненным" под определенным "аккаунтом" и может редактировать инфорамцию о себе. Раз так, где-то должен быть код, отвечающий за функционал авторизации:

- узнать, залогинен ли текущий пользователь?
- если да, идентифицировать пользователя (кто он?)
- залогиниться под аккаунтом студента X
- разлогиниться

Далее, в задаче написано, что таблицу можно сортировать по разным колонкам, делать в ней поиск по слову и переходить по страницам. Значит, нам нужна функция, которая получает на вход параметры вывода таблицы (сортировка, слово для поиска, страница) и формирует URL. Мы можем этот URL вывести на странице как ссылку, например "отсортировать по имени" или "перейти на 2-ю страницу с сортировкой по имени".

У каждой из этих функций должен быть определенный набор аргументов, которые она получает, и тип результата, который она возвращает. Ну, проще всего с функцией подсчета числа студентов - ей передавать ничего не надо, а вернуть она должна целое число (я использую тайп хинты из PHP7):

function getStudentCount():int { ... }

Такую функцию я у тебя вижу (TableModel::numOfRows), но она названа неправильно. Имена функций и методв начинаются с глагола, сделатьЧтоТо. В данном случае надо назвать её получитьКоличествоСтудентов, getStudentCount.

Но если мы посмотрим на твою функцию добавления студента (TableModel::saveTable), мы видим, что она спроектирована неправильно. В нее ничего не передается. А откуда тогда она знает, какую информацию надо вставить в базу? Она откуда-то ее берет сама. Это неудобно и неправильно. Ну например, если ты захочешь сгенерировать 100 случайных студентов скриптом - ты не сможешь использовать эту функцию. А надо, чтобы мог. Суть MVC как раз в том, что функция модели не пытается сама откуда-то брать данные, а получает их явно.

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

Функция добавления студента (без проверки данных) должна выглядеть так:

Входные данные: информация о студенте
Выходные данные: ничего

Разумеется, в коде, тем более в модели, не должны использоваться глобальные переменные (global), не должно быть обращений к $_GET, $_SERVER, $_POST, не должно ничего выводиться с помощью echo. Все, что нужно функции, ты передаешь ей явно, все, что она хочет вернуть, она возвращает через return. Я ведь по моему писал это в уроке про MVC.

Чтобы привести твой код к MVC, надо для начала сделать модель, то есть взять функции модели, которые я перечислил выше, определить их входные параметры и результаты, сделать их в коде. А потом уже писать View и Controller. Чтобы убедиться, что ты все понял, давай ты напишешь заголовки функций, которые я перечислил выше (без тела, только название, аргументы и тип результата). А я проверю и скажу, что не так. Список функций вверху примерный, можно его изменить при желании.

Жду от тебя список функций.

Что касается классов - перед каждым классом надо написать комментарий, для чего он нужен, что представляет объект этого класса, как его использовать. Если ты не можешь сформулировать это, то, наверно, этот класс не нужен.

Если что-то из написанного непонятно, или есть какие-то вопросы, задавай.
#679 #1093273
>>1093252

А что у тебя за задача, что ее нельзя решить другими способами? Ты пишешь, тебе надо записать число куда-то, а кто его будет читать? Нельзя его писать в файл, в БД, в redis, в именованный пайп (named pipe), в MQTT, еще куда-нибудь?

Судя по тому, что я прочел на SO - память все же будет освобождена, когда завершится процесс PHP. Или нет? В Апаче процессы PHP обслуживают много запросов и не умирают, потому она и не осовобождается. Но, как я понимаю, там всего один блок на поток, а блоков много, так как в Апаче много потоков с PHP.
#680 #1093274
>>1093242

Также, ты не добавил в проект SQL файл с дампом базы данных (как написано в комментариях). Без дампа, как развернуть твой проект? Как создать нужные таблицы в базе?
#681 #1093275
>>1092750
Бамп вопросу!
#682 #1093278
>>1093275

Будет очищена из памяти при следующей уборке мусора.

How does PHP cleanup memory?

If a variable falls out of scope and is not used in any other place of the currently executed code anymore, then it is garbage collected automatically. You can force this early by using unset() to end variables scope early.

If a variable is part of a cyclic reference, where A points to B and B back to A, then the variable can only be cleaned up by PHPs cycle garbage collector. It is triggered whenever 10000 possible cyclic objects or arrays are currently in memory and one of them falls out of scope. The collector is enabled by default in every request, but it can be toggled with the functions gc_enable() and gc_disable().

If you call the function gc_collect_cycles(), then collection of cyclic references is triggered explicitly even if you don't have 10000 of them in memory yet.

Подробнее
https://blog.ircmaxell.com/2014/12/what-about-garbage.html
#683 #1093279
>>1093278
Понятно. Значит объект существует по тем же законам, что и переменная.
Спасибо!
#684 #1093285
>>1092750

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

>>1093279

Переменная это просто хранилище для значений.

С переменными похожий механизм, переменные внутри функции удаляются при выходе из нее (если ссылки на них нигде не сохранены). Глобальные переменные не удаляются до завершения скрипта.
#685 #1093300
>>1093285
Тогда могу я предложить исправить на странице http://archive-ipq-co.narod.ru/l1/pasta.html

// Создадим три объекта (так как у нас будет 3 вопроса в тесте), и сохраним их в трех переменных:

Тут должно быть:

// Создадим три объекта (так как у нас будет 3 вопроса в тесте), и сохраним их адреса в трех переменных:
#686 #1093308
https://ideone.com/qImJaw

Написал скрипт, проверяющий наличие полученного значения в БД, но он почему-то не работает.
в #687 #1093364
#688 #1093391
>>1093271
класc TableDataGateway

функция contruct(без аргументов):
- устанавливает соединение с БД

функция getStudentCount(без аргументов):
- возвращает кол-во студентов

функция getStudentPage(общее кол-во студентов, сколько выводить на странице, сортировка(необязательный пар-р)):
- возвращает страницу со студентами, если есть сортировка, то возвращает отсортированное

функция searchPage(название запроса, сортировка(необязательный пар-р))
- возвращает страницу по запросу, если есть сортировка возвращает отсортированное

функция checkData(переменные с форм)
- возвращает массив ошибок, если они есть

функция addStudent(переменные с форм)
- добавляет студента в БД если всё хорошо

функция refreshStudent(переменные с форм)
- ничего не возвращает

функция checkAuth(без аргументов)
- возвращает 1 если есть куки с логином и пассом

функция getStudentInfo(без аргументов)
- возвращает информацию о студенте

функция enterSite(без аргументов)
- перебирает БД по логину и пассу и возвращает 1 если есть совпадение

функция setCookie(логин, пасс)
- ставит куки

функция delCookie(логин, пасс)
- удаляет куки
#688 #1093391
>>1093271
класc TableDataGateway

функция contruct(без аргументов):
- устанавливает соединение с БД

функция getStudentCount(без аргументов):
- возвращает кол-во студентов

функция getStudentPage(общее кол-во студентов, сколько выводить на странице, сортировка(необязательный пар-р)):
- возвращает страницу со студентами, если есть сортировка, то возвращает отсортированное

функция searchPage(название запроса, сортировка(необязательный пар-р))
- возвращает страницу по запросу, если есть сортировка возвращает отсортированное

функция checkData(переменные с форм)
- возвращает массив ошибок, если они есть

функция addStudent(переменные с форм)
- добавляет студента в БД если всё хорошо

функция refreshStudent(переменные с форм)
- ничего не возвращает

функция checkAuth(без аргументов)
- возвращает 1 если есть куки с логином и пассом

функция getStudentInfo(без аргументов)
- возвращает информацию о студенте

функция enterSite(без аргументов)
- перебирает БД по логину и пассу и возвращает 1 если есть совпадение

функция setCookie(логин, пасс)
- ставит куки

функция delCookie(логин, пасс)
- удаляет куки
#689 #1093407
Аноны, подскажите что почитать по регуляркам, никак не идет составление шаблона. Желательно на русском
#691 #1093433
>>1093428
Естественно
#692 #1093438
>>1093428
>>1093433
Надо больше примеров так сказать. Желательно с разбором
#693 #1093574
Добрый вечер, есть ли возможность в Yii2 получить линк, который генерируется в случае сабмита формы GET-методом? То-есть я знаю какой formName у модели которая используется при рендеринге формы, есть все данные, есть ли встроенная возможность получить линк или придется пердолиться?
#694 #1093576
>>1093574
Собственно получить линк надо без сабмита формы.
#695 #1093586
>>1093391

Тут есть одна проблема. Table Data Gateway - это класс, в котором хранятся методы для взаимодействия с БД. Функция "checkData(переменные с форм)" - в этот паттерн никак не вписывается.

Надо либо переименовать класс, либо перенести функцию в класс-валидатор (валидация - это и есть проверка данных).

Также, название Table Data Gateway намекает, что класс может работать с любой таблицей. Но этот класс заточен только под работу с таблицей студентов, и лучше это отразить в названии.

Что касается авторизации, то ее, конечно, тоже в Table Data Gateway быть не должно. Ее лучше поместить в отдельный класс, отвечающий за это.

В ООП есть принцип Single Responsibility - один класс отвечает только за одну какую-то зону ответственности. Взаимодействие с БД и авторизация - это очень разные вещи и их нужно разнести в отдельные классы. То, что это разные вещи, легко увидеть даже по тому, что они взаимодействуют с разными сущностями - TDG работает с базой данных, а авторизация с куками (а когда классу авторизации нужно получить что-то из базы, он не лезет в нее напрямую, а обращается к TDG).

Также, в твоем описании немного не хватает подробностей:

> checkData(переменные с форм)


Не написано, чем является (какой тип данных имеет) аргумент "переменные с форм". Напиши это.

> функция getStudentInfo(без аргументов)


> - возвращает информацию о студенте


Не указан тип возвращаемых данных

> функция getStudentPage(общее кол-во студентов, сколько выводить на странице, сортировка(необязательный пар-р)):


Ты указываешь, сколько надо взять студентов. Но непонятно, как получить студентов для второй, третьей и тд. страниц. Нужно еще добавить параметр offset (сколько студентов надо пропустить с начала списка).

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

- searchPage - "искать страницу" или "страница поиска". Имена функций начинаются с глагола, "сделайЭто", и лучше функцию назвать "найти студентов" - это ведь ее задача. В MVC модель не должна беспокоиться о том, как и где будут использоваться данные из нее, за это отвечает контроллер. Когда ты пишешь в модели название страницы, где будет использоваться функция, ты как бы нарушаешь это разделение ответственности.
- getStudentPage - "получить страницу студентов" - лучше просто "получить студентов"
- checkData - "проверить данные" - непонятно, какие данные. Лучше назвать "проверить данные студента", или, выкинув бесполезное слово "данные", "проверить студента". Вместо check можно использовать validate, которое значит "проверить на соответствие правилам" и используется как раз втаких случаях
- "checkAuth" - "проверить авторизацию" - такие функции, которые возвращают да/нет, принято называть со слов is/has/can/does, например: isAdmin, canDeletePage, hasPremuimStatus. Тут лучше использовать название "является ли авторизованным" - isAuthorised, isUserAuthorised
- "getStudentInfo" - "получить информацию о студенте" - "информация" - это бессмысленное слово, которое не говорит ничего нового и которое лучше избегать. Лучше написать "получить залогиненного студента" "getLoggedInStudent", "получить текущего пользователя" - getCurrentUser, "получить авторизованного пользователя" - getAuthorisedUser
- функция enterSite - "зайти на сайт" - это функция с результатом да/нет, нужно ее назвать как принято в таких случаях
- setCookie - "поставить куку". Неудачное название, лучше назвать ее "залогинить пользователя", "авторизовать пользователя". Не конкретизируя, как именно это делается. НАм (когда мы вызываем функцию) ведь важно, чтобы он в итоге был залогинен, а не как это будет сделано. То же самое с delCookie.

И еще. Чтобы представить значения да/нет, вместо цифр лучше использовать специальный булев тип: http://php.net/manual/ru/language.types.boolean.php . Операторы сравнения вроде ==, <, > как раз возвращают значения булева типа.

Что касается авторизации, у тебя там есть 2 функции для проверки залогиненности: проверить наличие кук и проверить содержимое кук по базе. Но нам ведь интересно только, залогинен пользователь или нет, нам не хочется самим где-то брать его куки и куда-то передавать. Не логичнее ли сделать одну функцию, которая сделает все необходимые проверки и окончательно отвечает на вопрос, залогинен он или нет?

Как видишь, в итоге модель предоставляет что-то вроде набора API (набора класссов и функций, которые можно вызвать, чтобы выполнить какое-то действие с приложением). Важно, чтобы оно было удачно спроектировано, удачно названы функции - код тогда будет читать намного проще.

И, наконец, еще один момент. У тебя некоторые функции принимают или возвращают данные о студенте? В каком они могут быть виде? Могут быть в виде массива, а могут быть в виде объекта (который хранит информацию об одном студенте). Подумай и напиши, какие плюсы и минусы есть у каждого из этих подходов и на основании этого выбери, что лучше подойдет для твоей модели.

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

1) скрипт, который вставляет в БД пользователя с прописанными в скрипте данными
2) скрипт, который при заходе из браузера логинит под определенным аккаунтом
3) скрипт, который при заходе из браузера пишет, под каким аккаунтом залогинен пользователь

После этого скинь ссылку на код, но не жди меня, а двигайся дальше. Можно переходить к написанию контроллеров и вью.
#695 #1093586
>>1093391

Тут есть одна проблема. Table Data Gateway - это класс, в котором хранятся методы для взаимодействия с БД. Функция "checkData(переменные с форм)" - в этот паттерн никак не вписывается.

Надо либо переименовать класс, либо перенести функцию в класс-валидатор (валидация - это и есть проверка данных).

Также, название Table Data Gateway намекает, что класс может работать с любой таблицей. Но этот класс заточен только под работу с таблицей студентов, и лучше это отразить в названии.

Что касается авторизации, то ее, конечно, тоже в Table Data Gateway быть не должно. Ее лучше поместить в отдельный класс, отвечающий за это.

В ООП есть принцип Single Responsibility - один класс отвечает только за одну какую-то зону ответственности. Взаимодействие с БД и авторизация - это очень разные вещи и их нужно разнести в отдельные классы. То, что это разные вещи, легко увидеть даже по тому, что они взаимодействуют с разными сущностями - TDG работает с базой данных, а авторизация с куками (а когда классу авторизации нужно получить что-то из базы, он не лезет в нее напрямую, а обращается к TDG).

Также, в твоем описании немного не хватает подробностей:

> checkData(переменные с форм)


Не написано, чем является (какой тип данных имеет) аргумент "переменные с форм". Напиши это.

> функция getStudentInfo(без аргументов)


> - возвращает информацию о студенте


Не указан тип возвращаемых данных

> функция getStudentPage(общее кол-во студентов, сколько выводить на странице, сортировка(необязательный пар-р)):


Ты указываешь, сколько надо взять студентов. Но непонятно, как получить студентов для второй, третьей и тд. страниц. Нужно еще добавить параметр offset (сколько студентов надо пропустить с начала списка).

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

- searchPage - "искать страницу" или "страница поиска". Имена функций начинаются с глагола, "сделайЭто", и лучше функцию назвать "найти студентов" - это ведь ее задача. В MVC модель не должна беспокоиться о том, как и где будут использоваться данные из нее, за это отвечает контроллер. Когда ты пишешь в модели название страницы, где будет использоваться функция, ты как бы нарушаешь это разделение ответственности.
- getStudentPage - "получить страницу студентов" - лучше просто "получить студентов"
- checkData - "проверить данные" - непонятно, какие данные. Лучше назвать "проверить данные студента", или, выкинув бесполезное слово "данные", "проверить студента". Вместо check можно использовать validate, которое значит "проверить на соответствие правилам" и используется как раз втаких случаях
- "checkAuth" - "проверить авторизацию" - такие функции, которые возвращают да/нет, принято называть со слов is/has/can/does, например: isAdmin, canDeletePage, hasPremuimStatus. Тут лучше использовать название "является ли авторизованным" - isAuthorised, isUserAuthorised
- "getStudentInfo" - "получить информацию о студенте" - "информация" - это бессмысленное слово, которое не говорит ничего нового и которое лучше избегать. Лучше написать "получить залогиненного студента" "getLoggedInStudent", "получить текущего пользователя" - getCurrentUser, "получить авторизованного пользователя" - getAuthorisedUser
- функция enterSite - "зайти на сайт" - это функция с результатом да/нет, нужно ее назвать как принято в таких случаях
- setCookie - "поставить куку". Неудачное название, лучше назвать ее "залогинить пользователя", "авторизовать пользователя". Не конкретизируя, как именно это делается. НАм (когда мы вызываем функцию) ведь важно, чтобы он в итоге был залогинен, а не как это будет сделано. То же самое с delCookie.

И еще. Чтобы представить значения да/нет, вместо цифр лучше использовать специальный булев тип: http://php.net/manual/ru/language.types.boolean.php . Операторы сравнения вроде ==, <, > как раз возвращают значения булева типа.

Что касается авторизации, у тебя там есть 2 функции для проверки залогиненности: проверить наличие кук и проверить содержимое кук по базе. Но нам ведь интересно только, залогинен пользователь или нет, нам не хочется самим где-то брать его куки и куда-то передавать. Не логичнее ли сделать одну функцию, которая сделает все необходимые проверки и окончательно отвечает на вопрос, залогинен он или нет?

Как видишь, в итоге модель предоставляет что-то вроде набора API (набора класссов и функций, которые можно вызвать, чтобы выполнить какое-то действие с приложением). Важно, чтобы оно было удачно спроектировано, удачно названы функции - код тогда будет читать намного проще.

И, наконец, еще один момент. У тебя некоторые функции принимают или возвращают данные о студенте? В каком они могут быть виде? Могут быть в виде массива, а могут быть в виде объекта (который хранит информацию об одном студенте). Подумай и напиши, какие плюсы и минусы есть у каждого из этих подходов и на основании этого выбери, что лучше подойдет для твоей модели.

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

1) скрипт, который вставляет в БД пользователя с прописанными в скрипте данными
2) скрипт, который при заходе из браузера логинит под определенным аккаунтом
3) скрипт, который при заходе из браузера пишет, под каким аккаунтом залогинен пользователь

После этого скинь ссылку на код, но не жди меня, а двигайся дальше. Можно переходить к написанию контроллеров и вью.
#696 #1093589
>>1093407

Если не боишься, могу дать подробный мануал: http://php.net/manual/ru/pcre.pattern.php

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

. (точка)
Квантификаторы ? + *{N} {N,M}
Круглые скобки
Вертикальная черта |
Квадратные скобки [abc], [a-z], [^a-z]
Условия \b, ^ и $
\s, \w\, \d
#697 #1093592
>>1093391

>функция searchPage(название запроса, сортировка(необязательный пар-р))


>- возвращает страницу по запросу, если есть сортировка возвращает отсортированное


getSearchPage конечно же

>функция refreshStudent(переменные с форм)


>- ничего не возвращает


resreshStudent(логин, пасс, переменные с форм), возвращает 1 если успешно

>функция enterSite(без аргументов)


>- перебирает БД по логину и пассу и возвращает 1 если есть совпадение


enterSite(логин, пасс)

>функция getStudentInfo(без аргументов)


>- возвращает информацию о студенте


getStudentInfo(логин, пасс)
#698 #1093593
>>1093308

У тебя тут SQL инъекция, надо исправить: https://github.com/codedokode/pasta/blob/master/security/sql-injection.md

Также, при ошибке ты пишешь No, но не выводишь подробности ошибки. Согласись, трудно понять тогда, в чем ее причина. Нужно сделать вывод подробностей ошибки, как это сделано в примерах по mysqli в мануале PHP. http://php.net/manual/ru/mysqli.examples-basic.php (я бы советовал изучить все примеры кода там, а также почитать мануал по использованным функциям, чтобы знать их особенности).
#699 #1093595
>>1093592

А, поздно, я уже написал выше, почему page писать в названии не надо.
#700 #1093597
>>1093592

> resreshStudent(логин, пасс, переменные с форм), возвращает 1 если успешно


А в какой ситуации и какая может произойти ошибка?
#701 #1093599
>>1093597
По идее ни в какой) Или не знаю, тогда не нужно это возвращение
#702 #1093611
>>1093599

Ошибка может произойти, техническая. Например, когда ты попытаешься отправить запрос в БД, может произойти многое:

- в сервере БД произойдет ошибка, и соединение с ним разорвется до получения ответа
- сервер БД вернет сообщение, что SQL запрос написан неверно

Но это такие ошибки, с которыми пользователь сделать ничего не может. Он же не может зайти на сервер и исправить код SQL запроса. Потому о них сообщать не надо, а надо выкидывать исключение, как описано в моем уроке https://github.com/codedokode/pasta/blob/master/php/exceptions.md

И вот, кстати, заодно можешь прочесть урок про правила хорошего кода: https://github.com/codedokode/pasta/blob/master/good-code.md
#703 #1093619
>>1092884
Первое издревле фиксится страницей-редиректом.
Второе - короткой жизнью хэша и/или привязкой к IP.
Поисковик логиниться не будет.
Алфавит по кругу #704 #1093637
https://ideone.com/dTm9dn
Оп подскажи как фиксить
#705 #1093642
>>1082507 (OP)
Решаю задачу с циклами. https://ideone.com/Rci3al
Поясните пожалуйста где я обосрался, уже битый час сижу и не могу понять.
#706 #1093681
>>1093637

В функцию cos, sin надо передавать угол в радианах, а не градусах. Также, в PHP есть функция перевода из градусов в радианы.
#707 #1093715
На Хабре интересная статья про особенности хранения сообщений вконтакте: https://m.habrahabr.ru/company/vkontakte/blog/342570/
313 Кб, 419x480
#708 #1093749
>>1093715

>vk


>производительность

#709 #1093777
Аноны, можно ли переопределить метод из класса, который не является наследником?
#710 #1093791
>>1093777
Нет.

Но в случае трейтов, можно!
#711 #1093808
https://github.com/kichiweb123/students

Оп проверяй MVC, но я еще не доделал все замечания из предыдущих постов
#712 #1093811
>>1093777
Делаю задачу про антикризисные меры Вектора.
Рационально ли класс, который будет рассчитывать антикризисные меры, сделать наследником класса, выводящего таблицу?

Код: https://3v4l.org/QfVAk
#713 #1093823
>>1093808

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

Также, не забудь про вопрос:

> И, наконец, еще один момент. У тебя некоторые функции принимают или возвращают данные о студенте? В каком они могут быть виде? Могут быть в виде массива, а могут быть в виде объекта (который хранит информацию об одном студенте). Подумай и напиши, какие плюсы и минусы есть у каждого из этих подходов и на основании этого выбери, что лучше подойдет для твоей модели.



И про тестовые скрипты, демонстрирующие, что модель работает.

И дамп SQL не забудь.
#714 #1093825
>>1093808

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

Публичная папка задается так:

- для встроенного в PHP сервера - с помощью параметра -t
- для Апача - с помощью директивы DocumentRoot

Про настройку Апача написано в комментариях к задаче. Если Апач настроить сложно, можно использовать пока встроенный в PHP сервер.
#715 #1093875
>>1082507 (OP)
https://ideone.com/WuPHQv
Чекните задачу на цикл у меня, пожалуйста, голову сломал, но всё-таки сделал. Мне кажется, что там можно было это всё проще сделать.
15 Кб, 626x342
#716 #1093924
Оп, проверь пожалуйста домашнее задание по ООП.
https://ideone.com/4T435y
#717 #1094061
>>1093270

>Самое важное - нужно сделать нормальную структуру файлов.


По идее сделал

>У меня в комментариях к задаче написано про публичную папку.


Здесь у меня не получилось, нужна помощь.
Я пишу

<VirtualHost *:80>
ServerName example.ru
DocumentRoot z:/home/example.ru/www/index
</VirtualHost>
И ни один сайт не открывается в таком случае, пытался гуглить не получилось выяснить в чем проблема

>У меня в уроке есть ссылка на урок про автозагрузку и PSR-4. Почему ты не используешь рекомендацию PSR-4 при выборе имен файлов, а придумываешь какие-то свои нестандартные имена?


Автозагрузку я сделал через spl, а с именами разобрались вроде

>> and ($_SERVER['QUERY_STRING'] == "id=registration"))


В такой ситуации нужно использовать массивы $_POST и $_GET. Более того, у меня в уроке ( https://github.com/codedokode/pasta/blob/master/soft/web-server.md ) недавно добавлено объяснение про массив $_GET. Прочитай про него.
Тут я не понял как мне действовать, читал про гет, какое у словия я должен задать?

>Тут смешана логика работы программы


Здесь вроде пофиксил всё

>Зачем там ob_start в index.php


кукисы ставятся ниже по коду, а должны быть наверху

>Здесь может быть уязвимость. Прочитай урок про XSS, который так же упомянут в комментариях и исправь.


Пофиксил вроде как, а вот объясни один момент
функция htmlspecialchars у меня ничего не меняет, а должна на спецсимволы заменять, я ввожу <>, они не меняются, и в таблицу тоже самое можно забить, это нормально?

>Прочитай на моем гитхабе урок про уязвимость "SQL инъекция" и исправь их.


Здесь сделал вроде

>id должен быть уникальным и не должен повторяться.


Пофиксил

>1) скрипт, который вставляет в БД пользователя с прописанными в скрипте данными


2) скрипт, который при заходе из браузера логинит под определенным аккаунтом
3) скрипт, который при заходе из браузера пишет, под каким аккаунтом залогинен пользователь

1)saveStudent.php
2)немного не понял, но у меня есть метод isLogin, который проверяет правильноcть логина и пароля и потом ставит куки если правило в login.phtml
3)После логина пишет под каким именем залогинился

>> И, наконец, еще один момент. У тебя некоторые функции принимают или возвращают данные о студенте? В каком они могут быть виде? Могут быть в виде массива, а могут быть в виде объекта (который хранит информацию об одном студенте). Подумай и напиши, какие плюсы и минусы есть у каждого из этих подходов и на основании этого выбери, что лучше подойдет для твоей модели.



Лучше массив потому что возвращает сразу всю выборку, а не один как объект
#717 #1094061
>>1093270

>Самое важное - нужно сделать нормальную структуру файлов.


По идее сделал

>У меня в комментариях к задаче написано про публичную папку.


Здесь у меня не получилось, нужна помощь.
Я пишу

<VirtualHost *:80>
ServerName example.ru
DocumentRoot z:/home/example.ru/www/index
</VirtualHost>
И ни один сайт не открывается в таком случае, пытался гуглить не получилось выяснить в чем проблема

>У меня в уроке есть ссылка на урок про автозагрузку и PSR-4. Почему ты не используешь рекомендацию PSR-4 при выборе имен файлов, а придумываешь какие-то свои нестандартные имена?


Автозагрузку я сделал через spl, а с именами разобрались вроде

>> and ($_SERVER['QUERY_STRING'] == "id=registration"))


В такой ситуации нужно использовать массивы $_POST и $_GET. Более того, у меня в уроке ( https://github.com/codedokode/pasta/blob/master/soft/web-server.md ) недавно добавлено объяснение про массив $_GET. Прочитай про него.
Тут я не понял как мне действовать, читал про гет, какое у словия я должен задать?

>Тут смешана логика работы программы


Здесь вроде пофиксил всё

>Зачем там ob_start в index.php


кукисы ставятся ниже по коду, а должны быть наверху

>Здесь может быть уязвимость. Прочитай урок про XSS, который так же упомянут в комментариях и исправь.


Пофиксил вроде как, а вот объясни один момент
функция htmlspecialchars у меня ничего не меняет, а должна на спецсимволы заменять, я ввожу <>, они не меняются, и в таблицу тоже самое можно забить, это нормально?

>Прочитай на моем гитхабе урок про уязвимость "SQL инъекция" и исправь их.


Здесь сделал вроде

>id должен быть уникальным и не должен повторяться.


Пофиксил

>1) скрипт, который вставляет в БД пользователя с прописанными в скрипте данными


2) скрипт, который при заходе из браузера логинит под определенным аккаунтом
3) скрипт, который при заходе из браузера пишет, под каким аккаунтом залогинен пользователь

1)saveStudent.php
2)немного не понял, но у меня есть метод isLogin, который проверяет правильноcть логина и пароля и потом ставит куки если правило в login.phtml
3)После логина пишет под каким именем залогинился

>> И, наконец, еще один момент. У тебя некоторые функции принимают или возвращают данные о студенте? В каком они могут быть виде? Могут быть в виде массива, а могут быть в виде объекта (который хранит информацию об одном студенте). Подумай и напиши, какие плюсы и минусы есть у каждого из этих подходов и на основании этого выбери, что лучше подойдет для твоей модели.



Лучше массив потому что возвращает сразу всю выборку, а не один как объект
#718 #1094210
>>1083163

Ошибки:

> $creditBalanc % $monthlyPayment;


Это выражение вычисляется, но результат никуда не сохраняется. Надо писать $x = $y % $z;

Что касается задачи, решать ее можно так:

В цикле:

- прибавляем проценты и комиссию к остатку долга (!не вычитаем ничего пока!)
- если остаток маленький, выплачиваем сколько осталось и уходим
- иначе платим 5000

«Платим» здесь значит уменьшаем долг и увеличиваем общую сумму выплаченного.

Также, советую нормально выравнивать код, тогда его будет легче читать тебе же самому.

>>1083214

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

>>1083537

Если это Visual Studio C++ Runtime, то надо на сайте майкрософта найти библиотеку точно такой же версии (не Visual Studio, а только Runtime Library) и установить.
#718 #1094210
>>1083163

Ошибки:

> $creditBalanc % $monthlyPayment;


Это выражение вычисляется, но результат никуда не сохраняется. Надо писать $x = $y % $z;

Что касается задачи, решать ее можно так:

В цикле:

- прибавляем проценты и комиссию к остатку долга (!не вычитаем ничего пока!)
- если остаток маленький, выплачиваем сколько осталось и уходим
- иначе платим 5000

«Платим» здесь значит уменьшаем долг и увеличиваем общую сумму выплаченного.

Также, советую нормально выравнивать код, тогда его будет легче читать тебе же самому.

>>1083214

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

>>1083537

Если это Visual Studio C++ Runtime, то надо на сайте майкрософта найти библиотеку точно такой же версии (не Visual Studio, а только Runtime Library) и установить.
#719 #1094211
>>1083576

В общем-то неплохо, но \W пропускает вообще любые символы, например, & % $ ? и так далее. Лучше явно указать, какие символы могут быть между цифрами.

>>1084794

HAVING AVG(...) < (SELECT ...) + 1

или

HAVING AVG(...) < (SELECT AVG(..) + 1 .. )

>>1094061

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


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

Если что , документация по виртуальным хостам на англ. тут: https://httpd.apache.org/docs/2.4/vhosts/name-based.html

Также, прописал ли ты имя домена в hosts? Каким образом твой комепьютер должен определить, что домену example.com соответствует твой компьютер? Если нет, то прочти про hosts: https://ru.wikipedia.org/wiki/Hosts

Также, если тебе трудно настроить Апач, ты можешь использовать встроенный в PHP сервер: https://github.com/codedokode/pasta/blob/master/soft/web-server.md

Без текста ошибки сказать трудно. Если у тебя не чистый Апач, а какая-то сборка - то тебе надо еще и разобраться, как она сделана и настроена и какие настройки в конфиге Апача в ней добавлены.

> Автозагрузку я сделал через spl, а с именами разобрались вроде


Нет, вроде бы не разобрались. Твои имена файлов не соответствуют PSR-4 и я хотел узнать, почему? Ты там добавляешь слово class. Лучше наверно следовать общепринятой рекомендации, если нет каких-то веских причин.

> Тут я не понял как мне действовать, читал про гет, какое условия я должен задать?


Такое, которое будет равносильно условию $_SERVER['QUERY_STRING'] == "id=registration"). Ты можешь сделать var_dump($_GET) и увидеть, что в этом массиве.

>>Зачем там ob_start в index.php


> кукисы ставятся ниже по коду, а должны быть наверху


Куки надо ставить до вывода текста страницы. Если это условие соблюдается, то ob_start не нужен.

> функция htmlspecialchars у меня ничего не меняет, а должна на спецсимволы заменять, я ввожу <>, они не меняются, и в таблицу тоже самое можно забить, это нормально?


Почему ты думаешь, что не меняет? Попробуй в командной строке (если не знаком с ней, прочти урок в ОП посте) набрать команду c:\php\php.exe -r 'var_dump(htmlspecialchars("Test <> &", ENT_QUOTES));' и посмотри, что получится. Если ты смотришь результат в браузере, то открой исходный код (Ctrl + U в фаерфоксе и хроме, через меню в других браузерах). Все заменяется, просто ты этого не видишь. Ты видишь не результат работы функции, а результат обработки HTML-кода браузером, который не соответствует полностью исходному HTML-коду.

То есть твой скрипт выдает & lt;, а браузер обрабатывает это и выводит символ <.

У тебя конечно очень не хватает каких-то базовых знаний. Реши-ка задачу на экранирование отсюда, чтобы лучше разобраться с этими функциями: https://github.com/codedokode/pasta/blob/master/soft/web-server.md

>>Прочитай на моем гитхабе урок про уязвимость "SQL инъекция" и исправь их.


> Здесь сделал вроде


Нет, не везде исправлена проблема. Вот например, места, где переменные вставляются напрямую в SQL-запрос без всякой обработки:

> LIMIT $start,$perPage


> WHERE name LIKE '%$search%'



Надо исправить проблему везде.

Заодно поговорим про обработку ошибок. Вот ты используешь функцию $mysqli->bind_param, а внимательно ли ты прочел мануал по ней? Открываем, и читаем:

http://php.net/manual/ru/mysqli-stmt.bind-param.php

> Возвращает TRUE в случае успешного завершения или FALSE в случае возникновения ошибки.



То есть может произойти какая-то ошибка. Это надо проверить, например, с помощью if:

$result = $mysqli->bind_param(...);
if (!$result) {
// сообщить об ошибке
}

Нужно для всех функций mysqli, которые могут вернуть ошибку, проверять результат.

Также, обрабатываешь ошибку ты тоже неправильно. Ты ее выводишь на экран (зачем пользователю это видеть?), и продолжаешь выполнять скрипт. Но какой смысл продолжать выполнять скрипт, если одно из действий выполнить не удалось? Такой скрипт не выдаст правильную информацию. Нужно останавливать выполнение скрипта при ошибке. Как это лучше сделать, описано в моем уроке про исключения: https://github.com/codedokode/pasta/blob/master/php/exceptions.md

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

> 1)saveStudent.php


Ок, хорошо.

> 2) немного не понял, но у меня есть метод isLogin, который проверяет правильноcть логина и пароля и потом ставит куки если правило в login.phtml


Нужно, чтобы когда ты запускаешь скрипт из браузера (заходишь на URL вида http://localhost/login.php) тебя бы залогинило под определенным пользователем, под каким именно - можно жестко заложить в скрипте. Ну например, под пользователем с идентификатором 1. Если ты бы залогинен под другим аккаунтом - он должен из него выйти и залогиниться под заданным в скрипте.

> 3) После логина пишет под каким именем залогинился


Нужен отдельный скрипт, который просто при открытии пишет например, email аккаунта, под которым ты залогинен. Если не залогинен - то выводит соответствующее сообщение. И ничего больше, просто выводит информацию, под каким аккаунтом ты сейчас залогинен. С помощью этого скрипта можно будет проверить работу второго скрипта (который залогинивает).

> Лучше массив потому что возвращает сразу всю выборку, а не один как объект



Мне кажется, ты не понял вопрос. Вот у тебя есть метод:

> function addStudent($login, $password, $name, $second_name, $grup, $email, $score, $age, $local, $sex)


Тут слишком много аргументов. У функции не должно быть так много аргументов. Легко ошибиться, и перепутать их местами. Ну и вообще, неудобно везде передавать так много переменных. Нужно представить информацию о пользователе в виде одной переменной - массива или объекта. И я просил сравнить плюсы и минусы этих 2 вариантов.

Ты наверно, говоря про "всю выборку", имел в виду функцию поиска студентов в базе. В ней тоже есть выбор: можно вернуть результат как массив массивов (где каждый массив = 1 студент), а можно - как массив объектов, где каждый объект предсталвяет одного студента.

Если ты плохо понимаешь объекты, в ОП посте есть учебник, в нем глава про ООП и задача про ООО "Вектор", которые помогут разобраться в них. Если понимаешь - то напиши плюсы и минусы представления информации об одном пользователе в виде объекта либо массива.

Я вижу, ты загрузил дамп БД. В нем тоже надо сделать исправления:

> `email` text,


> `score` text


Ты сделал все поля одного типа. Это не годится. Во-первых, так труднее понять структуру твоей базы, непонятно, данные какого типа где хранятся. Во-вторых, твоя база позволяет в поле score записать не число, а например, строку. Если так делать в реальном приложении, то со временем база начнет превращаться в свалку с неправильными данными.

Нужно изучить, какие типы полей существуют в mysql. И выбрать для каждого поля правильный вариант. Гугл: https://www.google.ru/search?q=mysql+типы+полей&newwindow=1&dcr=0&gbv=1&sei=BAIRWvGTB4jwatyIvogN

Далее, для каждого поля надо поставить, может ли в нем быть NULL или нет. Как ты это будешь решать?

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

Также, ты выбрал кодировку utf8. Почему именно эта, а не полноценная utf-8? В комментариях к задаче это упомянуто.

Также, если ты хочешь хранить пароли в базе, надо прочесть урок про хранение паролей: https://github.com/codedokode/pasta/blob/master/security/password-hashing.md

Я еще мельком посмотрел шаблоны, там код формы регистрации повторяется в 2 файлах, нужно наверно убрать повторы. Какой смысл 2 раза писать одно и то же?

Задавай вопросы, если что-то непонятно.
#719 #1094211
>>1083576

В общем-то неплохо, но \W пропускает вообще любые символы, например, & % $ ? и так далее. Лучше явно указать, какие символы могут быть между цифрами.

>>1084794

HAVING AVG(...) < (SELECT ...) + 1

или

HAVING AVG(...) < (SELECT AVG(..) + 1 .. )

>>1094061

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


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

Если что , документация по виртуальным хостам на англ. тут: https://httpd.apache.org/docs/2.4/vhosts/name-based.html

Также, прописал ли ты имя домена в hosts? Каким образом твой комепьютер должен определить, что домену example.com соответствует твой компьютер? Если нет, то прочти про hosts: https://ru.wikipedia.org/wiki/Hosts

Также, если тебе трудно настроить Апач, ты можешь использовать встроенный в PHP сервер: https://github.com/codedokode/pasta/blob/master/soft/web-server.md

Без текста ошибки сказать трудно. Если у тебя не чистый Апач, а какая-то сборка - то тебе надо еще и разобраться, как она сделана и настроена и какие настройки в конфиге Апача в ней добавлены.

> Автозагрузку я сделал через spl, а с именами разобрались вроде


Нет, вроде бы не разобрались. Твои имена файлов не соответствуют PSR-4 и я хотел узнать, почему? Ты там добавляешь слово class. Лучше наверно следовать общепринятой рекомендации, если нет каких-то веских причин.

> Тут я не понял как мне действовать, читал про гет, какое условия я должен задать?


Такое, которое будет равносильно условию $_SERVER['QUERY_STRING'] == "id=registration"). Ты можешь сделать var_dump($_GET) и увидеть, что в этом массиве.

>>Зачем там ob_start в index.php


> кукисы ставятся ниже по коду, а должны быть наверху


Куки надо ставить до вывода текста страницы. Если это условие соблюдается, то ob_start не нужен.

> функция htmlspecialchars у меня ничего не меняет, а должна на спецсимволы заменять, я ввожу <>, они не меняются, и в таблицу тоже самое можно забить, это нормально?


Почему ты думаешь, что не меняет? Попробуй в командной строке (если не знаком с ней, прочти урок в ОП посте) набрать команду c:\php\php.exe -r 'var_dump(htmlspecialchars("Test <> &", ENT_QUOTES));' и посмотри, что получится. Если ты смотришь результат в браузере, то открой исходный код (Ctrl + U в фаерфоксе и хроме, через меню в других браузерах). Все заменяется, просто ты этого не видишь. Ты видишь не результат работы функции, а результат обработки HTML-кода браузером, который не соответствует полностью исходному HTML-коду.

То есть твой скрипт выдает & lt;, а браузер обрабатывает это и выводит символ <.

У тебя конечно очень не хватает каких-то базовых знаний. Реши-ка задачу на экранирование отсюда, чтобы лучше разобраться с этими функциями: https://github.com/codedokode/pasta/blob/master/soft/web-server.md

>>Прочитай на моем гитхабе урок про уязвимость "SQL инъекция" и исправь их.


> Здесь сделал вроде


Нет, не везде исправлена проблема. Вот например, места, где переменные вставляются напрямую в SQL-запрос без всякой обработки:

> LIMIT $start,$perPage


> WHERE name LIKE '%$search%'



Надо исправить проблему везде.

Заодно поговорим про обработку ошибок. Вот ты используешь функцию $mysqli->bind_param, а внимательно ли ты прочел мануал по ней? Открываем, и читаем:

http://php.net/manual/ru/mysqli-stmt.bind-param.php

> Возвращает TRUE в случае успешного завершения или FALSE в случае возникновения ошибки.



То есть может произойти какая-то ошибка. Это надо проверить, например, с помощью if:

$result = $mysqli->bind_param(...);
if (!$result) {
// сообщить об ошибке
}

Нужно для всех функций mysqli, которые могут вернуть ошибку, проверять результат.

Также, обрабатываешь ошибку ты тоже неправильно. Ты ее выводишь на экран (зачем пользователю это видеть?), и продолжаешь выполнять скрипт. Но какой смысл продолжать выполнять скрипт, если одно из действий выполнить не удалось? Такой скрипт не выдаст правильную информацию. Нужно останавливать выполнение скрипта при ошибке. Как это лучше сделать, описано в моем уроке про исключения: https://github.com/codedokode/pasta/blob/master/php/exceptions.md

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

> 1)saveStudent.php


Ок, хорошо.

> 2) немного не понял, но у меня есть метод isLogin, который проверяет правильноcть логина и пароля и потом ставит куки если правило в login.phtml


Нужно, чтобы когда ты запускаешь скрипт из браузера (заходишь на URL вида http://localhost/login.php) тебя бы залогинило под определенным пользователем, под каким именно - можно жестко заложить в скрипте. Ну например, под пользователем с идентификатором 1. Если ты бы залогинен под другим аккаунтом - он должен из него выйти и залогиниться под заданным в скрипте.

> 3) После логина пишет под каким именем залогинился


Нужен отдельный скрипт, который просто при открытии пишет например, email аккаунта, под которым ты залогинен. Если не залогинен - то выводит соответствующее сообщение. И ничего больше, просто выводит информацию, под каким аккаунтом ты сейчас залогинен. С помощью этого скрипта можно будет проверить работу второго скрипта (который залогинивает).

> Лучше массив потому что возвращает сразу всю выборку, а не один как объект



Мне кажется, ты не понял вопрос. Вот у тебя есть метод:

> function addStudent($login, $password, $name, $second_name, $grup, $email, $score, $age, $local, $sex)


Тут слишком много аргументов. У функции не должно быть так много аргументов. Легко ошибиться, и перепутать их местами. Ну и вообще, неудобно везде передавать так много переменных. Нужно представить информацию о пользователе в виде одной переменной - массива или объекта. И я просил сравнить плюсы и минусы этих 2 вариантов.

Ты наверно, говоря про "всю выборку", имел в виду функцию поиска студентов в базе. В ней тоже есть выбор: можно вернуть результат как массив массивов (где каждый массив = 1 студент), а можно - как массив объектов, где каждый объект предсталвяет одного студента.

Если ты плохо понимаешь объекты, в ОП посте есть учебник, в нем глава про ООП и задача про ООО "Вектор", которые помогут разобраться в них. Если понимаешь - то напиши плюсы и минусы представления информации об одном пользователе в виде объекта либо массива.

Я вижу, ты загрузил дамп БД. В нем тоже надо сделать исправления:

> `email` text,


> `score` text


Ты сделал все поля одного типа. Это не годится. Во-первых, так труднее понять структуру твоей базы, непонятно, данные какого типа где хранятся. Во-вторых, твоя база позволяет в поле score записать не число, а например, строку. Если так делать в реальном приложении, то со временем база начнет превращаться в свалку с неправильными данными.

Нужно изучить, какие типы полей существуют в mysql. И выбрать для каждого поля правильный вариант. Гугл: https://www.google.ru/search?q=mysql+типы+полей&newwindow=1&dcr=0&gbv=1&sei=BAIRWvGTB4jwatyIvogN

Далее, для каждого поля надо поставить, может ли в нем быть NULL или нет. Как ты это будешь решать?

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

Также, ты выбрал кодировку utf8. Почему именно эта, а не полноценная utf-8? В комментариях к задаче это упомянуто.

Также, если ты хочешь хранить пароли в базе, надо прочесть урок про хранение паролей: https://github.com/codedokode/pasta/blob/master/security/password-hashing.md

Я еще мельком посмотрел шаблоны, там код формы регистрации повторяется в 2 файлах, нужно наверно убрать повторы. Какой смысл 2 раза писать одно и то же?

Задавай вопросы, если что-то непонятно.
#720 #1094212
>>1093924

> ("/([а-яё]+)\\s+([а-яё])


Тут нужно использовать ^

> //получаем полное имя


> $name = $this->name;


Переменная никак не используется.

> foreach( $this->hours as $object->$hour ){


Что такое $object? Эта переменная нигде не определена. Справа в foreach нужно указывать просто переменную, мануал http://php.net/manual/ru/control-structures.foreach.php

> for (;$stringLen < $length; $stringLen++){


> $space .= " ";


Используй str_repeat

В общем, кроме функции getOvertimeHours, сделано неплохо. Вместо <pre> можно еще ставить тип ответа text/plain, как описано тут https://github.com/codedokode/pasta/blob/master/soft/web-server.md

>>1093875

К сожалению, код переусложнен и его трудно понять. Выражение "$creditBalance$percent+$servicePayment" повторяется аж 3 раза. Нужно убрать повторы.

Более того, с математической точки зрения там формула бессмысленна:

> $creditBalance$percent+$servicePayment - $monthlyPayment + $monthlyPayment;


Какой смысл прибавлять значение и тут же его отнимать?

Решается эта задача примерно так:

- прибавляем проценты и комиссию к остатку долга (!не вычитаем ничего пока!)
- если остаток маленький, выплачиваем сколько осталось и уходим
- иначе платим 5000

«Платим» здесь значит уменьшаем долг и увеличиваем общую сумму выплаченного.
#720 #1094212
>>1093924

> ("/([а-яё]+)\\s+([а-яё])


Тут нужно использовать ^

> //получаем полное имя


> $name = $this->name;


Переменная никак не используется.

> foreach( $this->hours as $object->$hour ){


Что такое $object? Эта переменная нигде не определена. Справа в foreach нужно указывать просто переменную, мануал http://php.net/manual/ru/control-structures.foreach.php

> for (;$stringLen < $length; $stringLen++){


> $space .= " ";


Используй str_repeat

В общем, кроме функции getOvertimeHours, сделано неплохо. Вместо <pre> можно еще ставить тип ответа text/plain, как описано тут https://github.com/codedokode/pasta/blob/master/soft/web-server.md

>>1093875

К сожалению, код переусложнен и его трудно понять. Выражение "$creditBalance$percent+$servicePayment" повторяется аж 3 раза. Нужно убрать повторы.

Более того, с математической точки зрения там формула бессмысленна:

> $creditBalance$percent+$servicePayment - $monthlyPayment + $monthlyPayment;


Какой смысл прибавлять значение и тут же его отнимать?

Решается эта задача примерно так:

- прибавляем проценты и комиссию к остатку долга (!не вычитаем ничего пока!)
- если остаток маленький, выплачиваем сколько осталось и уходим
- иначе платим 5000

«Платим» здесь значит уменьшаем долг и увеличиваем общую сумму выплаченного.
#721 #1094213
>>1093811

> Рационально ли класс, который будет рассчитывать антикризисные меры, сделать наследником класса, выводящего таблицу?


Увы, такая идея говорит о том, что ты пока не очень разобрался в наследовании. Наследовать можно только однотипные классы, когда наследник дополняет предка какими-то полезными функциями или меняет его поведение.

Если класс A наследует B, то значит A - это расширенная, улучшенная, модифицированная версия B.

Пример:

От класса Организация (свойства: ИНН, ОГРН, город) наследуем класс Банк (с дополнительным свойством Номер Лицензии). Это осмысленно, так как Банк - это Организация. И наследованием мы добавляем функционал, который связан с лицензиями на банковскую деятельность. Этот функционал нужен только в Банке, а не в других Организациях, потому мы сделали для него отдельный класс-наследник.

Если мы пишем игру, то от класса ТранспортноеСредство (свойства: макс. скорость, запас хода, вместимость) мы можем унаследовать классы Танк (с дополнительным свойством Дальность Стрельбы) и Грузовик (со свойством грузоподъемность). Так как и Танк, и Грузовик - это ТранспортныеСредства (по крайней мере в рамках нашей игры).

Но можно ли унаследовать АнтикризисныйКомитет от ВыводителяТаблиц? Я не думаю, что первый является частным случаем второго, они никак не связаны и наследование здесь применять недопустимо.

Также, я тебе советую прочитать еще про "Принцип подстановки Барбары Лисков".

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

--------

Есть ПродюсерскоеАгенство, и оно периодически сотрудничает с разными Персонами для участия в рекламных, музыкальных, кинематографических и других Проектах. Агенству нужно хранить информацию о Персонах, с которыми оно контактировало или планирует контактировать. Тебе поручено создание соответствующей базы данных.

Персоны - это люди, у которых есть какие-то творческие способности. У каждой Персоны есть такие свойства:

- имя
- контактный номер телефона

Кроме того, у них могут быть навыки: Персона может быть Актером, Моделью, Музыкантом, Менеджером.

У Актера в дополнение к обычным свойствам есть свойство: список Фильмов, в которых он снимался
У Музыканта есть свойства: список Групп, в которых он участвует, и список инструментов, на которых он умеет играть
У Модели есть свойства: рост, цвет глаз и цвет волос
У Менеджера (Агент или менеджер по работе с талантами) есть свойство: название Агенства, которое он представляет.

У Актера, Музыканта или Модели может быть свой Менеджер, и эта информация должна быть указана в их профиле (нельзя заключить договор без обсуждения с ним).

Нужно представить информацию о Персонах в виде объектной модели (набора классов), которая бы позволила наиболее удобно представить информацию о них. Соответственно "база Персон" - это просто массив таких объектов. Тебе нужно спроектировать эти классы. Методы тут писать не нужно, хватит только полей.

--------

По коду:

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

- публичные константы
- непубличные константы
- публичные поля
- непубличные поля
- абстрактные методы
- конструктор
- публичные методы
- непубличные методы

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

> int $isBoss


Вообще, для значений типа да/нет есть булев тип: http://php.net/manual/ru/language.types.boolean.php

Операторы вроде == или < как раз возвращают значения булевого типа.

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

> public function deleteWorker(int $number): void


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

> public function sortWorkers(): void


Назначение функции непонятно. Зачем мне сортировать работников в департаменте? И по какому критерию? По алфавиту?

Кстати, если ты хотел устранить промежутки в нумерации, array_values делает это быстрее.

> class HiringWorkers


Название класса - это существительное. То есть WorkerHirer (странно звучит конечно) или WorkerCreator. Но правильнее было бы назвать WorkerFactory - класс, который "производит" объекты, называют фабрикой.

Кстати, для аргуиментов функций можно указать значения по умолчанию: http://php.net/manual/ru/functions.arguments.php

Так, в общем, пока код хорошо выглядит.
#721 #1094213
>>1093811

> Рационально ли класс, который будет рассчитывать антикризисные меры, сделать наследником класса, выводящего таблицу?


Увы, такая идея говорит о том, что ты пока не очень разобрался в наследовании. Наследовать можно только однотипные классы, когда наследник дополняет предка какими-то полезными функциями или меняет его поведение.

Если класс A наследует B, то значит A - это расширенная, улучшенная, модифицированная версия B.

Пример:

От класса Организация (свойства: ИНН, ОГРН, город) наследуем класс Банк (с дополнительным свойством Номер Лицензии). Это осмысленно, так как Банк - это Организация. И наследованием мы добавляем функционал, который связан с лицензиями на банковскую деятельность. Этот функционал нужен только в Банке, а не в других Организациях, потому мы сделали для него отдельный класс-наследник.

Если мы пишем игру, то от класса ТранспортноеСредство (свойства: макс. скорость, запас хода, вместимость) мы можем унаследовать классы Танк (с дополнительным свойством Дальность Стрельбы) и Грузовик (со свойством грузоподъемность). Так как и Танк, и Грузовик - это ТранспортныеСредства (по крайней мере в рамках нашей игры).

Но можно ли унаследовать АнтикризисныйКомитет от ВыводителяТаблиц? Я не думаю, что первый является частным случаем второго, они никак не связаны и наследование здесь применять недопустимо.

Также, я тебе советую прочитать еще про "Принцип подстановки Барбары Лисков".

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

--------

Есть ПродюсерскоеАгенство, и оно периодически сотрудничает с разными Персонами для участия в рекламных, музыкальных, кинематографических и других Проектах. Агенству нужно хранить информацию о Персонах, с которыми оно контактировало или планирует контактировать. Тебе поручено создание соответствующей базы данных.

Персоны - это люди, у которых есть какие-то творческие способности. У каждой Персоны есть такие свойства:

- имя
- контактный номер телефона

Кроме того, у них могут быть навыки: Персона может быть Актером, Моделью, Музыкантом, Менеджером.

У Актера в дополнение к обычным свойствам есть свойство: список Фильмов, в которых он снимался
У Музыканта есть свойства: список Групп, в которых он участвует, и список инструментов, на которых он умеет играть
У Модели есть свойства: рост, цвет глаз и цвет волос
У Менеджера (Агент или менеджер по работе с талантами) есть свойство: название Агенства, которое он представляет.

У Актера, Музыканта или Модели может быть свой Менеджер, и эта информация должна быть указана в их профиле (нельзя заключить договор без обсуждения с ним).

Нужно представить информацию о Персонах в виде объектной модели (набора классов), которая бы позволила наиболее удобно представить информацию о них. Соответственно "база Персон" - это просто массив таких объектов. Тебе нужно спроектировать эти классы. Методы тут писать не нужно, хватит только полей.

--------

По коду:

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

- публичные константы
- непубличные константы
- публичные поля
- непубличные поля
- абстрактные методы
- конструктор
- публичные методы
- непубличные методы

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

> int $isBoss


Вообще, для значений типа да/нет есть булев тип: http://php.net/manual/ru/language.types.boolean.php

Операторы вроде == или < как раз возвращают значения булевого типа.

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

> public function deleteWorker(int $number): void


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

> public function sortWorkers(): void


Назначение функции непонятно. Зачем мне сортировать работников в департаменте? И по какому критерию? По алфавиту?

Кстати, если ты хотел устранить промежутки в нумерации, array_values делает это быстрее.

> class HiringWorkers


Название класса - это существительное. То есть WorkerHirer (странно звучит конечно) или WorkerCreator. Но правильнее было бы назвать WorkerFactory - класс, который "производит" объекты, называют фабрикой.

Кстати, для аргуиментов функций можно указать значения по умолчанию: http://php.net/manual/ru/functions.arguments.php

Так, в общем, пока код хорошо выглядит.
#722 #1094215
>>1093642

> if ($creditBalance < $monthlyPayment) {


> $monthlyPayment = $monthlyPayment - $creditBalance;


Если creditBalance стал отрицательным, то monthlyPayment увеличится и станет например равна 6000.

>>1093619

Тогда уж лучше Referer/Origin проверять - меньше возможностей для багов.

>>1093574

http_build_query

>>1093300

Тут надо подумать, как это сформулировать. Я не могу написать "их адреса", так как сначала надо объяснить, что такое "адрес". Но я понимаю, что для начинающего концепция передачи объекта как будто по ссылке представляет сложность. Я подумаю, как об этом понятнее рассказать.

>>1093241

Я подозреваю, что памяти там может быть тратится не так и много, а объектов много из-за большого числа потоков в Апаче. Плюс, поток PHP в mod_php ведь не умирает после завершения скрипта.

У тебя там на скриншоте Working Set - 54 Мб, это не такая цифра, из-за которой надо поднимать панику. Хотя, конечно, может быть он тупо упирается в какой-то лимит дескрипторов на один процесс и падает из-за этого. Но их должно быть не 20, а думаю, тысячи.

И ведь у этих объектов (Section) одинаковое имя. Наверно, он мог бы открывать ранее созданный объект вместо того, чтобы постоянно создавать новые. Может это и баг.

Тогда можно сделать другую проверку: скрипт для ком. строки, который выделяет и освобождает один сегмент. И этот скрипт запускать N раз подряд другим скриптом. И смотреть, будут проблемы или нет. Ну или в случае Апача, дергать скрипт http://localhost/1.php в цикле из скрипта командной строки и смотреть на изменения со временем: будет потребление памяти и дескрипторов расти или остановится.

Что касается ошибки, когда Апач падает - это может быть баг где-то в другом месте. Было бы здорово, если бы ты мог сделать пример минимального, простейшего скрипта, который гарантированно роняет Апач, я бы его проверил, и если баг есть, может быть, написал бы разработчикам PHP (ну или ты сам можешь это сделать, но сначала лучше разобраться в ситуации получше, чтобы не нагружать людей лишней работой). Ну или конечно, может там тупо дескрипторы заканчиваются. Это наверно можно выяснить из сишного кода в PHP (можешь заодно попробовать и исправить :) ).

Алсо, на всякий случай, shmop_delete там надо вызывать ПЕРЕД shmop_close, если я не путаю.
#722 #1094215
>>1093642

> if ($creditBalance < $monthlyPayment) {


> $monthlyPayment = $monthlyPayment - $creditBalance;


Если creditBalance стал отрицательным, то monthlyPayment увеличится и станет например равна 6000.

>>1093619

Тогда уж лучше Referer/Origin проверять - меньше возможностей для багов.

>>1093574

http_build_query

>>1093300

Тут надо подумать, как это сформулировать. Я не могу написать "их адреса", так как сначала надо объяснить, что такое "адрес". Но я понимаю, что для начинающего концепция передачи объекта как будто по ссылке представляет сложность. Я подумаю, как об этом понятнее рассказать.

>>1093241

Я подозреваю, что памяти там может быть тратится не так и много, а объектов много из-за большого числа потоков в Апаче. Плюс, поток PHP в mod_php ведь не умирает после завершения скрипта.

У тебя там на скриншоте Working Set - 54 Мб, это не такая цифра, из-за которой надо поднимать панику. Хотя, конечно, может быть он тупо упирается в какой-то лимит дескрипторов на один процесс и падает из-за этого. Но их должно быть не 20, а думаю, тысячи.

И ведь у этих объектов (Section) одинаковое имя. Наверно, он мог бы открывать ранее созданный объект вместо того, чтобы постоянно создавать новые. Может это и баг.

Тогда можно сделать другую проверку: скрипт для ком. строки, который выделяет и освобождает один сегмент. И этот скрипт запускать N раз подряд другим скриптом. И смотреть, будут проблемы или нет. Ну или в случае Апача, дергать скрипт http://localhost/1.php в цикле из скрипта командной строки и смотреть на изменения со временем: будет потребление памяти и дескрипторов расти или остановится.

Что касается ошибки, когда Апач падает - это может быть баг где-то в другом месте. Было бы здорово, если бы ты мог сделать пример минимального, простейшего скрипта, который гарантированно роняет Апач, я бы его проверил, и если баг есть, может быть, написал бы разработчикам PHP (ну или ты сам можешь это сделать, но сначала лучше разобраться в ситуации получше, чтобы не нагружать людей лишней работой). Ну или конечно, может там тупо дескрипторы заканчиваются. Это наверно можно выяснить из сишного кода в PHP (можешь заодно попробовать и исправить :) ).

Алсо, на всякий случай, shmop_delete там надо вызывать ПЕРЕД shmop_close, если я не путаю.
#723 #1094216
>>1092841

Не знаю, может в документации посмотреть? Я не знаю.

>>1092784

Попробуй это сделать в другом языке.

>>1092756

В шаблонах. Как ты обернешь объект или результат возврата функции?

>>1092704

Иногда может быть удобнее разбить строку на массив слов и работать с каждым по отдельности. Что касается поиска слов с буквами разных алфавитов - они ищутся так:

- любые буквы, за ними кириллица, за ней латиница, за ней любые буквы
- или
- любые буквы, за ними латиница, за ней кириллица, за ней любые буквы

Что касается исправления, тут лучше работать с исходной строкой, а не со строкой с добавленными скобками. Если разбить исходную строку на слова, для каждого слова можно определить язык (например по первой букве) и заменить буквы других алфавитов в нем.

А так, у тебя всего 3 буквы исправляется, и то, если они стоят по одиночке.
#724 #1094217
>>1092684

Формулу увеличения суммы лучше вынести из заголовка цикла в тело на отдельную строчку. А то код труднее читать и труднее найти проблему.

Почему у тебя 2 вложенных цикла? Ты можешь описать словами, какие команды должен выполнять PHP?

Я твой код вижу так:

1) присвоить $x значение 10000
2) проверить: если $x больше миллиона, перейти к шагу 10
3) присвоить $y знаечние 16
4) проверить: если $x больше миллиона, перейти к шагу 10
5) написать: "В $y будет $x на счете \n"
6) увеличить $y на 1 ($y++)
7) перейти к шагу 4
8) увеличить $x на 10%
9) перейти к шагу 2
10) конец программы

Попробуй выполнить этот алгоритм "вручную", выполняя роль PHP. Если ты все сделаешь правильно, то ты увидишь, почему эта программа будет выполняться бесконечно ("зациклится").

>>1092677

Я обычно не заморачиваюсь и в тесте просто создаю временную папку в /tmp, которую потом уничтожаю.

Чтобы использовать абстракции вроде Flysystem, твой код должен принимать снаружи объект Filesystem. Тогда его можно будет подменить в тесте.

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



Простой вариант: ведь код должен испоьзовать путь из Settings

Более сложный вариант: код должен принимать объект Filesystem и работать с файлом через него, тогда этот объект можно подменить в тесте. То есть, надо использовать DI. Урок про DI: https://github.com/codedokode/pasta/blob/master/arch/di.md
#724 #1094217
>>1092684

Формулу увеличения суммы лучше вынести из заголовка цикла в тело на отдельную строчку. А то код труднее читать и труднее найти проблему.

Почему у тебя 2 вложенных цикла? Ты можешь описать словами, какие команды должен выполнять PHP?

Я твой код вижу так:

1) присвоить $x значение 10000
2) проверить: если $x больше миллиона, перейти к шагу 10
3) присвоить $y знаечние 16
4) проверить: если $x больше миллиона, перейти к шагу 10
5) написать: "В $y будет $x на счете \n"
6) увеличить $y на 1 ($y++)
7) перейти к шагу 4
8) увеличить $x на 10%
9) перейти к шагу 2
10) конец программы

Попробуй выполнить этот алгоритм "вручную", выполняя роль PHP. Если ты все сделаешь правильно, то ты увидишь, почему эта программа будет выполняться бесконечно ("зациклится").

>>1092677

Я обычно не заморачиваюсь и в тесте просто создаю временную папку в /tmp, которую потом уничтожаю.

Чтобы использовать абстракции вроде Flysystem, твой код должен принимать снаружи объект Filesystem. Тогда его можно будет подменить в тесте.

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



Простой вариант: ведь код должен испоьзовать путь из Settings

Более сложный вариант: код должен принимать объект Filesystem и работать с файлом через него, тогда этот объект можно подменить в тесте. То есть, надо использовать DI. Урок про DI: https://github.com/codedokode/pasta/blob/master/arch/di.md
#725 #1094218
>>1092388

Потому что чаны уже написаны и модерируются. Может когда-нибудь и подумаем над какими-то формумами или обсуждением под уроками.

>>1092613

Я тут подумал, если бы в Filesystem при создании можно было указать "корень" файловой системы, то путь к папке не надо было бы указывать - мы передаем в компонент "файловую систему", а он создает в ней файлы где хочет.

Ну и во многих случаях файловая система используется как кеш - тогда лучше сделать зависимостью не ее, а например кеш из Доктрины - это позволит хранить данные не только в файлах, но и в памяти, редисе, БД и тд.

>>1092607

Общая идея верная, но есть косяки.

> [,]


Запятая не спецсимвол, в скобки можно не брать

> Жж


Можно просто добавить флаг i

> [Жж|Шш]


Вертикальная черта здесь обозначает соответствующий символ, а не "или"

Выражение для запятой перед "а" сработает даже если эта запятая есть: 'Не X, а Y'.

>>1092517

> В гайде написано LoadModule php5_module


Ну вообще, там есть 2 варианта, для PHP5 и PHP7:

http://php.net/manual/ru/install.unix.apache2.php

> For PHP 7:


> LoadModule php7_module modules/libphp7.so



> AH00558: httpd.exe: Could not reliably determine the server's fully qualified domain name, using тут шестнадцатеричные числа. Set the 'ServerName' directive globally to suppress this message


Там написано, как победить это предупреждение - добавить директиву ServerName

> тут шестнадцатеричные числа


Это твой IPv4 или IPv6 адрес наверно.

Сделал ты вроде все верно.
#725 #1094218
>>1092388

Потому что чаны уже написаны и модерируются. Может когда-нибудь и подумаем над какими-то формумами или обсуждением под уроками.

>>1092613

Я тут подумал, если бы в Filesystem при создании можно было указать "корень" файловой системы, то путь к папке не надо было бы указывать - мы передаем в компонент "файловую систему", а он создает в ней файлы где хочет.

Ну и во многих случаях файловая система используется как кеш - тогда лучше сделать зависимостью не ее, а например кеш из Доктрины - это позволит хранить данные не только в файлах, но и в памяти, редисе, БД и тд.

>>1092607

Общая идея верная, но есть косяки.

> [,]


Запятая не спецсимвол, в скобки можно не брать

> Жж


Можно просто добавить флаг i

> [Жж|Шш]


Вертикальная черта здесь обозначает соответствующий символ, а не "или"

Выражение для запятой перед "а" сработает даже если эта запятая есть: 'Не X, а Y'.

>>1092517

> В гайде написано LoadModule php5_module


Ну вообще, там есть 2 варианта, для PHP5 и PHP7:

http://php.net/manual/ru/install.unix.apache2.php

> For PHP 7:


> LoadModule php7_module modules/libphp7.so



> AH00558: httpd.exe: Could not reliably determine the server's fully qualified domain name, using тут шестнадцатеричные числа. Set the 'ServerName' directive globally to suppress this message


Там написано, как победить это предупреждение - добавить директиву ServerName

> тут шестнадцатеричные числа


Это твой IPv4 или IPv6 адрес наверно.

Сделал ты вроде все верно.
#726 #1094219
>>1092476

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

>>1092373

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

>>1092316

Поиск по регулярке по миллиону строк быстрым не будет. Если нужен поиск по слову - то смотри на FULLTEXT индексы либо на сторонний поисковый демон вроде Sphinx, Lucene ит д.

FULLTEXT индекс не ускоряет поиск по регулярке, он будет делаться полным обходом таблицы. FULLTEXT ускоряет только поиск через MATCH() если я не путаю.

>>1092261

Не знаю, поищи трейты в опен сурс проектах, может что найдешь. Можно попрбовать так: https://github.com/search?l=PHP&q=trait&type=Repositories&utf8=✓

Алсо, посмотри выше задачу про ПродюсерскоеАгенство - помогут ли там трейты?

>>1092206

Можно использовать str_repeat, ну и я вроде выше комментировал эту задачу.

>>1092199

Да, Но вообще лучше подумать над интерфейсом, неужели пользователь одновременно редактирует 200 форм?
#726 #1094219
>>1092476

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

>>1092373

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

>>1092316

Поиск по регулярке по миллиону строк быстрым не будет. Если нужен поиск по слову - то смотри на FULLTEXT индексы либо на сторонний поисковый демон вроде Sphinx, Lucene ит д.

FULLTEXT индекс не ускоряет поиск по регулярке, он будет делаться полным обходом таблицы. FULLTEXT ускоряет только поиск через MATCH() если я не путаю.

>>1092261

Не знаю, поищи трейты в опен сурс проектах, может что найдешь. Можно попрбовать так: https://github.com/search?l=PHP&q=trait&type=Repositories&utf8=✓

Алсо, посмотри выше задачу про ПродюсерскоеАгенство - помогут ли там трейты?

>>1092206

Можно использовать str_repeat, ну и я вроде выше комментировал эту задачу.

>>1092199

Да, Но вообще лучше подумать над интерфейсом, неужели пользователь одновременно редактирует 200 форм?
#727 #1094220
>>1092175

Не работает

>>1092154

Ты выводишь ссылку, но забыл, что ее тоже надо экранировать при вставке в HTML код.

Также, $link не создает ссылку, а только собирает в строку параметры. Тебе надо хотя бы знак вопроса приписать, а может еще и имя скрипта. Посмотри глазами, что там за ссылка получается.

Алсо, урок про относительные URL: https://github.com/codedokode/pasta/blob/master/network/urls.md

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

>>1091628

Вообще, в мануале MySQL написано, что в INSERT можно ссылаться на предыдущие знаечния:

INSERT INTO t(a, b) VALUES (10, a + 1)

Почему-то у тебя он разрешил ссылаться на текущее же значение поля.

>>>В первом варианте нужно явно указать имена колонок


> Где именно, а то я и так их указывал но не там где нужно?


Я имел в виду, указывать после INSERT, то есть INSERT INTO t(a, b). Иначе ты полагаешься на порядок, в котором поля идут в таблице.
#728 #1094223
>>1094215

>Тут надо подумать, как это сформулировать. Я не могу написать "их адреса", так как сначала надо объяснить, что такое "адрес". Но я понимаю, что для начинающего концепция передачи объекта как будто по ссылке представляет сложность. Я подумаю, как об этом понятнее рассказать.


Рад, что смог улучшить сайт!

Так-то можно ещё в переменных бросить пару слов, что мол "давайте абстрагировать и не представлять, что в памяти создается раздел с именем переменной" и далее.
#729 #1094231
Аноны или ОП, если прочтёшь, подскажите, как клонировать объект, содержащий массив с объектами другого класса. Пробовал через __clone, но так ничего и не получается. Объяснить, пожалуйста.
#730 #1094233
>>1094231

Клонирование в PHP неглубокое. То есть объект клонируется, но другие объекты, которые хранятся в его свойствах, не клонируются. В клон просто копируются ссылки на те же самые объекты.

Решение - переопределить метод __clone, изучить как он работает (а он вызывается на клоне после клонирования). И в нем создать клоны нужных объектов, которые хранятся в свойствах.

Покажи свой не работающий код.
#731 #1094241
>>1094233
кода к задаче пока нет, пробую разобраться на чём-то элементарном вроде этого.

https://3v4l.org/dUWWD

Не понимаю, как правильно переопределить метод клонирования
#732 #1094251
>>1094241

> $this->ar = clone $this->ar;



А разве можно клонировать массив? Нужно создать новый массив и в него положить клоны всех элементов из старого в цикле.

> foreach($this->ar as &$value){


Зачем тут & ? Он не нужен.

Если что, var_dump пишет номера объектов и по ним ты можешь понять, тот же самый перед тобой объект или копия.
#733 #1094255
>>1094251
Добра тебе, анон. Работает
#734 #1094257
>>1094212

>Тут нужно использовать ^



Исправил

>Переменная никак не используется.



Исправил

>Что такое $object? Эта переменная нигде не определена. Справа в foreach нужно указывать просто переменную



Исправил

>Используй str_repeat



У меня как-то криво получилось ее использовать сейчас. Хорошо, спасибо большое за подсказку в следующий раз обязательно буду знать, что использовать, если будет подобный случай

>В общем, кроме функции getOvertimeHours, сделано неплохо



А как надо было ее описать?

>Вместо <pre> можно еще ставить тип ответа text/plain, как описано тут



Прочитаю сейчас, спасибо большое за комментарии и помощь.

https://ideone.com/71bN65
#735 #1094305
Молю анонов объяснить дауну как запустить пхп скрипт, например роутер из статьи ОПа на гитхабе, на апаче. Нюанс в том что он ниоткуда не вызывается, и я вообще не могу понять как заставить его проверять юрлы.
#736 #1094306
ОП, посмотри задачу про антикризисные меры.

https://3v4l.org/oLuMG

Подскажи, пожалуйста, как сделать меру, в которой стимулируются аналитики. Думал, переопределить функции из класса "Аналитик", в которой возвращаются кофе и зарплата, но наследовать "Антикризисные меры" от "Аналитик" бред же.
Дай подсказку.
#737 #1094309
>>1094231
Только не вздумай свой велосипед где-то в реальных проектах использовать, есть deep-clone: https://github.com/myclabs/DeepCopy

>>1092677

>public function setCookiePath($path)


>{


>$this->cookiePath = self::LIB_ROOT . $path;


>}



Тут нет ошибки? Локальный путь конкатенируется с путём из виртуальной ФС, так работать не будет.

И может быть для тестирования аутентификации не нужно сохранять куки на ФС? А то у тебя уже не юнит-тест, а интеграционный. Тесты должны быть как можно проще, неудобно поддерживать сложный код.
#738 #1094311
>>1094212

>К сожалению, код переусложнен и его трудно понять.



https://ideone.com/JckI8o

Так лучше?
#739 #1094366
>>1094217

> Я обычно не заморачиваюсь и в тесте просто создаю временную папку в /tmp, которую потом уничтожаю.


Я тоже смотрю, что даже в серьезных проектах делается зачастую как раз так, но с другой стороны в самом мануале по phpunit указана эта библиотека для работы с файловой системой и такой подход кажется изящным (пока не попытаешься использовать, по крайней мере).

>Более сложный вариант: код должен принимать объект Filesystem и работать с файлом через него, тогда этот объект можно подменить в тесте



Спасибо! Так и поступлю.

> Тут нет ошибки? Локальный путь конкатенируется с путём из виртуальной ФС, так работать не будет.


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

> И может быть для тестирования аутентификации не нужно сохранять куки на ФС?


Там еще идет тестирование на то, что файл куки создается корректно (есть нужная папка, нужные права и т.д.).

А вот еще вопрос по случаю: ты говоришь, тесты должны быть простыми. И вроде да, ведь юнит-тест тестирует минимально самостоятельную часть кода, метод там или класс. Но есть же некоторые вещи, которые тоже хочется протестировать, но они уже выходят за рамки одного класса. Например, что твой код корректно обрабатывает присланные каким-то сторонним сервером по АПИ данные. Тогда нужно создавать класс-мок и
это уже по идее не юнит-тест. Или что при авторизации корректно создается файл куки. С такими вещами как поступать? Не тестировать их с помощью Phpunit, а, допустим, через codeception?
#740 #1094368
>>1094305

На Апаче его так просто использовать нельзя. Нужно с помощью mod_rewrite настроить переписывание всех URL, которым не соответствуют файлы, на скрипт роутинга.

https://habrahabr.ru/company/sprinthost/blog/129560/

Также, в этом случае не будет работать return false (он не вернет управление серверу для поиска файла).
#741 #1094436
Только начинаю постигать php, не могу понять, почему не записываются данные из формы в txt файл?
https://pastebin.com/EqAHm1GW
#742 #1094685
>>1094220

Спасибо!
Вроде бы получилось.
Буду благодарен за замечания.
Есть 2 файла index.php

<form action="index.php" method="get">
<textarea name="text" cols="30" rows="10">

</textarea>
<p><input type="submit"></p>
</form>

<?php
$text = $_GET["text"];
$htmlText = htmlspecialchars($text);
echo "<pre>$htmlText</pre>";

$link = http_build_query(['text' => $text, 'lt' => 1]);
echo "<a href='script.php?{$link}'>Ссылка</a>";

--
script.php
<?php
$urlData = htmlspecialchars($_GET["text"]);
echo "<pre>$urlData</pre>";
#742 #1094685
>>1094220

Спасибо!
Вроде бы получилось.
Буду благодарен за замечания.
Есть 2 файла index.php

<form action="index.php" method="get">
<textarea name="text" cols="30" rows="10">

</textarea>
<p><input type="submit"></p>
</form>

<?php
$text = $_GET["text"];
$htmlText = htmlspecialchars($text);
echo "<pre>$htmlText</pre>";

$link = http_build_query(['text' => $text, 'lt' => 1]);
echo "<a href='script.php?{$link}'>Ссылка</a>";

--
script.php
<?php
$urlData = htmlspecialchars($_GET["text"]);
echo "<pre>$urlData</pre>";
#743 #1094692
>>1094211

>Для начала, надо открыть логи и посмотреть там подробности ошибки.


Паблик сделал

>Нет, вроде бы не разобрались. Твои имена файлов не соответствуют PSR-4 и я хотел узнать, почему? Ты там добавляешь слово class. Лучше наверно следовать общепринятой рекомендации, если нет каких-то веских причин.


Сделал, если я правильно понял?

>Такое, которое будет равносильно условию $_SERVER['QUERY_STRING'] == "id=registration"). Ты можешь сделать var_dump($_GET) и увидеть, что в этом массиве.


Сделал

>Реши-ка задачу на экранирование отсюда


В процессе

>Куки надо ставить до вывода текста страницы. Если это условие соблюдается, то ob_start не нужен.


Так у меня много мест где куки идут ниже по странице и хедеров тоже есть

>Нет, не везде исправлена проблема. Вот например, места, где переменные вставляются напрямую в SQL-запрос без всякой обработки:


Щас исправил, только ордер бай по столбцам нельзя делать через prepare, иначе он выдаёт по айдишникам на любой запрос, я сделал вайт лист для для сорта
$whiteList = array('name', 'second_name', 'grup');

foreach($whiteList as $list){
if($list == $_GET['sort']){
$sort = $_GET['sort'];
}
}
https://stackoverflow.com/questions/12021018/php-mysql-mysqli-prepared-statements-possible-to-use-bind-param-for-order-by
Вот ссылка там все сказано, если я правильно перевёл

>Нужно для всех функций mysqli, которые могут вернуть ошибку, проверять результат.


Сделал

>Нужно, чтобы когда ты запускаешь скрипт из браузера (заходишь на URL вида http://localhost/login.php) тебя бы залогинило под определенным пользователем, под каким именно - можно жестко заложить в скрипте. Ну например, под пользователем с идентификатором 1. Если ты бы залогинен под другим аккаунтом - он должен из него выйти и залогиниться под заданным в скрипте.


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

>Нужен отдельный скрипт, который просто при открытии пишет например, email аккаунта, под которым ты залогинен. Если не залогинен - то выводит соответствующее сообщение. И ничего больше, просто выводит информацию, под каким аккаунтом ты сейчас залогинен. С помощью этого скрипта можно будет проверить работу второго скрипта (который залогинивает).


Теперь показывает залогиненный емейл

>Тут слишком много аргументов. У функции не должно быть так много аргументов.


Сделал через массивы

>Я вижу, ты загрузил дамп БД. В нем тоже надо сделать исправления:


В процессе

>Если ты плохо понимаешь объекты, в ОП посте есть учебник, в нем глава про ООП и задача про ООО "Вектор", которые помогут разобраться в них.


В процессе
#743 #1094692
>>1094211

>Для начала, надо открыть логи и посмотреть там подробности ошибки.


Паблик сделал

>Нет, вроде бы не разобрались. Твои имена файлов не соответствуют PSR-4 и я хотел узнать, почему? Ты там добавляешь слово class. Лучше наверно следовать общепринятой рекомендации, если нет каких-то веских причин.


Сделал, если я правильно понял?

>Такое, которое будет равносильно условию $_SERVER['QUERY_STRING'] == "id=registration"). Ты можешь сделать var_dump($_GET) и увидеть, что в этом массиве.


Сделал

>Реши-ка задачу на экранирование отсюда


В процессе

>Куки надо ставить до вывода текста страницы. Если это условие соблюдается, то ob_start не нужен.


Так у меня много мест где куки идут ниже по странице и хедеров тоже есть

>Нет, не везде исправлена проблема. Вот например, места, где переменные вставляются напрямую в SQL-запрос без всякой обработки:


Щас исправил, только ордер бай по столбцам нельзя делать через prepare, иначе он выдаёт по айдишникам на любой запрос, я сделал вайт лист для для сорта
$whiteList = array('name', 'second_name', 'grup');

foreach($whiteList as $list){
if($list == $_GET['sort']){
$sort = $_GET['sort'];
}
}
https://stackoverflow.com/questions/12021018/php-mysql-mysqli-prepared-statements-possible-to-use-bind-param-for-order-by
Вот ссылка там все сказано, если я правильно перевёл

>Нужно для всех функций mysqli, которые могут вернуть ошибку, проверять результат.


Сделал

>Нужно, чтобы когда ты запускаешь скрипт из браузера (заходишь на URL вида http://localhost/login.php) тебя бы залогинило под определенным пользователем, под каким именно - можно жестко заложить в скрипте. Ну например, под пользователем с идентификатором 1. Если ты бы залогинен под другим аккаунтом - он должен из него выйти и залогиниться под заданным в скрипте.


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

>Нужен отдельный скрипт, который просто при открытии пишет например, email аккаунта, под которым ты залогинен. Если не залогинен - то выводит соответствующее сообщение. И ничего больше, просто выводит информацию, под каким аккаунтом ты сейчас залогинен. С помощью этого скрипта можно будет проверить работу второго скрипта (который залогинивает).


Теперь показывает залогиненный емейл

>Тут слишком много аргументов. У функции не должно быть так много аргументов.


Сделал через массивы

>Я вижу, ты загрузил дамп БД. В нем тоже надо сделать исправления:


В процессе

>Если ты плохо понимаешь объекты, в ОП посте есть учебник, в нем глава про ООП и задача про ООО "Вектор", которые помогут разобраться в них.


В процессе
#744 #1094729
Друзья, подскажите как в клишном скрипте сделать вывод данных не в новой строке, а обновляемый. Типа добавляются записи в БД и выводится строчка "добавлено записей: 100", а каждое новое обновление там цифра меняется.

Я точно видел, что такое делается, но не могу понять, как нагуглить.
#745 #1094744
>>1094729
нагуглил таки.

Есть 2 варианта
for ($i=0 ; $i<=100 ; $i++) {
echo "Progress: $i% \r";
sleep(1);
}

и
for ($i=0 ; $i<=100 ; $i++) {
echo "Progress: $i% \r";
sleep(1);
}

Правда ни один из них не работает, если запускать скрипт через run шторма, что меня и смутило. Но в консоли все ок.
#746 #1094748
>>1094744

for ($i=0 ; $i<=100 ; $i++) {
echo "\033[5D"; // Move 5 characters backward
echo str_pad($i, 3, ' ', STR_PAD_LEFT) . " %"; // Output is always 5 characters long

ошибочка во втором варианте
#747 #1094866
Интересная статья про попытку определить частоту использования тех или иных языков: https://m.geektimes.ru/post/295577/

Задача интересна тем, что тут нет простого и очевидного решения. Вообще, работа с естественными языками (NLP) - довольно интересная тема.
someApprentice #748 #1094971
>>1093715

>В конце 2009 года было написано первое хранилище text-engine, а в 2010 на него перевели сообщения.


Надо бы не забыть и найти ваш пост, где вы писали о том что нужно в самописной БД.

Скорей бы наш сайт с архивами тредов поднять! На днях мне подтвердят paypal аккаунт, и я арендую VPS и домен - phpclub.tech
@kubk уже почти дописал парсер, поэтому на сайте будут и старые треды.

Кстати, мои данные с paypal аккаунта не будут теперь общедоступными для WhoIs сервисов?

>У сообщения есть набор атрибутов: идентификатор собеседника, текст, вложения и так далее.


Интересно как они хранили вложения, потому что к одному сообщению можно прикрепить одновременно и изоброжения, и аудизопись, и любой другой документ.
Мне видеться использовать JSON-объект с свойствами каждого вложения. MySQL поддерживает такой тип хранения.

>Для работы с ними мы подняли два новых кластера — member-chats и chat-members. Первый хранит данные о чатах по пользователям, второй — данные о пользователях по чатам.


Они имели ввиду, что денормализовали данные на две "сущности"?

>Кроме самих списков это, например, пригласивший пользователь и время добавления в чат.


Никогда не бывает достаточно данных. Я бы никогда не подумал что это информация может понадобиться. Как можно заранее построить схему, если со временём неизбежно придётся что-то менять, а данных слишком много?

>В этой схеме есть минусы. Синхронизация по-прежнему возложена на PHP. Большие чаты и пользователи, которые одновременно отправляют сообщения в них — опасная история. Поскольку экземпляр text-engine зависит от uid, участники чата могли получать одно и то же сообщение с разницей во времени. С этим можно было жить, если бы прогресс стоял на месте. Но не бывать такому.


Как это возможно? Можно было использовать получившийся экземпляр text-engine и преобразовывать его для member-chats и chat-members. Как у них удалось получить дисинхрон в сообщениях?

>Работа с диском в наших базах в большинстве случаев основана на сочетании бинарного лога изменений (бинлога), статических снимков и частичного образа в памяти.



>бинарный лог


https://ru.wikipedia.org/wiki/Двоичный_логарифм
https://dev.mysql.com/doc/refman/5.7/en/binary-log.html
Неужели число может представить операции над базой данных? Никак не могу это представить.

>статических снимков и частичного образа в памяти


Интересно какой софт они для этого использовали.

Очень познавательная статья, узнал много нового, и хотел бы однажды применить некоторые описанные там технологии чтобы познакомиться с ними по лучше.
someApprentice #748 #1094971
>>1093715

>В конце 2009 года было написано первое хранилище text-engine, а в 2010 на него перевели сообщения.


Надо бы не забыть и найти ваш пост, где вы писали о том что нужно в самописной БД.

Скорей бы наш сайт с архивами тредов поднять! На днях мне подтвердят paypal аккаунт, и я арендую VPS и домен - phpclub.tech
@kubk уже почти дописал парсер, поэтому на сайте будут и старые треды.

Кстати, мои данные с paypal аккаунта не будут теперь общедоступными для WhoIs сервисов?

>У сообщения есть набор атрибутов: идентификатор собеседника, текст, вложения и так далее.


Интересно как они хранили вложения, потому что к одному сообщению можно прикрепить одновременно и изоброжения, и аудизопись, и любой другой документ.
Мне видеться использовать JSON-объект с свойствами каждого вложения. MySQL поддерживает такой тип хранения.

>Для работы с ними мы подняли два новых кластера — member-chats и chat-members. Первый хранит данные о чатах по пользователям, второй — данные о пользователях по чатам.


Они имели ввиду, что денормализовали данные на две "сущности"?

>Кроме самих списков это, например, пригласивший пользователь и время добавления в чат.


Никогда не бывает достаточно данных. Я бы никогда не подумал что это информация может понадобиться. Как можно заранее построить схему, если со временём неизбежно придётся что-то менять, а данных слишком много?

>В этой схеме есть минусы. Синхронизация по-прежнему возложена на PHP. Большие чаты и пользователи, которые одновременно отправляют сообщения в них — опасная история. Поскольку экземпляр text-engine зависит от uid, участники чата могли получать одно и то же сообщение с разницей во времени. С этим можно было жить, если бы прогресс стоял на месте. Но не бывать такому.


Как это возможно? Можно было использовать получившийся экземпляр text-engine и преобразовывать его для member-chats и chat-members. Как у них удалось получить дисинхрон в сообщениях?

>Работа с диском в наших базах в большинстве случаев основана на сочетании бинарного лога изменений (бинлога), статических снимков и частичного образа в памяти.



>бинарный лог


https://ru.wikipedia.org/wiki/Двоичный_логарифм
https://dev.mysql.com/doc/refman/5.7/en/binary-log.html
Неужели число может представить операции над базой данных? Никак не могу это представить.

>статических снимков и частичного образа в памяти


Интересно какой софт они для этого использовали.

Очень познавательная статья, узнал много нового, и хотел бы однажды применить некоторые описанные там технологии чтобы познакомиться с ними по лучше.
sage #749 #1094980
Делаю сейчас студентов. Заметил, что ОП всем советует создавать абстрактный класс контроллера с конструктором, куда контейнер помещается, и от него уже все остальные наследовать. Зачем это надо?
#750 #1094986
>>1094980

Не советует. Где такое было?
#751 #1095116
PHP7 в подлиннике годное чтиво?
27 Кб, 1356x758
#752 #1095120
Я правильно понял задачу на наследование, абстрактные классы и методы?

https://ideone.com/SPUeqi
#753 #1095139
Отрывок кода с учебника про методы и инкапсуляцию.
https://ideone.com/ZU6IX3

Разве не должно быть так?
https://ideone.com/fZTS1K
#754 #1095385
>>1095139
Нет, не должно. Аргумент метода это просто переменная, данная тебе на вход. А уж потом ты решаешь, что с ней делать, и совать ли ее в объект.
Твой код не запустится, потому в аргументах должна быть обычная переменная.
#755 #1095389
>>1095120
$type лишняя, за нее должен работать полиморфизм.
Присваивай свойства объектам через конструктор, либо методы. Свойства должны быть private.
Класс Question не должен ничего выводить, особенно в методе с названием check. Унеси вывод наружу.
Вместо die надо кидать Exception.
Проверь ответ на третий вопрос.
#756 #1095390
Можно ли посмотреть поля класса не создавая его объект?
#757 #1095393
>>1095390

Так данные (значеия) хранятся в объектах. Объект - это условно говоря набор ящиков (полей), в которые можно "положить" (записать) какие-то знаечния. Ты создаешь объект и можешь в его поля что-то записывать.

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

Если проводить аналогии, то объект - это как дом, а класс - это план дома (на котором видно, сколько там комнат, дверей и тд.). И ты спрашиваешь "можно ли узнать, кто живет в плане дома".
#758 #1095395
>>1095389

Добавил абстрактный метод. Убрал $type. Так лучше?

https://ideone.com/1vJZXB

Это я еще сделал до твоего ответа, если что. Сейчас попробую переделать. Спасибо за ответы
#759 #1095402
>>1095390
Можно. Reflection API либо get_class_vars(). Но я уверен, что у тебя нет никаких веских причин этого делать, ты что-то делаешь не так.

>>1095395
Теперь у тебя вопрос еще и выводит сам себя. Это перегрузка обязанностями. Вопрос должен быть вопросом и ничем больше.
Тебе нужен класс QuestionWriter, который будет выводить вопросы.
#760 #1095440
Анон, как реализовать редирект в PHP?
Т.е. у меня есть две ссылки в бд. Они взаимозависимы.
Пользователь переходит по первой и попадает на вторую.
#761 #1095442
Yii2.
У меня ошибка. Всё что хочу - добавить форму на странимцу сайта.
Call to a member function getAttributeLabel() on null in ......\vendor\yiisoft\yii2-bootstrap\ActiveField.php
в строке $label = Html::encode($this->model->getAttributeLabel($attribute));

Во вью client.php: <?= $form->field($model, 'client') ?>
В модели Client.php:
namespace app\models;
use yii\db\ActiveRecord;
class Client extends ActiveRecord
{
public $client;
public function rules() {
return [
['client', 'safe'],
];
}
public function attributeLabels() {
return [
'client' => 'Клиент',
];
}
}
В контроллере:
public function actionClient()
{
$model = new Client();
$listClients = Client::find()->all();
return $this->render('client', compact('listClients'));
}

Что не так-то? Во вью написано "взять client из модели". Идём в контроллер, создаём модель, берём атрибут client (прописанный в модели), возвращаем на страницу.
#761 #1095442
Yii2.
У меня ошибка. Всё что хочу - добавить форму на странимцу сайта.
Call to a member function getAttributeLabel() on null in ......\vendor\yiisoft\yii2-bootstrap\ActiveField.php
в строке $label = Html::encode($this->model->getAttributeLabel($attribute));

Во вью client.php: <?= $form->field($model, 'client') ?>
В модели Client.php:
namespace app\models;
use yii\db\ActiveRecord;
class Client extends ActiveRecord
{
public $client;
public function rules() {
return [
['client', 'safe'],
];
}
public function attributeLabels() {
return [
'client' => 'Клиент',
];
}
}
В контроллере:
public function actionClient()
{
$model = new Client();
$listClients = Client::find()->all();
return $this->render('client', compact('listClients'));
}

Что не так-то? Во вью написано "взять client из модели". Идём в контроллер, создаём модель, берём атрибут client (прописанный в модели), возвращаем на страницу.
#762 #1095473
>>1082507 (OP)
А мы напоминаем, что оп и прочие помогаторы - няшки, и матери ихние - милашки.
мимо-разобрался-в-регулярках-только-благодаря-треду
#763 #1095564
>>1095440
Бамп вопросу. Я не представляю, как может работать код, который перенаправляет из одной ссылки к другой через сервак.
Есть какой-нибудь материал по теме?
#764 #1095581
>>1095442
Кое-как сам нашаманил решение.
В модели вместо client (название таблицы) надо было name (название столбца) и без объявления public $name;
И контроллер зменил слегка. Не знаю, правильно ли это, но после нажатия кнопки сабмит, в контроллер постом отправляется аж целый массив, в котором name - тоже массв. Поэтому приходится его выковыривать вручную.
$r1 = Yii::$app->request->post('Client');
$model->name = $r1['name'];
#765 #1095598
>>1095473
А я уже неделю жду пока кто-нибудь посмотрит мой кулькулятор. Пичаль.
#766 #1095616
>>1095598

Ты бы ссылку добавил на пост, а то в треде их уже больше 750.
#767 #1095625
>>1095616
Пардон >>1091538
#768 #1095651
>>1095625
Да говно твой калькулятор, переделывай
#769 #1095657
>>1094692

>>Если ты плохо понимаешь объекты, в ОП посте есть учебник, в нем глава про ООП и задача про ООО "Вектор", которые помогут разобраться в них.


https://ideone.com/o55cUw
Не знаю норм или нет, я сделал 1 класс под рабочего

>Реши-ка задачу на экранирование отсюда


https://ideone.com/WFgTYm
Вообще не понял что от меня требуется, сделал какую-то херню
#770 #1095749
Где можно посмотреть примеры приватных, публичных и защищенных свойств? Я пытаюсь понять зачем они нужны, но слишком много вопросов.

Приватные свойства нельзя менять, принимать в качестве аргументов функций, вызывать. Зачем они нужны?
#771 #1095760
>>1095749
https://ideone.com/iUuikq

Почему выводит 1?
#772 #1095767
>>1095760
Потому что ты из $this вычитаешь text. Стрелочка поломалась у тебя.
#773 #1095775
>>1095767
Спасибо большое
#774 #1095789
Зачем используют слэш (вот так например \PDO, а не просто PDO), когда задают класс PDO в тайпхинт?
#775 #1095790
>>1094218

>Выражение для запятой перед "а" сработает даже если эта запятая есть: 'Не X, а Y'.


А как исправить?
Оно либо прибавляет вторую, либо не ставит запятую вовсе.
https://ideone.com/RgrIHR
#776 #1095803
>>1095789
Ссылка на глобальный неймспейс. На случай, если кто-то захочет использовать этот код внутри не глобального неймспейса.
#777 #1095806
>>1095803
Ок, понял. Лучей добра, анон!
#778 #1095827
https://ideone.com/VmfSs5

Почему ucwords никак не влияет?
#779 #1095833
https://ideone.com/itRvqY

Что за содомия? Почему ucfirst не работает?
#780 #1095837
>>1095827
Потому что она работает только с однобайтовыми символами. Кириллица двухбайтовая.
Используй echo mb_convert_case($c, MB_CASE_TITLE, "UTF-8");

У ideone как-то странно собран php, там это undefined function. Проверь здесь - http://sandbox.onlinephpfunctions.com/
17 Кб, 795x425
#781 #1095840
>>1095837
Работает, но он все буквы делает большими. А как, чтобы только первую?
#783 #1095847
>>1095843
Но этот укфирст не работает. >>1095827
29 Кб, 366x480
#784 #1095956
>>1082507 (OP)
Уфф, ну и тяжело же было вас найти. Вы в глубоком бамплимите, >>1082507 (OP)
Нужно делать перекат. А то уже на главной создают тупые треды по алгоритмам, прикрываясь пхп.

У меня немного оффтоповый вопрос. Дома стоит сервер на debian9, там LAMP стоит.
На сервере создал виртуальный хост "test", в роутере связал домен test и ip сервера, файлы сайта лежат в отдельной директории пользователя, который является хозяином и разрабом сайта, принадлежит группе www-data (это такая группа, к которой в т.ч. принадлежит пользователь www-data, из под которого запускается апач, сделано для того, чтобы можно было настроить права на файлы сайта), в директории лишь файл index.html, и там не работает php.
До того как делал виртуальный хост, все работало - просто прописал в /var/www/htmi/index.php вывод phpinfo() и появилась та самая страничка с информацией. Сделал вставку вида ...<body> <?php echo phpinfo(); ?> </body> По-хорошему, так делать не надо, знаю.
И ничего не выводится. php необходимо подключить к каждому сайту?
#785 #1095965
Народ кто нибудь вкурсе сколько платят начинающему и вообще как он продвигается вперед сколько его ЗП?
Например начинающий у нас знает PhP, JS, Фреймы и т.д чувак вышел с технаря и знает базу, хочет расти, параллельно с этим пилил проекты на Гите и там его график работ и т.д который немал. Какие у него шансы?
#786 #1095983
>>1095965
ты как будто уже на собеседовании, лол

нормальные шансы у него. в дс 45-50 за такой расклад. просто обычно если первая работа, то опыта нет, в итоге фреймворк ты знаешь по примерам из документации, а когда видишь реальный проект, охуеваешь.

>>1095956
ты подробно описал владельца папки, но не приложил свой конфиг апача на неработающий хост, например. без этих сведений можно просто порекомендовать общую инфу https://stackoverflow.com/questions/5121495/php-code-is-not-being-executed-instead-code-shows-on-the-page

еще вот статья про mod_vhost_alias чтобы не прописывать каждый раз когфиги для хостов https://www.sitepoint.com/set-automatic-virtual-hosts-nginx-apache/
#787 #1095987
>>1095983
Эм... Потому что конфиг обычный.
Хост работает, на нем не работает php.

Вот лог /etc/apache2/sites-available/test.conf

<VirtualHost *:80>
ServerName test

ServerAdmin user@server
DocumentRoot /home/user/websites/test

ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined

</VirtualHost>

# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
#788 #1095997
>>1095840
Документация ответит тебе быстрее, чем тред. Она на русском.
#789 #1096005
>>1095987

>


>


>ErrorLog ${APACHE_LOG_DIR}/error.log


>CustomLog ${APACHE_LOG_DIR}/access


читал? https://stackoverflow.com/questions/5121495/php-code-is-not-being-executed-instead-code-shows-on-the-page
#790 #1096007
>>1095987

Подключение PHP, скорее всего, задается где-то в /etc/apache2/mods-available/php.conf

Что там написано?

Также, исполнение PHP скриптов может быть отключено в .htaccess.
#791 #1096008
>>1095987

Также, в файлах с раширением html PHP код при настройках по умолчанию не выполняется (где заданы эти настройки, я написал выше).
#792 #1096022
>>1096005
Читал. Там get запросы с устройств, с которых я пытался смотреть сайт.
В error.log отчеты о том, что все в норме.
В другом error.log.1 есть отчеты об ошибке в духе
"[Wed Nov 22 04:36:58.207793 2017] [:error] [pid 1175] [client 192.168.1.4:36885] script '/home/user/websites/test/index.php' not found or unable to start"

И еще обращения к иконке favicon.ico, к которой нет доступа "согласно настройке сервера".

>>1096007
Черт, а вот в php.conf есть такая строчка
" Running PHP scripts in user directories is disabled by default. To enable..."
И дальше блок с <IfModule... который я закомментил. Также исправил код в странице с phpinfo на простой вывод echo "строка php";
Не помогло. htaccess в директиве с сайтом нет.

При этом на главном домене php все еще работает. На виртуальном - нет. Создал файл внутри сайта test/phpinfo.php, выдает белый экран.
#793 #1096027
>>1096022
Мне кажется какой-то косяк в правах.
#794 #1096038
Сейчас начал решать вектор. Я правильно понимаю, что мне нужно создать два абстрактных класса( абстрактный департамент и абстрактный работник) и один класс для методов, чтобы высчитать зарплату/посчитать кофе/что-нибудь еще
#795 #1096049
>>1096022

Второй раз предлагаю показать php.conf
#796 #1096054
>>1096038

Поясни свою мысль, какие поля и методы будут в классах и как они наследуются.
#797 #1096061
>>1096054
Абстрактному классу работник задаются свойства ранг, зарплата, кофе, бумага. И абстрактный метод(?)

Из абстрактного класса работник наследуется 4 класса — Менеджер, Маркетолог, Инженер, Аналитик.

Наверное, я был не прав, когда писал:"один класс для методов, чтобы высчитать зарплату ..." ,потому что ничего придумать дельного не могу этому классу теперь.
#798 #1096088
>>1096022
почитай https://ubuntuforums.org/archive/index.php/t-2230036.html

особенно вот

> Thanks, it's working now, I'd forgotten that I'd enabled mod_userdir. I'd originally done that through symlinks :rolleyes:


> Changed "Off" to "On" and reset Apache :3

6 Кб, 443x133
#799 #1096120
Объясните, пожалуйста, этот момент в гайде ОПа.
Только что решал задачу с калькулятором и спокойно по невнимательности добавил сложение обычного числа с числом, записанным в строку. Проблем не возникло, калькулятор работал без проблем. После чего, ради интереса написал простецкую проверку для утверждения, что строки нельзя складывать или умножать: https://ideone.com/GPeBOp

Но опять, все работает. В чем соль?
#800 #1096124
>>1096120
PHP слабо типизированный язык, так что он сам приводит типы в выражениях. http://php.net/manual/en/language.types.type-juggling.php
#801 #1096127
>>1096124
т.е. данное утверждение верно для большинства других языков программирования, но в php можно забить на это хуй? Или для чего ОП сделал это уточнение?
#802 #1096133
>>1096127
Просто intval в твоем случае вызывается неявно.
#803 #1096145
Почему я не могу обратиться к protected полю? Ведь класс Analyst наследуется

https://ideone.com/fxnci9
#804 #1096146
>>1095564
>>1095440
Есть на странице ссылка <a href="localhost/link1">Link1<a>
Клиент переходит по ссылке и попадает на скрипт в котором написано header('Location: link2');
В конечном итоге клиент перейдет по одной ссылке, а попадет на другую.
Так? Или я не правильно понял вопрос?
#805 #1096147
>>1096146
Не, все намного сложнее:

Главная страница:

поле ввода оригинальной ссылки.
кнопка сгенерировать
При нажатии на кнопку пользователю отдается сокращенная ссылка. Переход по ссылке редиректит на оригинальный uri.

Как генерировать и записывать в БД я понял, а вот дальше...
#806 #1096150
>>1096147
Окей. У тебя в базе есть таблица вида: id | короткая ссылка | оригинальная ссылка. Наверное любой фреймворк имеет маршрутизатор URL. Создаешь маршрут с параметром, в который попадает необходимая часть ссылки. Маршрут отправляет эту часть ссылки в качестве аргумента контроллеру. Контроллер обращается к базе с запросом на выборку записи, у которой в поле "короткая ссылка" будет то, что было передано в качестве аргумента. Контроллеру возвращается запись из базы. Ты из нее берешь оригинальную ссылку и передаешь обратно клиенту. Так?
#807 #1096160
>>1096147

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

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

Ты бы мог сделать сокращалку ссылок с MVC, лучшими практиками и тд.
#808 #1096171
>>1096150
Честно, я даже не понял, что ты написал. На ютубе я нашел несколько видосов о ЧПУ, но там все было в статичной форме.

>>1096160

>или по работе и качество не важно?


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

https://github.com/codedokode/pasta/blob/master/student-list.md
Ты это имеешь ввиду?

>Ты бы мог сделать сокращалку ссылок с MVC, лучшими практиками и тд.


Прости, не понимаю тебя.

Так-то я уже пришел к осознанию, что эта вакансия не для меня нынешнего и уже намыливаюсь на место попроще, но хочу убить монстра.
#809 #1096173
>>1095651
Ты б хоть объяснил что не так и как надо. Я ж если переделаю, то точно так же.
#810 #1096210
>>1096127
не надо забивать хуй, хорошим тоном является заботиться о типах и делать проверки из серии "является ли переменная числом", что в случае Php означает "можно ли привести переменную к числу". то есть проверка на то, содержит ли переменная только числа, знак и точку.

также с семерки появилась директива declare(strict_types=1), которая делает его жестко типизированным в рамках файла, в котором эта директива объявлена
#811 #1096213
>>1096171

>эта вакансия не для меня нынешнего


Ну судя по всему да.
#812 #1096228
>>1096049
Окей, вот он.
<FilesMatch ".+\.ph(p[3457]?|t|tml)$">
SetHandler application/x-httpd-php
</FilesMatch>
<FilesMatch ".+\.phps$">
SetHandler application/x-httpd-php-source
# Deny access to raw php sources by default
# To re-enable it's recommended to enable access to the files
# only in specific virtual host or directory
Require all denied
</FilesMatch>
# Deny access to files without filename (e.g. '.php')
<FilesMatch "^\.ph(p[3457]?|t|tml|ps)$">
Require all denied
</FilesMatch>

# Running PHP scripts in user directories is disabled by default
#
# To re-enable PHP in user directories comment the following lines
# (from <IfModule ...> to </IfModule>.) Do NOT set it to On as it
# prevents .htaccess files from disabling it.
<IfModule mod_userdir.c>
<Directory /home/*>
php_admin_flag engine On
</Directory>
</IfModule>

>>1096088
Там не то. Там используется mod_userdir для апача, который позволяет хостить сайты на одном домене пользователям под разными директориями формата домен/юзер, при этом не трогая сам апач. Мне же нужно сделать много доменов, чтобы сайты на эти различные домены могли админить разные юзеры, т.е.
1 айпишник, domain1 = user1, domain2 = user2, и в /home/ для каждого пользователя своя папка.
Но не в этом дело, а в том, что почему-то интерпретатор игнорирует php код, если он не в стандартной /var/www/.
#812 #1096228
>>1096049
Окей, вот он.
<FilesMatch ".+\.ph(p[3457]?|t|tml)$">
SetHandler application/x-httpd-php
</FilesMatch>
<FilesMatch ".+\.phps$">
SetHandler application/x-httpd-php-source
# Deny access to raw php sources by default
# To re-enable it's recommended to enable access to the files
# only in specific virtual host or directory
Require all denied
</FilesMatch>
# Deny access to files without filename (e.g. '.php')
<FilesMatch "^\.ph(p[3457]?|t|tml|ps)$">
Require all denied
</FilesMatch>

# Running PHP scripts in user directories is disabled by default
#
# To re-enable PHP in user directories comment the following lines
# (from <IfModule ...> to </IfModule>.) Do NOT set it to On as it
# prevents .htaccess files from disabling it.
<IfModule mod_userdir.c>
<Directory /home/*>
php_admin_flag engine On
</Directory>
</IfModule>

>>1096088
Там не то. Там используется mod_userdir для апача, который позволяет хостить сайты на одном домене пользователям под разными директориями формата домен/юзер, при этом не трогая сам апач. Мне же нужно сделать много доменов, чтобы сайты на эти различные домены могли админить разные юзеры, т.е.
1 айпишник, domain1 = user1, domain2 = user2, и в /home/ для каждого пользователя своя папка.
Но не в этом дело, а в том, что почему-то интерпретатор игнорирует php код, если он не в стандартной /var/www/.
#813 #1096235
>>1094211

>Ты сделал все поля одного типа. Это не годится.


Пофиксил

>Также, если ты хочешь хранить пароли в базе, надо прочесть урок про хранение паролей: >https://github.com/codedokode/pasta/blob/master/security/password-hashing.md


Смотри: у меня denwer php 5.3, я могу сделать рандомную соль и захешировать с ней пароль в бд, а потом как проверить полученный пасс из бд с ведённым, ведь я захешировал в помощью crypt() обратно расхешировать я не могу, более того там рандомная соль, а вот в php 5.5+ есть password_verify(), которая автоматом проверяет хеш и рандомную соль, выход ставить php 5.5+ или как мне поступить?
#814 #1096252
>>1096173

>


> Аноним 22/11/17 Срд 18:15:00 №1096173


>>>1095651


>Ты б хоть объяснил что не так и как надо. Я ж если переде


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

ты в конструкторе пишешь
$this->left = null;
$this->right = null;
$this->value = null;
$this->leaf = false;
а почему не сделать эти нуллы значением по умолчанию при объявлении свойства, а потом переопределять при необходимости?

почему две первые функции не часть класса?

сравнение лучше везде делать строгим.

в целом очень тяжело для чтения. названия переменных и методов везде выбраны такие, что нихуя непонятно.
"toCalc" - почему не input? чем calculate отличается от compute?

function isPossible($toCheck) - по сигнатуре вообще непонятно, что она проверяет. isValid($expression) и то будет понятнее. или там $nestedExpression.
аналогично
trimpars($toTrim)

private function compute(){
if($this->isLeaf()) return;
...

ретурн внутри функции - это не break и не continue. либо изменяй состояние и возвращай тру в случае успеха (и эксепшн в случае неудачи), либо не возвращай ничего. а у тебя получается хз чего от нее ждать
к коду принято писать phpdoc и к такому методу он будет @returns null|void, что не айс. лучше разбить на разные методы.

так не пишут if($this->isLeaf()) return;
это не js, пиши с фигурными скобочками, даже если одно условие, и с пробелами после if.
#814 #1096252
>>1096173

>


> Аноним 22/11/17 Срд 18:15:00 №1096173


>>>1095651


>Ты б хоть объяснил что не так и как надо. Я ж если переде


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

ты в конструкторе пишешь
$this->left = null;
$this->right = null;
$this->value = null;
$this->leaf = false;
а почему не сделать эти нуллы значением по умолчанию при объявлении свойства, а потом переопределять при необходимости?

почему две первые функции не часть класса?

сравнение лучше везде делать строгим.

в целом очень тяжело для чтения. названия переменных и методов везде выбраны такие, что нихуя непонятно.
"toCalc" - почему не input? чем calculate отличается от compute?

function isPossible($toCheck) - по сигнатуре вообще непонятно, что она проверяет. isValid($expression) и то будет понятнее. или там $nestedExpression.
аналогично
trimpars($toTrim)

private function compute(){
if($this->isLeaf()) return;
...

ретурн внутри функции - это не break и не continue. либо изменяй состояние и возвращай тру в случае успеха (и эксепшн в случае неудачи), либо не возвращай ничего. а у тебя получается хз чего от нее ждать
к коду принято писать phpdoc и к такому методу он будет @returns null|void, что не айс. лучше разбить на разные методы.

так не пишут if($this->isLeaf()) return;
это не js, пиши с фигурными скобочками, даже если одно условие, и с пробелами после if.
#815 #1096290
>>1096160
Кстати, как бы ты генерировал короткий URL, просто цифры в 16-ричном формате? Если мы хотим, чтобы URL'ы были как можно короче хотя бы поначалу.
#816 #1096304
>>1096290
52 английские буквы да 10 цифр. Возводим 62 в куб - получаем 238328, столько ссылок можно нагенерить всего-то из трех символов.
Дальше генеришь три рандомных символа и пишешь в базу эти символы и ссылку. Три символа будут первичным ключом. Если прилетает эксепшн, что такой ключ уже есть - перегенерация ключа.
#817 #1096416
А на какой мы уже странице? Скоро придется сделать перекат видимо.

>>1096290

По идее у каждой ссылки есть свой номер. Чтобы он занимал меньше места, можно вместо десятичной системы счисления (где всего 10 цифр) использовать системы счисления с большим основанием, например, base64. В этой системе счисления используется 64 символа, представляющих "цифры" от 0 до 63. Номер ссылки преобразуется в 64-ричную систему счисления.

https://en.wikipedia.org/wiki/Base64

При этом важно выбирать символы, которые допустимы в URL, и не требуют процентного кодирования (так как тогда они займут больше места). Список таких символов описан тут: https://ru.wikipedia.org/wiki/URL#Кодирование_URL

base64 имеет тот недостаток, что в ней есть похожие символы (l и I, 0 и O) и их легко перепутать при ручном наборе. Есть система base58, в которой такие символы убраны.

В base64 в слове получается смесь заглавных и маленьких букв. Если это нежелательно, можно использовать упрощенную систему, например из 36 символов (0-9, a-z).

Формулы преобразования числа в другую систему счисления при желании нетрудно найти.

Чем больше основание системы счисления, тем короче будет записываться номер.

Такой подход, впрочем, имеет особенность, что можно организовать последовательный перебоор номеров и получить все ссылки, которые есть в сервисе. Если это нежелательно, вместо последовательных номеров надо генерировать длинные случайные, но тогда теряется смысл сокращения ссылок. Однако, в других случаях возможность перебора номеров может быть уязвимостью.
#818 #1096417
>>1091538

Калькулятор

> public function __construct(){


> $this->left = null;


Вместо этого можно просто поставить полям значения по умолчанию:

public $left = null;

Но значение по умолчанию, если оно не указано, и так равно null, так что можно даже это не писать

У тебя объект TreeCalc представляет одновременно и узел дерва выражения ( http://aliev.me/runestone/Trees/ParseTree.html ) и содержит код для разбора выражения. Это не очень логично, ты возлагаешь на один класс 2 разных задачи. Лучше было бы наверно сделать отдельно класс-узел дерева и отдельно класс-парсер выражений.

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

Поле value очень непонятное: сначала оно хранит знак операции, а потом - результат вычисления. Это делает написание кода трудным: как мне понять, что хранится в этом поле: еще знак операции, или там уже результат? Как мне понять, что именно вернет getValue() ? Не делай так, сделай разные поля. Более того, результат вообще хранить не нужно - его можно всегда вычислить при необходимости.

Как следствие, если 2 раза вызвать compute(), произойдет ошибка. Лучше писать код, чтобы такое было бы невозможно.

Алгоритм парсера понять трудно. Используются переменные с сокращенными именами, нет комментариев, нет описания. Что такое $weight, например? Из кода это не понять. Или переменная $tok - можно подумать, что она значит "токен", но в нее записывается позиция в строке ($i).

Функции надо называть лучше. Не "isPossible", а "areBracketsBalanced".

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

Как я понимаю, твой парсер работает методом "деления" выражения пополам по первому найденному знаку с наименьшим приоритетом (наибольшим "весом" в твоих терминах).

Тут есть такие проблемы:

1) операция ^ правоассоциативна, то есть 2 ^ 3 ^ 4 значит 2 ^ (3 ^ 4) - учел ли ты это? В рамках твоего алгоритма это, конечно, возможно исправить.
2) вот тут вот в value могут попасть скобки:

> if($weight==-1){


> $this->leaf = true;


> $this->value = $inputString;


Если мы имеем выражение "(1)" то в value запишется число со скобками.

3) не поддерживается оператор "унарный минус", которые использован в выражении "-(2 + 2)". Также, некоторые языки для симметрии поддерживают и "унарный плюс", в стиле "+(1)".

Также, твой "велосипедный" парсер имеет тот недостаток, что он не очень эффективен: он разбирает одну и ту же часть строки много раз, в зависимости от глубины дерева выражения. Лучше, я думаю, изучить существующие алгоритмы.

Традиционно разбор выражения делают в 2 этапа:

1) В рамках лексического анализа лексер (токенайзер) разбивает выражение на токены (лексемы): "-(22 + 2) ^ 3 ^ 4" -> ['-', '(', '22', '+', '2', ')', '^', '3', '^', '4']. На этом этапе числа группируются в токен, удаляются незначащие символы. Токен может быть представлен строкой, массивом, объектом, в зависимости от задачи.

2) В рамках синтаксического анализа парсер получает на вход поток токенов и строит дерево выражения их узлов. Тут есть разные алгоритмы: https://ru.wikipedia.org/wiki/Синтаксический_анализ

Для твоей задачи самым простым будет метод "рекурсивного спуска". На вход алгоритм получает "поток токенов", на выходе выдает дерево выражения.

Мы представляем поток токенов в виде некоей сущности tokens (это может быть объект, итератор, и тд), которая поддерживает по сути 2 операции: "подглядеть" текущий токен (peek) и "поглотить" (consume) текущий токен с переходом к следующему. Таким образом, парсер читает последовательность токенов за один проход и никогда не "отступает" назад. Это позволяет нам подсоединить выход лексера так, что мы не накапливаем массив токенов, а сразу же разбираем их по мере получения.

Для начала, мы записываем "грамматику", то есть полный набор правил, по которым разбираются выражения, начиная с верхнего уровня. Я использую синтаксис ABNF ( https://en.wikipedia.org/wiki/Augmented_Backus–Naur_form , советую почитать также про BNF и EBNF):

-------

; "операнд" может быть одной их перечисленных ниже конструкций
; ЧИСЛО - это один токен, который далее не делится на части (терминал)
операнд = ЧИСЛО / "(" выражение ")" / унарный-минус / унарный-плюс

унарный-минус = "-" операнд
унарный-плюс = "+" операнд

; * значит, что выражение в скобках повторяется сколько угодно раз,
; то есть конструкция "степень" может содержать много операндов и знаков ^,
; а может состоять из одного операнда без знака ^
степень-или-операнд = операнд *( "^" операнд )

; произведение - это набор конструкций "степень", разделенный
; знаками деления и умножения
произведение = степень-или-операнд *( ( "*" / "/" ) степень-или-операнд ) 
сумма = произведение *( ( "+" / "-" ) произведение ) 

выражение = сумма

-------

Читать правила удобнее снизу вверх (а писать - наоборот).

Эти правила по сути задают алгоритм разбора той или иной конструкции. Ну например, правило 'операнд = ЧИСЛО / "(" выражение ")" / унарный-минус / унарный-плюс' значит следующее:

Когда мы хотим разобрать конструкцию "операнд", мы должны:

- проверить, является ли токен ЧИСЛОм ? Если да - создаем из него узел и разбор закончен
- является ли первый токен скобкой? Если да, поглощаем его, затем вызываем правило разбора "выражение", затем поглощаем закрывающую скобку
- является ли первый токен минусом? Если да, разбираем конструкцию "унарный-минус"
- является ли первый токен плюсом? Если да, разбираем конструкцию "унарный-плюс"
- иначе, выдаем синтаксическую ошибку

Правило 'сумма = произведение *( ( "+" / "-" ) произведение )' надо читать так:

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

Эти правила можно записать и по-другому. Например, "степень-или-операнд" можно сформулировать так:

; правоассоциативное выражение
степень-или-операнд = операнд "^" степень-или-операнд / операнд

; левоассоциативное
произведение = степень-или-операнд "*" произведение / степень-или-операнд "/" произведение / степень-или-операнд

Возвращаясь к методу "рекурсивного спуска". В нем мы для каждого правила пишем соответствующую функцию. Она выглядит так:

function parseSomething(tokens): [Node, tokens]

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

Если она не может распарсить поток токенов, она сигнализирует о синтаксической ошибке. Функция может вызывать другие функции для разбора конструкций (отсюда и название "спуск").

Если взять правила выше, то у нас будут функции:

parseOperand
parseUnaryMinus
parseUnaryPlus
parsePower
parseMultiplication
parseSum = parseExpression

Опишу для примера алгоритм функции parseOperand(tokens):

- если текущий токен == ЧИСЛО, то создаем узел типа NumberNode и возвращаем
- если текущий токен = "(", то поглощаем его, вызываем parseExpression и поглощам идущий далее токен ")"
- если текущий токен - знак минус, то, вызываем parseUnaryMinus
- если текущий токен - знак плюс, то вызвыаем parseUnaryPlus

Мои правила предполагают, что узел может содержать не 2, а более детей. То есть для выражения "2 + 4 - 3" я создаю один узел SumNode с 3 детьми: 2, 4 и 3. Но это можно поменять и на узлы с 2 детьми, это не принципиально.

Я советую попробовать реализовать метод "рекурсивного спуска".

Если хочешь усложнить задачу, попробуй добавить в выражение: дроби (1/3), функции (sin(x)). Также, можешь попробовать сделать парсер какого-нибудь языка программирования, например, урезанной версии PHP, поддерживающей переменные, функции, конструкции if и for. Начать можешь с описания грамматики.
#818 #1096417
>>1091538

Калькулятор

> public function __construct(){


> $this->left = null;


Вместо этого можно просто поставить полям значения по умолчанию:

public $left = null;

Но значение по умолчанию, если оно не указано, и так равно null, так что можно даже это не писать

У тебя объект TreeCalc представляет одновременно и узел дерва выражения ( http://aliev.me/runestone/Trees/ParseTree.html ) и содержит код для разбора выражения. Это не очень логично, ты возлагаешь на один класс 2 разных задачи. Лучше было бы наверно сделать отдельно класс-узел дерева и отдельно класс-парсер выражений.

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

Поле value очень непонятное: сначала оно хранит знак операции, а потом - результат вычисления. Это делает написание кода трудным: как мне понять, что хранится в этом поле: еще знак операции, или там уже результат? Как мне понять, что именно вернет getValue() ? Не делай так, сделай разные поля. Более того, результат вообще хранить не нужно - его можно всегда вычислить при необходимости.

Как следствие, если 2 раза вызвать compute(), произойдет ошибка. Лучше писать код, чтобы такое было бы невозможно.

Алгоритм парсера понять трудно. Используются переменные с сокращенными именами, нет комментариев, нет описания. Что такое $weight, например? Из кода это не понять. Или переменная $tok - можно подумать, что она значит "токен", но в нее записывается позиция в строке ($i).

Функции надо называть лучше. Не "isPossible", а "areBracketsBalanced".

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

Как я понимаю, твой парсер работает методом "деления" выражения пополам по первому найденному знаку с наименьшим приоритетом (наибольшим "весом" в твоих терминах).

Тут есть такие проблемы:

1) операция ^ правоассоциативна, то есть 2 ^ 3 ^ 4 значит 2 ^ (3 ^ 4) - учел ли ты это? В рамках твоего алгоритма это, конечно, возможно исправить.
2) вот тут вот в value могут попасть скобки:

> if($weight==-1){


> $this->leaf = true;


> $this->value = $inputString;


Если мы имеем выражение "(1)" то в value запишется число со скобками.

3) не поддерживается оператор "унарный минус", которые использован в выражении "-(2 + 2)". Также, некоторые языки для симметрии поддерживают и "унарный плюс", в стиле "+(1)".

Также, твой "велосипедный" парсер имеет тот недостаток, что он не очень эффективен: он разбирает одну и ту же часть строки много раз, в зависимости от глубины дерева выражения. Лучше, я думаю, изучить существующие алгоритмы.

Традиционно разбор выражения делают в 2 этапа:

1) В рамках лексического анализа лексер (токенайзер) разбивает выражение на токены (лексемы): "-(22 + 2) ^ 3 ^ 4" -> ['-', '(', '22', '+', '2', ')', '^', '3', '^', '4']. На этом этапе числа группируются в токен, удаляются незначащие символы. Токен может быть представлен строкой, массивом, объектом, в зависимости от задачи.

2) В рамках синтаксического анализа парсер получает на вход поток токенов и строит дерево выражения их узлов. Тут есть разные алгоритмы: https://ru.wikipedia.org/wiki/Синтаксический_анализ

Для твоей задачи самым простым будет метод "рекурсивного спуска". На вход алгоритм получает "поток токенов", на выходе выдает дерево выражения.

Мы представляем поток токенов в виде некоей сущности tokens (это может быть объект, итератор, и тд), которая поддерживает по сути 2 операции: "подглядеть" текущий токен (peek) и "поглотить" (consume) текущий токен с переходом к следующему. Таким образом, парсер читает последовательность токенов за один проход и никогда не "отступает" назад. Это позволяет нам подсоединить выход лексера так, что мы не накапливаем массив токенов, а сразу же разбираем их по мере получения.

Для начала, мы записываем "грамматику", то есть полный набор правил, по которым разбираются выражения, начиная с верхнего уровня. Я использую синтаксис ABNF ( https://en.wikipedia.org/wiki/Augmented_Backus–Naur_form , советую почитать также про BNF и EBNF):

-------

; "операнд" может быть одной их перечисленных ниже конструкций
; ЧИСЛО - это один токен, который далее не делится на части (терминал)
операнд = ЧИСЛО / "(" выражение ")" / унарный-минус / унарный-плюс

унарный-минус = "-" операнд
унарный-плюс = "+" операнд

; * значит, что выражение в скобках повторяется сколько угодно раз,
; то есть конструкция "степень" может содержать много операндов и знаков ^,
; а может состоять из одного операнда без знака ^
степень-или-операнд = операнд *( "^" операнд )

; произведение - это набор конструкций "степень", разделенный
; знаками деления и умножения
произведение = степень-или-операнд *( ( "*" / "/" ) степень-или-операнд ) 
сумма = произведение *( ( "+" / "-" ) произведение ) 

выражение = сумма

-------

Читать правила удобнее снизу вверх (а писать - наоборот).

Эти правила по сути задают алгоритм разбора той или иной конструкции. Ну например, правило 'операнд = ЧИСЛО / "(" выражение ")" / унарный-минус / унарный-плюс' значит следующее:

Когда мы хотим разобрать конструкцию "операнд", мы должны:

- проверить, является ли токен ЧИСЛОм ? Если да - создаем из него узел и разбор закончен
- является ли первый токен скобкой? Если да, поглощаем его, затем вызываем правило разбора "выражение", затем поглощаем закрывающую скобку
- является ли первый токен минусом? Если да, разбираем конструкцию "унарный-минус"
- является ли первый токен плюсом? Если да, разбираем конструкцию "унарный-плюс"
- иначе, выдаем синтаксическую ошибку

Правило 'сумма = произведение *( ( "+" / "-" ) произведение )' надо читать так:

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

Эти правила можно записать и по-другому. Например, "степень-или-операнд" можно сформулировать так:

; правоассоциативное выражение
степень-или-операнд = операнд "^" степень-или-операнд / операнд

; левоассоциативное
произведение = степень-или-операнд "*" произведение / степень-или-операнд "/" произведение / степень-или-операнд

Возвращаясь к методу "рекурсивного спуска". В нем мы для каждого правила пишем соответствующую функцию. Она выглядит так:

function parseSomething(tokens): [Node, tokens]

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

Если она не может распарсить поток токенов, она сигнализирует о синтаксической ошибке. Функция может вызывать другие функции для разбора конструкций (отсюда и название "спуск").

Если взять правила выше, то у нас будут функции:

parseOperand
parseUnaryMinus
parseUnaryPlus
parsePower
parseMultiplication
parseSum = parseExpression

Опишу для примера алгоритм функции parseOperand(tokens):

- если текущий токен == ЧИСЛО, то создаем узел типа NumberNode и возвращаем
- если текущий токен = "(", то поглощаем его, вызываем parseExpression и поглощам идущий далее токен ")"
- если текущий токен - знак минус, то, вызываем parseUnaryMinus
- если текущий токен - знак плюс, то вызвыаем parseUnaryPlus

Мои правила предполагают, что узел может содержать не 2, а более детей. То есть для выражения "2 + 4 - 3" я создаю один узел SumNode с 3 детьми: 2, 4 и 3. Но это можно поменять и на узлы с 2 детьми, это не принципиально.

Я советую попробовать реализовать метод "рекурсивного спуска".

Если хочешь усложнить задачу, попробуй добавить в выражение: дроби (1/3), функции (sin(x)). Также, можешь попробовать сделать парсер какого-нибудь языка программирования, например, урезанной версии PHP, поддерживающей переменные, функции, конструкции if и for. Начать можешь с описания грамматики.
#819 #1096420
>>1091538

Для сложных случаев есть генераторы парсеров (ANTLR и другие). ты даешь им грамматику и они по ней генерируют код парсера. "Взрослые" парсеры для компьютерных программ делаются по такому принципу, так как вручную их писать долго и легко ошибиться.
#820 #1096422
>>1096235

> у меня denwer php 5.3,


Вообще, это очень старая версия. Нужно хотя бы 5.6, а лучше - 7.1

> я могу сделать рандомную соль и захешировать с ней пароль в бд, а потом как проверить полученный пасс из бд с ведённым, ведь я захешировал в помощью crypt() обратно расхешировать я не могу,


Ты сохраняешь в базу соль и хеш. При получении пароля от пользователя хешируешь его с той же солью и сравниваешь хеши.

> а вот в php 5.5+ есть password_verify(), которая автоматом проверяет хеш и рандомную соль


Она просто в хеш включает соль, в стиле 'версия алгоритма$соль$хеш'. Ты можешь их просто хранить по отдельности.

> ставить php 5.5+


Если есть возможность то да, если нет - то я написал выше решение.

Типы полей пока выбраны неправильно. Ну например, TEXT позволяет сохранить до 65536 байт (то есть около 16 000 символов), неужели в логине их может быть так много? Нужно использовать VARCHAR с ограничением длины.

email должен быть уникален.

grup пишется как group.

> ENUM('local1','local2')


Названия не годятся, так как непонятно, что они значат. Нужны более удачные названия. Ну хотя бы resident/foreign или yes/no

>>1096228

Ты PHP код пишешь в файле с расширением php, не html? Апач перезапустил? Он на самом деле перезапустился?
#820 #1096422
>>1096235

> у меня denwer php 5.3,


Вообще, это очень старая версия. Нужно хотя бы 5.6, а лучше - 7.1

> я могу сделать рандомную соль и захешировать с ней пароль в бд, а потом как проверить полученный пасс из бд с ведённым, ведь я захешировал в помощью crypt() обратно расхешировать я не могу,


Ты сохраняешь в базу соль и хеш. При получении пароля от пользователя хешируешь его с той же солью и сравниваешь хеши.

> а вот в php 5.5+ есть password_verify(), которая автоматом проверяет хеш и рандомную соль


Она просто в хеш включает соль, в стиле 'версия алгоритма$соль$хеш'. Ты можешь их просто хранить по отдельности.

> ставить php 5.5+


Если есть возможность то да, если нет - то я написал выше решение.

Типы полей пока выбраны неправильно. Ну например, TEXT позволяет сохранить до 65536 байт (то есть около 16 000 символов), неужели в логине их может быть так много? Нужно использовать VARCHAR с ограничением длины.

email должен быть уникален.

grup пишется как group.

> ENUM('local1','local2')


Названия не годятся, так как непонятно, что они значат. Нужны более удачные названия. Ну хотя бы resident/foreign или yes/no

>>1096228

Ты PHP код пишешь в файле с расширением php, не html? Апач перезапустил? Он на самом деле перезапустился?
#821 #1096424
>>1096171

Да, я тебе советую либо решать задачу про студентов, либо писать сокращалку с использованием описанных в задаче подходов. Во многих учебниках тебе о тех вещах, которые у меня описаны, толком не расскажут. А без этих знаний работать с современными фреймворками будет очень трудно (даже если ты прочтешь каике-то уроки для "чайников", ты все равно толком ничего не поймешь), а без них ты толком никуда не сможешь устроиться.

Другие аноны, решавшие эту задачу, потом смогли освоить Симфони или Юи.

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

Также, есть еще такой урок: https://github.com/codedokode/pasta/blob/master/soft/web-server.md - может он пригодится.

Также, тебе надо изучить хотя бы основы HTML.

А что именно-то тебе непонятно? Из твоих постов не очень очевидно.
#822 #1096425
>>1096145

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

Бонусом дам пасту про инкапсуляцию:

------------------------------

Инкапсуляция. У этого слова есть разные определения, в том числе такие что ничего не понять, потому объясню простыми словами.

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

Это упрощает понимание кода: тебе не надо читать и разбирать код класса, достаточно прочитать название метода (и может быть комментарий к нему). Также, это упрощает изменение кода: если какое-то свойство имеет уровень private то доступ к нему возможен только из того же класса и тебе не надо бегать по всему коду и смотреть что там с этим свойством делается, тебе достаточно просмотреть один файл с этим классом.

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

Инкапсуляция это хорошо. Так как весь код, который занимается одной задачей, оказывается заключен внутри одного класса. Противоположный случай это когда код (или знание о его внутреннем устройстве) вылезает из класса и размазывается по всей программе.

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

Лучше наверно привести пример, чем обсуждать абстрактные вещи. Допустим, мы решили представить ломаную линию из нескольких отрезков (например, маршрут на карте) в виде объекта. Для начала, мы спроектируем, что можно будет делать с нашим объектом:

- создать, указав начальную точку (мы решили, что ломаная линия, не содержащая ни одной точки, невозможна, потому требуем передать начальные координаты в конструктор. Я сейчас не могу сказать как выгоднее - разрешить линии без точек вообще, требовать наличие минимум одной или требовать минимум 2 точки. Это надо сравнивать)
- добавить еще одну точку к линии
- найти длину линии (т.е сумму длин всех ее отрезков)

Теперь, имея этот список, мы можем написать класс PolyLine:

class PolyLine
{
// Массив со списком точек
private $points = [];

public function __construct($x, $y)
{
$this->points[] = [$x, $y];
}

public function addPoint($x, $y)
{
$this->points[] = [$x, $y];
}

/ Посчитать общую длину линии */
public function calculateLength()
{
$length = 0;
for ($i = 1; $i < count($this->points)) {
$length += $this->calculateSegmentLength(
$this->points[$i - 1][0],
$this->points[$i - 1][1],
$this->points[$i][0],
$this->points[$i][1]
);
}

return $length;
}

private function calculateSegmentlength($x1, $y1, $x2, $y2) { ... }
}

Вот в этом классе мы делаем публичными только те методы, которые запроектировали выше. А все остальное мы закрываем. Например, мы закрываем от доступа снаружи массив points. Это имеет такие преимущества:

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

Ну например завтра мы решим что хранить координаты точки удобнее не в числовом массиве [$x, $y], а в таком ['x' => $x, 'y' => $y]. Или в виде объектов класса Point. И так как этот массив у нас приватный, мы можем смело менять его и нам не придется править код снаружи класса PolyLine так как изменилась только внутренняя реализация, а внешний интерфейс остался таким же.

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

До ООП зачастую никакой инкапсуляции и не было, код состоял из функций и глобальных переменных, и можно было обращаться к любой. По мере роста объема программы разбираться в этом было сложнее. И разделение кода на классы нужно для того, чтобы справиться с этой сложностью, чтобы огромная программа могла бы оставаться относительно понятной, чтобы мы могли рассмтаривать класс отдельно от остального кода.
#822 #1096425
>>1096145

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

Бонусом дам пасту про инкапсуляцию:

------------------------------

Инкапсуляция. У этого слова есть разные определения, в том числе такие что ничего не понять, потому объясню простыми словами.

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

Это упрощает понимание кода: тебе не надо читать и разбирать код класса, достаточно прочитать название метода (и может быть комментарий к нему). Также, это упрощает изменение кода: если какое-то свойство имеет уровень private то доступ к нему возможен только из того же класса и тебе не надо бегать по всему коду и смотреть что там с этим свойством делается, тебе достаточно просмотреть один файл с этим классом.

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

Инкапсуляция это хорошо. Так как весь код, который занимается одной задачей, оказывается заключен внутри одного класса. Противоположный случай это когда код (или знание о его внутреннем устройстве) вылезает из класса и размазывается по всей программе.

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

Лучше наверно привести пример, чем обсуждать абстрактные вещи. Допустим, мы решили представить ломаную линию из нескольких отрезков (например, маршрут на карте) в виде объекта. Для начала, мы спроектируем, что можно будет делать с нашим объектом:

- создать, указав начальную точку (мы решили, что ломаная линия, не содержащая ни одной точки, невозможна, потому требуем передать начальные координаты в конструктор. Я сейчас не могу сказать как выгоднее - разрешить линии без точек вообще, требовать наличие минимум одной или требовать минимум 2 точки. Это надо сравнивать)
- добавить еще одну точку к линии
- найти длину линии (т.е сумму длин всех ее отрезков)

Теперь, имея этот список, мы можем написать класс PolyLine:

class PolyLine
{
// Массив со списком точек
private $points = [];

public function __construct($x, $y)
{
$this->points[] = [$x, $y];
}

public function addPoint($x, $y)
{
$this->points[] = [$x, $y];
}

/ Посчитать общую длину линии */
public function calculateLength()
{
$length = 0;
for ($i = 1; $i < count($this->points)) {
$length += $this->calculateSegmentLength(
$this->points[$i - 1][0],
$this->points[$i - 1][1],
$this->points[$i][0],
$this->points[$i][1]
);
}

return $length;
}

private function calculateSegmentlength($x1, $y1, $x2, $y2) { ... }
}

Вот в этом классе мы делаем публичными только те методы, которые запроектировали выше. А все остальное мы закрываем. Например, мы закрываем от доступа снаружи массив points. Это имеет такие преимущества:

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

Ну например завтра мы решим что хранить координаты точки удобнее не в числовом массиве [$x, $y], а в таком ['x' => $x, 'y' => $y]. Или в виде объектов класса Point. И так как этот массив у нас приватный, мы можем смело менять его и нам не придется править код снаружи класса PolyLine так как изменилась только внутренняя реализация, а внешний интерфейс остался таким же.

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

До ООП зачастую никакой инкапсуляции и не было, код состоял из функций и глобальных переменных, и можно было обращаться к любой. По мере роста объема программы разбираться в этом было сложнее. И разделение кода на классы нужно для того, чтобы справиться с этой сложностью, чтобы огромная программа могла бы оставаться относительно понятной, чтобы мы могли рассмтаривать класс отдельно от остального кода.
#823 #1096426
>>1096120

В PHP "1234" и 1234 - это разные вещи. Первое - строка из 4 символов, второе - число типа int (то есть целое небольшое число, а бывает еще float).

intval преобразует значение из строки в int.

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


Это потому, что PHP сам за тебя преобразовал строку в число. Но это может работать не всегда так, как ты хочешь, и не отменяет того, что иногда мы хотим явно сделать это преобразование.

http://php.net/manual/ru/language.types.type-juggling.php

Это может приводить к тому, что ошибки в коде труднее найти:

$partType = "engine";
$partPrice = 400;

// опечатка: должно быть partPrice
$total = 1000 + $partType;

Этот код не выдаст ошибки, а просто преобразует 'engine' в 0 и даст неверный результат. Лучше было бы, если бы PHP сообщил об ошибке и мы сразу бы ее исправили. А так, этот неверный результат может куда-то сохраниться и найти и исправить последствия будет сложнее. То есть разработчики PHP выбрали неудачный подход, который скрывает ошибки. Это плохо.

Бороться с этим можно в PHP7 за счет тайп-хинтов:

// здесь строка "engine" не пройдет
function add(int $a, int %b)

Более того, сравнения значений разных типов могут вообще работать неожиданно:

var_dump("car" == 0);

> bool(true)



То есть PHP считает что "car" и 0 - это примерно одно и то же (он неявно преобразовал "car" в число). Замена == на === решит проблему:

var_dump("car" === 0);

> false

#823 #1096426
>>1096120

В PHP "1234" и 1234 - это разные вещи. Первое - строка из 4 символов, второе - число типа int (то есть целое небольшое число, а бывает еще float).

intval преобразует значение из строки в int.

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


Это потому, что PHP сам за тебя преобразовал строку в число. Но это может работать не всегда так, как ты хочешь, и не отменяет того, что иногда мы хотим явно сделать это преобразование.

http://php.net/manual/ru/language.types.type-juggling.php

Это может приводить к тому, что ошибки в коде труднее найти:

$partType = "engine";
$partPrice = 400;

// опечатка: должно быть partPrice
$total = 1000 + $partType;

Этот код не выдаст ошибки, а просто преобразует 'engine' в 0 и даст неверный результат. Лучше было бы, если бы PHP сообщил об ошибке и мы сразу бы ее исправили. А так, этот неверный результат может куда-то сохраниться и найти и исправить последствия будет сложнее. То есть разработчики PHP выбрали неудачный подход, который скрывает ошибки. Это плохо.

Бороться с этим можно в PHP7 за счет тайп-хинтов:

// здесь строка "engine" не пройдет
function add(int $a, int %b)

Более того, сравнения значений разных типов могут вообще работать неожиданно:

var_dump("car" == 0);

> bool(true)



То есть PHP считает что "car" и 0 - это примерно одно и то же (он неявно преобразовал "car" в число). Замена == на === решит проблему:

var_dump("car" === 0);

> false

#824 #1096427
>>1096061

Методы могут быть "получить зарплату", "получить потребление кофе" и тд. Или их может не быть, если поля публичные.

Важно помнить, что объект - это данные (поля) + методы для работы с этими данными. Делать поля в одном классе, а методы - в другом может быть не очень логично.

Каждый класс должен иметь свою зону ответственности. Например, Работник отвечает за хранение и вычисление своей зарплаты/кофе, а Департамент - за управление списком работников и за вычисление суммарных расходов.

Алсо, если хочешь еще поучиться проектировать классы, есть задача про продюсерское агенство, попробуй решить: >>1094213 Рекомендую поломать голову. И потом, если этого мало, попросить задачу на ООП про Гостиницу.

>>1095827

ucfirst не работает с utf-8: https://github.com/codedokode/pasta/blob/master/php/strings-utf8.md

Нужно использовать mb-функции, например, отрезать первую букву и перевести ее в верхний регистр.

>>1095789

Урок про неймспейсы: https://github.com/codedokode/pasta/blob/master/php/autoload.md

>>1095749

> Приватные свойства нельзя менять, принимать в качестве аргументов функций, вызывать. Зачем они нужны?


Ты не понял, что такое приватные свойства. private/protected/public задают "видимость" свойства, то есть показывают, из какого места в коде можно обращаться к свойству:

private - только из того же класса, где задано свойство. private свойство "не видно" в других классах и снаружи класса
protected - их того же класса и его наследников
public - из любого места кода

Менять приватные свойства можно, но только изнутри класса.

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

someFunc($this->x); // в функцию передается не свойство x, а записанное в нем значение

> Приватные свойства нельзя ... вызывать


Вызывать можно только методы. Приватные методы можно вызывать только изнутри класса.

Нужно это для повышения качества и понятности кода, защиты от ошибок, за счет инкапсуляции. Я написал про нее очень подробно несколькими постами выше. Обязательно прочти.

Ты правильно делаешь, что задаешь такие вопросы.

Если ты решаешь задачу про Вектор, то давай для закрепления используем в ней инкапсуляцию, то есть сделаем все свойства непубличными и защитим их от записи неправильных значений.
#824 #1096427
>>1096061

Методы могут быть "получить зарплату", "получить потребление кофе" и тд. Или их может не быть, если поля публичные.

Важно помнить, что объект - это данные (поля) + методы для работы с этими данными. Делать поля в одном классе, а методы - в другом может быть не очень логично.

Каждый класс должен иметь свою зону ответственности. Например, Работник отвечает за хранение и вычисление своей зарплаты/кофе, а Департамент - за управление списком работников и за вычисление суммарных расходов.

Алсо, если хочешь еще поучиться проектировать классы, есть задача про продюсерское агенство, попробуй решить: >>1094213 Рекомендую поломать голову. И потом, если этого мало, попросить задачу на ООП про Гостиницу.

>>1095827

ucfirst не работает с utf-8: https://github.com/codedokode/pasta/blob/master/php/strings-utf8.md

Нужно использовать mb-функции, например, отрезать первую букву и перевести ее в верхний регистр.

>>1095789

Урок про неймспейсы: https://github.com/codedokode/pasta/blob/master/php/autoload.md

>>1095749

> Приватные свойства нельзя менять, принимать в качестве аргументов функций, вызывать. Зачем они нужны?


Ты не понял, что такое приватные свойства. private/protected/public задают "видимость" свойства, то есть показывают, из какого места в коде можно обращаться к свойству:

private - только из того же класса, где задано свойство. private свойство "не видно" в других классах и снаружи класса
protected - их того же класса и его наследников
public - из любого места кода

Менять приватные свойства можно, но только изнутри класса.

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

someFunc($this->x); // в функцию передается не свойство x, а записанное в нем значение

> Приватные свойства нельзя ... вызывать


Вызывать можно только методы. Приватные методы можно вызывать только изнутри класса.

Нужно это для повышения качества и понятности кода, защиты от ошибок, за счет инкапсуляции. Я написал про нее очень подробно несколькими постами выше. Обязательно прочти.

Ты правильно делаешь, что задаешь такие вопросы.

Если ты решаешь задачу про Вектор, то давай для закрепления используем в ней инкапсуляцию, то есть сделаем все свойства непубличными и защитим их от записи неправильных значений.
#825 #1096428
>>1095657

Ну, первая проблема в том, что константы хранятся сами по себе - лучше было бы поместить их в какой-то класс, например ... класс WorkerParams. Или их не надо делать константами.

Далее, для этих значений константы использовать довольно неудобно:

> //Количество менеджеров 1 уровня


> const ME_ZAKUPKI_LEVEL1 = 9;


> //Количество менеджеров 2 уровня


> const ME_ZAKUPKI_LEVEL2 = 3;



Гораздо короче было бы сделать массив с парамтерами работников.

В классе Worker ранг лучше хранить в одной переменной, зачем было делать переменные level2 и level3?

Не надо сокращать имена переменных, salary как salar, это плохо смотрится и сбивает с толку.

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

> $level2 = ''


Значение по умолчанию разве не false должно быть? Почему строка?

У тебя есть класс, представляющий Работника, но нет класса, представляющего Депарамент. Из-за этого код расчета суммарных затрат у тебя размазан по приложению. Было бы удобнее собрать его в один класс. А так, у тебя один и тот же код 4 раза скопирован. Копипасты быть не должно. Плюс, если мы захотим добавить один департамент, нам придется копипастить кучу кода. Это плохо.

Также, можно сделать класс, представляющий Компанию.

Имена вроде "$tugrzak" непонятные и не надо их использовать.

Список работников удобнее задать так:

$workers = [
['count' => 10, 'job' => 'Manager', 'rank' => 2],
['count' => 20, 'job' => 'Manager', 'rank' => 1],
...
];

Или так:

$workers = [
// count, job, rank
[10, 'Manager', 2],
[20, 'Manager', 1],
..
]

Или, еще короче, так:

$workers = ['10ma1', '20ma3', ...];

> $allcount = $countzak+$countsell+$countad+$countlogic;


Это нечитаемо. Нет пробелов вокруг плюса, слова в переменных не разделены.

Пока код даже близко не тянет на ООП. Плюс, если ты посмотришь вторую часть задачи (Антикризисный комитет), то ты увидишь, что с твоим кодом вторую часть сделать практически нереально, код будет слишком запутанный. Если не веришь, можешь попробовать.

HTML-код лучше вынести в отдельный шаблон: https://github.com/codedokode/pasta/blob/master/php/templates.md

Если ты хочешь получше потренироваться проектировать классы (рекомендую), ты можешь попробовать решить маленькую задачу про продюсерское агенство: >>1094213 и, если этого мало, попросить задачу про Гостиницу на ООП.

Экранирование

> <a href="index.php?text=<?php echo htmlspecialchars($_GET['text']); ?>&lt=1">ссылка</a>


А ты тестировал эту ссылку, на приведенных в задаче примерах текста? Я могу сказать что при наличии в строке знаков вроде < или & они, скорее всего, обрежутся при открытии ссылки.

Также, ссылка написана неправильно:

> &lt=1


Знак & при вставке в HTML как текст или значение атрибута надо записывать как HTML-мнемонику (& amp ; )

> Вообще не понял что от меня требуется


Требуется правильно использовать функции экранирования, чтобы код корректно работал с любыми строками из любых символов. В задаче даны примеры строк.
#825 #1096428
>>1095657

Ну, первая проблема в том, что константы хранятся сами по себе - лучше было бы поместить их в какой-то класс, например ... класс WorkerParams. Или их не надо делать константами.

Далее, для этих значений константы использовать довольно неудобно:

> //Количество менеджеров 1 уровня


> const ME_ZAKUPKI_LEVEL1 = 9;


> //Количество менеджеров 2 уровня


> const ME_ZAKUPKI_LEVEL2 = 3;



Гораздо короче было бы сделать массив с парамтерами работников.

В классе Worker ранг лучше хранить в одной переменной, зачем было делать переменные level2 и level3?

Не надо сокращать имена переменных, salary как salar, это плохо смотрится и сбивает с толку.

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

> $level2 = ''


Значение по умолчанию разве не false должно быть? Почему строка?

У тебя есть класс, представляющий Работника, но нет класса, представляющего Депарамент. Из-за этого код расчета суммарных затрат у тебя размазан по приложению. Было бы удобнее собрать его в один класс. А так, у тебя один и тот же код 4 раза скопирован. Копипасты быть не должно. Плюс, если мы захотим добавить один департамент, нам придется копипастить кучу кода. Это плохо.

Также, можно сделать класс, представляющий Компанию.

Имена вроде "$tugrzak" непонятные и не надо их использовать.

Список работников удобнее задать так:

$workers = [
['count' => 10, 'job' => 'Manager', 'rank' => 2],
['count' => 20, 'job' => 'Manager', 'rank' => 1],
...
];

Или так:

$workers = [
// count, job, rank
[10, 'Manager', 2],
[20, 'Manager', 1],
..
]

Или, еще короче, так:

$workers = ['10ma1', '20ma3', ...];

> $allcount = $countzak+$countsell+$countad+$countlogic;


Это нечитаемо. Нет пробелов вокруг плюса, слова в переменных не разделены.

Пока код даже близко не тянет на ООП. Плюс, если ты посмотришь вторую часть задачи (Антикризисный комитет), то ты увидишь, что с твоим кодом вторую часть сделать практически нереально, код будет слишком запутанный. Если не веришь, можешь попробовать.

HTML-код лучше вынести в отдельный шаблон: https://github.com/codedokode/pasta/blob/master/php/templates.md

Если ты хочешь получше потренироваться проектировать классы (рекомендую), ты можешь попробовать решить маленькую задачу про продюсерское агенство: >>1094213 и, если этого мало, попросить задачу про Гостиницу на ООП.

Экранирование

> <a href="index.php?text=<?php echo htmlspecialchars($_GET['text']); ?>&lt=1">ссылка</a>


А ты тестировал эту ссылку, на приведенных в задаче примерах текста? Я могу сказать что при наличии в строке знаков вроде < или & они, скорее всего, обрежутся при открытии ссылки.

Также, ссылка написана неправильно:

> &lt=1


Знак & при вставке в HTML как текст или значение атрибута надо записывать как HTML-мнемонику (& amp ; )

> Вообще не понял что от меня требуется


Требуется правильно использовать функции экранирования, чтобы код корректно работал с любыми строками из любых символов. В задаче даны примеры строк.
#826 #1096429
>>1095564

Нужно выдавать HTTP-ответ с редиректом. Например, через функцию header().

Урок по HTTP, не знаю, поможет ли: https://github.com/codedokode/pasta/blob/master/network/http.md

>>1095402

> Можно. Reflection API либо get_class_vars()


И что ты там собрался смотреть? Поля есть только у объектов, а не у классов.

> Теперь у тебя вопрос еще и выводит сам себя. Это перегрузка обязанностями.


В маленьком скрипте вполне допустимо, чтобы не усложнять код. Хотя удобнее наверно делать вывод снаружи.

А вот тебе еще вопрос: если у нас разные типы вопросов требуют разный формат вывода, как ты это сделаешь в QuestionWriter? Чтобы мы могли легко добавлять новые типы вопросов? switch разумеется не годится :)

>>1095395

Было бы лучше, если бы функция checkAnswer ничего не писала, а только возвращала результат - правильно/неправильно. А то если мы захотим просто посчитать сумму баллов, мы этого сделать не сможем (кстати, она у тебя и не считается).

Ну или ее надо переименовать в printCheckResult(...).

deviation в исходной задаче обозначало "погрешность", например, Пи - это 3.14 +/- 0.01, то есть ответ 3.1415 тоже подойдет. Твой вариант больше подходит к текстовым ответам, а не числовым (NumericQuestion).

>>1095139

Нет, метод - это функция в классе, и в скобках пишется список аргументов (переменных), а не свойств:

public function x($a, $b, $c) { .. }

Аргументы $a, $b, $c - это просто переменные, в которые можно при вызове метода передать произвольные значения:

$object->x(100, "text", []);

Они не связаны напрямую со свойствами объекта. Твой код синтаксически неправильный, то есть так писать в принципе нельзя. $this можно использовать только в теле метода.

Обрати внимание, что $this->salary и $salary - это разные вещи. Первое - свойство объекта, второе - переменная. Они никак не связаны, хоть у них и одинаковое название.
#826 #1096429
>>1095564

Нужно выдавать HTTP-ответ с редиректом. Например, через функцию header().

Урок по HTTP, не знаю, поможет ли: https://github.com/codedokode/pasta/blob/master/network/http.md

>>1095402

> Можно. Reflection API либо get_class_vars()


И что ты там собрался смотреть? Поля есть только у объектов, а не у классов.

> Теперь у тебя вопрос еще и выводит сам себя. Это перегрузка обязанностями.


В маленьком скрипте вполне допустимо, чтобы не усложнять код. Хотя удобнее наверно делать вывод снаружи.

А вот тебе еще вопрос: если у нас разные типы вопросов требуют разный формат вывода, как ты это сделаешь в QuestionWriter? Чтобы мы могли легко добавлять новые типы вопросов? switch разумеется не годится :)

>>1095395

Было бы лучше, если бы функция checkAnswer ничего не писала, а только возвращала результат - правильно/неправильно. А то если мы захотим просто посчитать сумму баллов, мы этого сделать не сможем (кстати, она у тебя и не считается).

Ну или ее надо переименовать в printCheckResult(...).

deviation в исходной задаче обозначало "погрешность", например, Пи - это 3.14 +/- 0.01, то есть ответ 3.1415 тоже подойдет. Твой вариант больше подходит к текстовым ответам, а не числовым (NumericQuestion).

>>1095139

Нет, метод - это функция в классе, и в скобках пишется список аргументов (переменных), а не свойств:

public function x($a, $b, $c) { .. }

Аргументы $a, $b, $c - это просто переменные, в которые можно при вызове метода передать произвольные значения:

$object->x(100, "text", []);

Они не связаны напрямую со свойствами объекта. Твой код синтаксически неправильный, то есть так писать в принципе нельзя. $this можно использовать только в теле метода.

Обрати внимание, что $this->salary и $salary - это разные вещи. Первое - свойство объекта, второе - переменная. Они никак не связаны, хоть у них и одинаковое название.
#827 #1096430
>>1095120

> //тип вопроса 1. choose - выбор 2. input - ввод | Такюе можно добавить еще новых типов


Для таких случаев используют константы:

class Warrior {
// Тип брони
// деревянная
const ARMOR_WOOD = 'wood';
// платиновая
const ARMOR_PLATINUM = 'platinum';

....
}

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

Но тут тип вообще не нужен. У тебя ведь на каждый тип свой класс, класс и обозначает тип вопроса.
#828 #1096432
>>1096422

>Ты PHP код пишешь в файле с расширением php, не html


Тогда писал и так, и так. Не в этом было дело.

>Апач перезапустил? Он на самом деле перезапустился?


Из-под рута service apache2 restart & status каждый раз, когда что-то менял в конфиге. Не в этом было дело.
А было в том, что нужно было явно в php7.conf задать php_admin_flag engine On, затем заработало. Ты был прав.
#829 #1096456
В статье https://nix-tips.ru/yii2-prostaya-realizaciya-rbac-s-dvumya-rolyami.html описана "реализация RBAC с двумя ролями (пользователя и администратора)". Про администратора мне там вроде понятно, но вот где вторая роль пользователя? Судя по коду (как я его понял), при попытке логина проверяется, есть ли в базе такой юзер и есть ли у него роль админа (const ROLE_ADMIN = 20;). И в итоге, если оба условия не тру, то страница логина просто обновляется. Или автор имел в виду, что доступ к страницам сайта возможен кому угодно (и это роль "юзер"), а пройти логин может только "администратор"?
#830 #1096463
>>1096456

Имеется в виду, что есть просто пользователи и есть пользователи, у которых есть признак администратора. Соответственно, "роль пользователь" - это роль обычного пользователя, не администратора.

Если что, тут документация:

https://github.com/yiisoft/yii2/blob/master/docs/guide-ru/security-authorization.md (рус)
http://www.yiiframework.com/doc-2.0/guide-security-authorization.html (англ)

Код в статье какой-то не очень понятный, например, непонятно, почему они в метод isUserAdmin передают логин, а не id, ну и вообще, почему они этот метод сделали статическим, а не в самой модели User.
#831 #1096464
>>1096456

> но вот где вторая роль пользователя?


Она описана в коде заготовки приложения Yii advanced. Там же не с нуля это пишут, а правят приложение advanced.
#832 #1096478
>>1095442

> Во вью client.php: <?= $form->field($model, 'client') ?>


Откуда там берутся переменные $form и $model?

Также, обращение к несуществующей переменной должно как минимум давать предупреждение, у тебя включен режим отладки и ты читаешь логи?

> $model = new Client();


> $listClients = Client::find()->all();


> return $this->render('client', compact('listClients'));


Зачем ты создаешь переменную $model, если она никак не используется?

Что-то у меня ощущение, что тебе нужно подучить основы PHP, а не за Юи браться. Из-за незнания базовых вещей ты не можешь понять, в чем проблема в твоем коде.

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


> $r1 = Yii::$app->request->post('Client');


> $model->name = $r1['name'];


Это должна делать форма (объект фреймворка Юи). Форма сама извлекает нужные значения и помещает их в поля модели. Ты читал документацию по формам в Юи?
#833 #1096556
Привет, двач. Закатываюсь в тред с желанием запилить собственную браузерку. Начну с прочтения книжки oReally по php. Здесь буду задавать вопросы по ходу их возникновения. Вы же не против?
браузерка-кун
#834 #1096561
>>1096556
все книги по пхп - говно. лучше читай http://www.phptherightway.com/ https://github.com/jupeter/clean-code-php и мануал по языку.
#835 #1096562
Как не надо писать код: https://github.com/sphinxsearch/sphinx/blob/master/src/searchd.cpp

Это код на Си++ из поискового демона sphinx. Сам по себе Sphinx - очень крутой, но на код без боли смотреть невозможно. И как только его автор в нем разбирается.

>>1096556

Не против.
#836 #1096563
>>1082507 (OP)
планируется перекат треда?
#837 #1096564
>>1096561
Вроде бы и знаю английский, но читать на нём некомфортно. Плюс некоторые спорные моменты могут быть непонятны.
#838 #1096565
>>1096564
http://getjump.me/ru-php-the-right-way/ тогда вот, правда она чуть устаревшая, но не так как oReally (у которой последнее издание вышло в феврале 2013 лол). такие старые вещи в плане пхп прям противопоказано читать. если что, в феврале 2013 последней версией был 5.4 вроде.

еще читай учебник и пасту ОПа, они охуенные.

непонятные моменты спрашивай, тут подскажут.
#839 #1096568
В задаче на определение номеров написал регулярку /^(\\s([+]\\s7|8))(\\W[0-9]\\W){10}$/, но понимаю, что \W не подходит туда хоть и определяет все номера из задачи правильно. Как можно сделать всё нормально, чтобы не переусложнять выражение?
#840 #1096578
>>1096556
Начал с того, чтобы запилить себе какой-нибудь хостинг, куда я бы мог выкладывать свой прогресс. Вспомнил про то, что когда-то, ещё в далёком 2014 году, запиливал игрушку на бесплатном хостингере, и, что удивительно, тот аккаунт остался рабочим!
Правда, есть одна беда. Нельзя поменять домен.
В общем, получил доступ к этому хосту и вот какое интересное поделие откопал. Наверно, даже схороню где-нибудь в папочке хлам, на память.
19 Кб, 1366x768
#841 #1096579
>>1096578
Абу-мудак не разрешает постить ссылочки, по крайней мере в бесплатных зонах. Так что прилеплю ссылочку в картинке.
#842 #1096585
>>1096563

Да, скоро переедем.
#843 #1096587
>>1096579

Ты лучше ссылки на код давай, у нас все же тред про программирование в первую очередь.
#844 #1096596
>>1096417

>Я советую попробовать реализовать метод "рекурсивного спуска".


Дядь, я ненастоящий сварщик, я ток начал вкатываться, я ж сломаюсь.
#845 #1096632
>>1096429

>И что ты там собрался смотреть? Поля есть только у объектов, а не у классов.



Вут?

> Поле класса или атрибут в объектно-ориентированном программировании — переменная, связанная с классом или объектом.


А посмотреть можно всё.
https://ideone.com/Tv4ohl

>как ты это сделаешь в QuestionWriter? Чтобы мы могли легко добавлять новые типы вопросов? switch разумеется не годится :)



В Question паблик метод getQuestionText(), возвращающий текст вопроса и абстрактный метод getQuestionPrompt(), возвращающий варианты/подсказки/whatever. QuestionWriter это выводит.
#846 #1096651
>>1091975
Какую строку? Что ты несешь?!
#847 #1096653
>>1096651

Текстовую строку. char * или string. Ты что, Си++ не знаешь?
#848 #1096655
>>1096562

16000+ строк. Нифига себе взрослые дядьки работают.
#849 #1096657
>>1096653

>строку, возвращающую результат в виде строки



Слишком сложный вопрос. Конечно я не знаю С++, раз я в этом треде сижу.
#850 #1096660
>>1096657

Имеется в виду, конечно "как написать функцию, возвращающую строку неизвестной заранее длины".
#851 #1096671
>>1096660
Раз говоришь, что с подвохом, буду разбираться.

Глупо спорить что из них лучше, ведь они оба выросли из С? Тем более у них разное предназначение же.

И да, на говне умные люди не будут писать. На С++ пишут. На PHP пишут. Даже на Pony.

Оффтопный вопрос: как происходит обучение на "программиста" в вузе? Просто учат ЯП 5 курсов? Есть ли там вебдизайн предметы?
#852 #1096672
>>1096660
И в чем проблема? Возвращаем std::string и всё.
#853 #1096677
>>1096671
Учишь кучу матана 5 курсов. Иногда выполняешь проекты курсачи на каком-нибудь ЯП. По сути, обучение в универе на ИТ специальности тебе даст только математическую базу, а языки и само программирование ты в любом случае будешь сам изучать.
#854 #1096685
>>1096672

А память, няша, кто и как освобождать будет? В этом и подвох. Подсказки ты можешь поискать в реализации функций в WinAPI или в стандартной библиотеке линукс, которые возвращают строки.

В PHP, кстати, такой проблемы нет. И в Го тоже.
#855 #1096692
>>1096685
Сама освободится при выходе из области видимости.
#856 #1096746
Решаю задачу про вектор. Как через метод обратиться из одного метода к другому? Не родительскому.
#857 #1096749
>>1096746
То есть методу другого обьекта, я имею в виду.
#858 #1096755
>>1096749
>>1096746
Вот код https://ideone.com/Fr1RyG

Конкретно интересуют вот эти участки кода
1)Class Manager extends Employee
{
protected $profession = "Manager";
public function Hello(){echo"hello";}
}

2)class Department
{

public function AddWorker($departments)
{
$this->Hello();
}

public function __construct(){}
}
#859 #1096761
>>1096749
Ну если статический метод то так
class One
{
public function do()
{
$xyu = Two::doTwo()
}
}

class Two
{
public static function doTwo()
{
return $zalupa;
}
}
Иначе например так
class One
{
private $classTwo;
public function __construct($classTwo)
{
$this->classTwo = $classTwo;
}
public function do()
{
$xyu = $this->classTwo->doTwo();
}
}
class Two
public function doTwo()
{
}
Ну или ты можешь не передавать в конструктор а создавать его там и запихивать в свойство. Ну или например вместо одно объекта classTwo записаного в свойство class One ты можешь запихать их массив.
#859 #1096761
>>1096749
Ну если статический метод то так
class One
{
public function do()
{
$xyu = Two::doTwo()
}
}

class Two
{
public static function doTwo()
{
return $zalupa;
}
}
Иначе например так
class One
{
private $classTwo;
public function __construct($classTwo)
{
$this->classTwo = $classTwo;
}
public function do()
{
$xyu = $this->classTwo->doTwo();
}
}
class Two
public function doTwo()
{
}
Ну или ты можешь не передавать в конструктор а создавать его там и запихивать в свойство. Ну или например вместо одно объекта classTwo записаного в свойство class One ты можешь запихать их массив.
#860 #1096766
>>1096761
Спасибо. Что я тут делаю не так?
https://ideone.com/mFY5q8
Выдает NULL
#861 #1096771
>>1096766
В функции do() ничего не возвращается. Сделай return $xyu;
А в статическом методе присвой какое-нибудь значение $zalupa чтобы видеть что там. Просто ты вызвал функцию которая ничего не возвращает.
#862 #1096839
>>1096746
А где взять эту задачу? Тоже хочу решить.
#863 #1096850
Парни, обновил PHP на сервере с 5.6 на 7.1 и такие ошибки вылезают при запуске с консольки:
[code]PHP Warning: PHP Startup: Unable to load dynamic library '/usr/local/lib/php/20160303/timezonedb.so' - Cannot open "/usr/local/lib/php/20160303/timezonedb.so" in Unknown on line 0[/code]
``PHP Warning: PHP Startup: Unable to load dynamic library '/usr/local/lib/php/20160303/pdf.so' - Cannot open "/usr/local/lib/php/20160303/pdf.so" in Unknown on line 0``

Я так понял, что .ini-файлы, которые остались еще от 5.6, грузят то, чего нет в 7.1 (расширения я поставил ровно те же, что были).
Думается мне, без базы таймзон пхп будет не очень хорошо. Как доставить-то эти библиотеки?
#864 #1096857
>>1096839

>А где взять эту задачу? Тоже хочу решить.



http://archive-ipq-co.narod.ru/l1/pasta.html

Задача про компанию «Вектор»
#865 #1096862
>>1096771
Да. Слушай, спасибо большое.
Ты няша.
#866 #1096923
>>1096850

>/usr/local/lib/php/20160303/timezonedb.so


а там этот файл-то есть? он совместим с семеркой? вообще, оставлять старые конфиги, не проверяя - не очень хорошая идея. если ты ставил эту библиотеку на новый пхп, то найди где реально лежит файл корректный timezonedb.so и пропиши к нему правильный путь.

>> Как доставить-то эти библиотеки?


так ты поставил их или нет? самый простой путь - pecl install extname в командной строке http://php.net/manual/en/install.pecl.downloads.php
#867 #1096932
Что можно сделать дальше? Туплю над этой задачей уже очень долго, столько раз переудалял все и начинал сначала.

https://ideone.com/DeIQNw
#868 #1096953
>>1096932
https://ideone.com/8elAgD

чуть-чуть доделал. я не понимаю, как потом добавлять сотрудников и как это все должно взаимодействовать друг с другом. Как добавлять сотрудников через департамент и указывать в качестве аргументов свойства? Или это не так делается.
#869 #1096955
ОП, сделал задачку про вопросы вообще по красоте.
Проверь, пожалуйста.

https://ideone.com/YuWDBl
#870 #1096965
>>1096422
Сделал хеш и емейл, исправил ENUM
https://github.com/kichiweb123/students
#871 #1096987
>>1096965
и дамп sql пофиксил
#872 #1097031
Поясните за абсолютные и относительные пути. Я ньюфаг, и у меня почему-то всегда проблемы возникают, когда я пытаюсь использовать __DIR__. Можно ли без него обойтись, например, в задаче про студентов?
#873 #1097048
>>1096692

То есть память под строку освободится в момент возврата этой самой строки из функции?

>>1097031

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

Абсолютный путь - это полный путь к файлу от корня файловой системы. Относительный - относительно какой-то папки, например, "текущего каталога процесса". Второй ненадежно, так как мы не можем гарантировать, что "текущий каталог" всегда будет одинаков.
#874 #1097077
>>1096965

> `pass` varchar(150) NOT NULL,


Поле лучше переименовать в password_hash (чтобы не думали, что там реально пароль хранится), а также, стоит добавить краткий комментарий, какой именно хеш и как его получить. И да! конечно, у меня есть урок про добавление комментариев в базу данных: https://github.com/codedokode/pasta/blob/master/db/comments.md

Очевидные вещи комментировать не надо, но тип используемого хеша - это как раз неочевидная вещь.

grup желательно переименовать в group. Это ведь недолго.

> `age` year(4) NOT NULL,


Название неудачное, age - это "возраст", а должно быть "год рождения", то есть birth_year.

По коду - тебе еще есть что исправлять, или все замечания исправлены и надо проверить код снова?

Дам тогда пока еще несколько маленьких замечаний, чтобы тебе было чем заняться.

> https://github.com/kichiweb123/students/blob/master/model/TableStudentsGateway.php


Вот тут вот есть проблема: параметры соединения с БД вписаны прямо в код. То есть пользователь, который скачал твое приложение, должен править код, чтобы соединиться с базой. Это плохо, параметры соединения надо вынести в конфиг в любом формате на твой выбор: ini, php, json, xml, yaml или другой. В комментариях к задаче, опять же, это описано.

И вторая проблема. Ты тут создаешь объект mysqli, но, что, если где-то еще понадобится соединение с БД? Лучше использовать DI и убрать с класса TableStudentGateway обязанность соединяться с БД. Урок про DI с объяснениями: https://github.com/codedokode/pasta/blob/master/arch/di.md

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

> $this->_db


Не используй подчеркивание в начале, в PHP5 есть private/protected чтобы показать, что поле закрыто для доступа снаружи.

> throw new Exception('Невозможно подключиться к БД');


Здесь в сообщение желательно добавить подробности ошибки от mysqli, а то как понять, что именно произошло?

> throw new Exception('Ошибка в запросе при добавлении студентов');


То же самое.

Ты можешь заметить, что шаблон "вызов функции mysqli - проверка на ошибки" повторяется довольно часто в коде (а также паттерн "подготовка запроса - привязка параметров"). Это значит, что имеет смысл подумать над своим классом-оберткой для mysqli, который будет делать это за тебя. То есть класс с примерно такими методами:

public function executeQuery($sql, array $parameters = [])
{
// подготовка запроса
// привязка параметров
// проверка ошибок
}

При этом желательно, чтобы класс-обертка не ограничивал твои возможности и не мешал исопльзовать какие-то возможности mysqli напрямую.

Это позволит упростить код в StudentTableGateway, он будет работать не напрямую с mysqli, а с оберткой.

Ты можешь посмотреть на библиотеку Doctrine DBAL, в которой такая обертка есть. Вот документация по ней на англ: http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/data-retrieval-and-manipulation.html

Вот код, та часть, где находится обертка над mysqli: https://github.com/doctrine/dbal/tree/master/lib/Doctrine/DBAL/Driver/Mysqli

Он не очень понятный, но может быть, это даст тебе какие-то идеи.

> function getStudentCount($search = '', $offset = '', $perPage =''){


> $result = $stmt->get_result();


> return $this->_db->affected_rows;


Чтобы найти число записей в базе, ты их выбираешь (вытягиваешь из mysql в PHP-код) и считаешь количество. Это не эффективно, выгоднее использовать запрос SELECT COUNT(*), который считает число записей на строне mysql и возвращает толкьо это число. Погугли про COUNT, если ты не сталкивался с этой функцией в языке SQL.

> function getPageCount($getStudentCount, $perPage){


Не вижу, какое отношение этот метод имеет к задачам работы с базой данных. Лучше вынести его отсюда.

Насчет метода function refreshStudent(array $data). Здесь идет копипаста. Нужно как минимум использовать цикл. Но еще лучше будет сформировать SQL-запрос, который изменит сразу все поля.

> function findPage($search, $offset, $perPage, $sort = ''){


Здесь почти одинаковый запрос написан 2 раза.

> function checkEmailForForms($email){


Лучше назвать isEmailUnique/isEmailUsed. Также, надо учесть что при редактировании данных email может быть в базе, если он у того же самого пользователя.

> function isLogin($login, $pass = ''){


У тебя есть класс авторизации, в котором правильнее заниматься проверкой пароля. При этом сама работа с БД должна быть в классе TDG, конечно.
#874 #1097077
>>1096965

> `pass` varchar(150) NOT NULL,


Поле лучше переименовать в password_hash (чтобы не думали, что там реально пароль хранится), а также, стоит добавить краткий комментарий, какой именно хеш и как его получить. И да! конечно, у меня есть урок про добавление комментариев в базу данных: https://github.com/codedokode/pasta/blob/master/db/comments.md

Очевидные вещи комментировать не надо, но тип используемого хеша - это как раз неочевидная вещь.

grup желательно переименовать в group. Это ведь недолго.

> `age` year(4) NOT NULL,


Название неудачное, age - это "возраст", а должно быть "год рождения", то есть birth_year.

По коду - тебе еще есть что исправлять, или все замечания исправлены и надо проверить код снова?

Дам тогда пока еще несколько маленьких замечаний, чтобы тебе было чем заняться.

> https://github.com/kichiweb123/students/blob/master/model/TableStudentsGateway.php


Вот тут вот есть проблема: параметры соединения с БД вписаны прямо в код. То есть пользователь, который скачал твое приложение, должен править код, чтобы соединиться с базой. Это плохо, параметры соединения надо вынести в конфиг в любом формате на твой выбор: ini, php, json, xml, yaml или другой. В комментариях к задаче, опять же, это описано.

И вторая проблема. Ты тут создаешь объект mysqli, но, что, если где-то еще понадобится соединение с БД? Лучше использовать DI и убрать с класса TableStudentGateway обязанность соединяться с БД. Урок про DI с объяснениями: https://github.com/codedokode/pasta/blob/master/arch/di.md

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

> $this->_db


Не используй подчеркивание в начале, в PHP5 есть private/protected чтобы показать, что поле закрыто для доступа снаружи.

> throw new Exception('Невозможно подключиться к БД');


Здесь в сообщение желательно добавить подробности ошибки от mysqli, а то как понять, что именно произошло?

> throw new Exception('Ошибка в запросе при добавлении студентов');


То же самое.

Ты можешь заметить, что шаблон "вызов функции mysqli - проверка на ошибки" повторяется довольно часто в коде (а также паттерн "подготовка запроса - привязка параметров"). Это значит, что имеет смысл подумать над своим классом-оберткой для mysqli, который будет делать это за тебя. То есть класс с примерно такими методами:

public function executeQuery($sql, array $parameters = [])
{
// подготовка запроса
// привязка параметров
// проверка ошибок
}

При этом желательно, чтобы класс-обертка не ограничивал твои возможности и не мешал исопльзовать какие-то возможности mysqli напрямую.

Это позволит упростить код в StudentTableGateway, он будет работать не напрямую с mysqli, а с оберткой.

Ты можешь посмотреть на библиотеку Doctrine DBAL, в которой такая обертка есть. Вот документация по ней на англ: http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/data-retrieval-and-manipulation.html

Вот код, та часть, где находится обертка над mysqli: https://github.com/doctrine/dbal/tree/master/lib/Doctrine/DBAL/Driver/Mysqli

Он не очень понятный, но может быть, это даст тебе какие-то идеи.

> function getStudentCount($search = '', $offset = '', $perPage =''){


> $result = $stmt->get_result();


> return $this->_db->affected_rows;


Чтобы найти число записей в базе, ты их выбираешь (вытягиваешь из mysql в PHP-код) и считаешь количество. Это не эффективно, выгоднее использовать запрос SELECT COUNT(*), который считает число записей на строне mysql и возвращает толкьо это число. Погугли про COUNT, если ты не сталкивался с этой функцией в языке SQL.

> function getPageCount($getStudentCount, $perPage){


Не вижу, какое отношение этот метод имеет к задачам работы с базой данных. Лучше вынести его отсюда.

Насчет метода function refreshStudent(array $data). Здесь идет копипаста. Нужно как минимум использовать цикл. Но еще лучше будет сформировать SQL-запрос, который изменит сразу все поля.

> function findPage($search, $offset, $perPage, $sort = ''){


Здесь почти одинаковый запрос написан 2 раза.

> function checkEmailForForms($email){


Лучше назвать isEmailUnique/isEmailUsed. Также, надо учесть что при редактировании данных email может быть в базе, если он у того же самого пользователя.

> function isLogin($login, $pass = ''){


У тебя есть класс авторизации, в котором правильнее заниматься проверкой пароля. При этом сама работа с БД должна быть в классе TDG, конечно.
#875 #1097078
>>1096955

> public function __construct(string $text, $correctAnswer)


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

А так, все правильно сделано. Если хочешь немного поломать голову, посмотри задачу (с подвохом!) про продюсерское агенство: >>1094213 (там даже код писать почти не надо, только описать классы) или задачу про Гостиницу:

------------------

Есть Гостиница, в ней есть Номера. Для каждого Номера известен его номер, количество Гостей, которое в него влезет, а также цена за сутки. В Гостиницу приезжают Гости. Нужно сделать ООП-модель Гостиницы с такими возможностями:

- получить список свободных номеров на определенную дату
- получить список свободных номеров, которые будут свободны в определенный диапазон дат (от A до B)
- дан список Гостей и диапазон дат, в которые они хотели бы заселиться. Необходимо подобрать им самый дешевый и маленький Номер, который их вместит и который свободен в это время.
- то же самое, но при отстутствии одного подходящего номера для Гостей разрешается заселить их в несколько номеров, опять же, начиная с самых дешевых. Например, приехало 3 Гостя, но все 3-местные номера заняты и мы выделяем 2 2-местных, или 3 1-местных или 1-местный + 2-местный.
- зарегистрировать проживание данных Гостей в данных Номерах на данный период
- получить историю заселения Номера (кто в нем когда жил)
- получить историю заселения Гостя (в каких номерах он жил)
- получить статистику доходов Гостиницы за данный диапазон дат (в день A отдель заработал X тугриков, в день B - Y тугриков и так далее)

-------------------

Сделать достаточно только ООП-модель, то есть классы (но конечно можно для проверки дописать код, который проверяет, что все сложные методы работают). Для представления даты в PHP есть класс DateTimeImmutable ( http://php.net/manual/ru/class.datetimeimmutable.php ), почему я рекомендую его, а не DateTime, подумай сам.

Также, есть интересная статья про ООП-проектирование: https://habrahabr.ru/post/153225/
#875 #1097078
>>1096955

> public function __construct(string $text, $correctAnswer)


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

А так, все правильно сделано. Если хочешь немного поломать голову, посмотри задачу (с подвохом!) про продюсерское агенство: >>1094213 (там даже код писать почти не надо, только описать классы) или задачу про Гостиницу:

------------------

Есть Гостиница, в ней есть Номера. Для каждого Номера известен его номер, количество Гостей, которое в него влезет, а также цена за сутки. В Гостиницу приезжают Гости. Нужно сделать ООП-модель Гостиницы с такими возможностями:

- получить список свободных номеров на определенную дату
- получить список свободных номеров, которые будут свободны в определенный диапазон дат (от A до B)
- дан список Гостей и диапазон дат, в которые они хотели бы заселиться. Необходимо подобрать им самый дешевый и маленький Номер, который их вместит и который свободен в это время.
- то же самое, но при отстутствии одного подходящего номера для Гостей разрешается заселить их в несколько номеров, опять же, начиная с самых дешевых. Например, приехало 3 Гостя, но все 3-местные номера заняты и мы выделяем 2 2-местных, или 3 1-местных или 1-местный + 2-местный.
- зарегистрировать проживание данных Гостей в данных Номерах на данный период
- получить историю заселения Номера (кто в нем когда жил)
- получить историю заселения Гостя (в каких номерах он жил)
- получить статистику доходов Гостиницы за данный диапазон дат (в день A отдель заработал X тугриков, в день B - Y тугриков и так далее)

-------------------

Сделать достаточно только ООП-модель, то есть классы (но конечно можно для проверки дописать код, который проверяет, что все сложные методы работают). Для представления даты в PHP есть класс DateTimeImmutable ( http://php.net/manual/ru/class.datetimeimmutable.php ), почему я рекомендую его, а не DateTime, подумай сам.

Также, есть интересная статья про ООП-проектирование: https://habrahabr.ru/post/153225/
#876 #1097079
>>1096953

ООП задачи решают примерно так:

- придумываем, какие у нас будут сущности, и соответственно, классы (например: Работник, Департамент, Компания)
- придумываем, какие у них свойства (например: ранг, базовая ставка, итд). То, что никогда не меняется, или то, что вычисляется из других свойств, нет особого смысла делать свойством. Ну например, ранг разный у разных работников, потому его можно сделать свойством, но базовая ставка у всех одинаковая, потому смысла делать ее свойством нет. Итоговая зарплата вычисляется из ранга, базовой зарплаты, потому ее тоже нет смысла делать свойством, а можно сделать метод, который ее считает.
- придумываем, что с ними можно делать и какую информацию получать (то есть какие будут методы). Например: получить итоговую зарплату работника, получить потребление кофе по департаменту.

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

Если ты не знаешь, куда лучше поместить тот или иной метод или как сделать, задай уточняющий вопрос.

Также, могу дать еще такую статью про ООП-проектирование: https://habrahabr.ru/post/153225/

Посмотрим на твой код:

> abstract class Employee


> public $rank;


> abstract function getSalary($rank);


Здесь у тебя из-за передачи ранга приходится копипастить код вычисления добавок к зарплате. Было бы лучше при данных условиях задачи сделать абстрактным метод получитьБазовуюСтавку, а вычисление итоговой зарплаты сделать в Employee.

> public $profession;


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

> public function __construct($rank, $profession, $isBoss){}


Тут надо сохранять переданные аргументы в поля объекта. Сами они туда не запишутся.

> class Department


> private $departaments = array(); // в плане сюда добавить департаменты, с ссылками на сотрудников через метод, но это не точно


Тут не логично, что в объекте Депаратемнта содержится список каких-то других департаментов. А зачем? Мне кажется, в объекте Департамента логичнее хранить список Работников, которые в нем работают.

> public function TotalPaid(){}


getTotalPaid, имена функций выглядят как сделатьЧтоТо.

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

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

> я не понимаю, как потом добавлять сотрудников


Можно так:

$worker = new Worker(....);
$department->addWorker($worker);

То есть создаем объект работника и добавляем его в департамент. При желании можно сделать еще метод увольнения из департамента.

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

$workerData = [
// count, job, rank
[10, Manager::class, 2],
[10, Manager::class, 1],
...
];
#876 #1097079
>>1096953

ООП задачи решают примерно так:

- придумываем, какие у нас будут сущности, и соответственно, классы (например: Работник, Департамент, Компания)
- придумываем, какие у них свойства (например: ранг, базовая ставка, итд). То, что никогда не меняется, или то, что вычисляется из других свойств, нет особого смысла делать свойством. Ну например, ранг разный у разных работников, потому его можно сделать свойством, но базовая ставка у всех одинаковая, потому смысла делать ее свойством нет. Итоговая зарплата вычисляется из ранга, базовой зарплаты, потому ее тоже нет смысла делать свойством, а можно сделать метод, который ее считает.
- придумываем, что с ними можно делать и какую информацию получать (то есть какие будут методы). Например: получить итоговую зарплату работника, получить потребление кофе по департаменту.

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

Если ты не знаешь, куда лучше поместить тот или иной метод или как сделать, задай уточняющий вопрос.

Также, могу дать еще такую статью про ООП-проектирование: https://habrahabr.ru/post/153225/

Посмотрим на твой код:

> abstract class Employee


> public $rank;


> abstract function getSalary($rank);


Здесь у тебя из-за передачи ранга приходится копипастить код вычисления добавок к зарплате. Было бы лучше при данных условиях задачи сделать абстрактным метод получитьБазовуюСтавку, а вычисление итоговой зарплаты сделать в Employee.

> public $profession;


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

> public function __construct($rank, $profession, $isBoss){}


Тут надо сохранять переданные аргументы в поля объекта. Сами они туда не запишутся.

> class Department


> private $departaments = array(); // в плане сюда добавить департаменты, с ссылками на сотрудников через метод, но это не точно


Тут не логично, что в объекте Депаратемнта содержится список каких-то других департаментов. А зачем? Мне кажется, в объекте Департамента логичнее хранить список Работников, которые в нем работают.

> public function TotalPaid(){}


getTotalPaid, имена функций выглядят как сделатьЧтоТо.

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

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

> я не понимаю, как потом добавлять сотрудников


Можно так:

$worker = new Worker(....);
$department->addWorker($worker);

То есть создаем объект работника и добавляем его в департамент. При желании можно сделать еще метод увольнения из департамента.

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

$workerData = [
// count, job, rank
[10, Manager::class, 2],
[10, Manager::class, 1],
...
];
#877 #1097080
>>1096850

В PHP для новой версии нужны новые плагины, потому в пути к ним указана версия API: /usr/local/lib/php/20160303 - тут 20160303 это и есть версия API. Ты обновил PHP, но где-то в конфигах в /etc/php (или в твоей программе) остался прописан путь со старой версией API - его надо убрать или поменять. Вообще, в таком случае apt-get обычно обнаруживает правку конфигов и выдает предупреждение.

>>1096857

А еще на ООП есть задача про продюсерское агенство >>1094213 и про Гостиницу в посте выше.

>>1096749

Для того, чтобы вызвать не-статический ("обычный") метод, надо иметь объект - в переменной или в поле объекта или еще где-то.

>>1096632

Справедливости ради, ты смотришь не значения полей, а заданные для полей значения по умолчанию.

>>1096596

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

>>1096568

Надо вместо \\W написать "один из символов: скобка, минус, пробел". Это делается с помощью конструкций (a|b|c) или, что лучше, [abc]. Ты с ними знаком?

>>1096564

Мануал PHP почти весь переведен ( http://php.net/manual/ru/index.php ).
#877 #1097080
>>1096850

В PHP для новой версии нужны новые плагины, потому в пути к ним указана версия API: /usr/local/lib/php/20160303 - тут 20160303 это и есть версия API. Ты обновил PHP, но где-то в конфигах в /etc/php (или в твоей программе) остался прописан путь со старой версией API - его надо убрать или поменять. Вообще, в таком случае apt-get обычно обнаруживает правку конфигов и выдает предупреждение.

>>1096857

А еще на ООП есть задача про продюсерское агенство >>1094213 и про Гостиницу в посте выше.

>>1096749

Для того, чтобы вызвать не-статический ("обычный") метод, надо иметь объект - в переменной или в поле объекта или еще где-то.

>>1096632

Справедливости ради, ты смотришь не значения полей, а заданные для полей значения по умолчанию.

>>1096596

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

>>1096568

Надо вместо \\W написать "один из символов: скобка, минус, пробел". Это делается с помощью конструкций (a|b|c) или, что лучше, [abc]. Ты с ними знаком?

>>1096564

Мануал PHP почти весь переведен ( http://php.net/manual/ru/index.php ).
#878 #1097135
>>1097079

>Здесь у тебя из-за передачи ранга приходится копипастить код вычисления добавок к зарплате. Было бы лучше при данных условиях задачи сделать абстрактным метод получитьБазовуюСтавку, а вычисление итоговой зарплаты сделать в Employee.



Можно подробнее? Ведь у меня вычисление зарплаты и так в Employee. Или нет?

>Тут надо сохранять переданные аргументы в поля объекта. Сами они туда не запишутся.



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

>Тут не логично, что в объекте Депаратемнта содержится список каких-то других департаментов. А зачем? Мне кажется, в объекте Департамента логичнее хранить список Работников, которые в нем работают.



Вроде сделал

>getTotalPaid, имена функций выглядят как сделатьЧтоТо.



Переименовал

>В департаменте желательно предусмотреть метод для добавления нового работника.



Вроде сделал

Все что ниже написано сложновато понять. Сейчас попробую что-нибудь еще дописать. Спасибо
#880 #1097151
#881 #1097192
>>1097135

> Можно подробнее? Ведь у меня вычисление зарплаты и так в Employee. Или нет?


В коде тут https://ideone.com/8elAgD , который я проверял, вычисление зарплаты сделано в классах-наследниках:

> class Manager extends Employee


> public function getSalary($rank)


> } elseif($rank == 2){


> return 500 * 1.25;


И это скопипащено 4 раза. Разве это правильно? Я пишу о том, что в наследнике можно определять только базовую ставку, а домножение на 1.25 или 1.5 делать в классе Employee.

>Все что ниже написано сложновато понять.


Задавай уточняющие вопросы тогда.

>>1097151

Конструктор пишут в начале. Обычно порядок примерно такой:

- константы
- публичные поля
- непубличные поля
- абстрактные методы (иногда они идут после конструктора)
- конструктор
- публичные методы
- непубличные методы

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

> // Если это не босс, то переменной присваевается 1 чтобы при умножение не было ошибки.


> if($this->isBoss == 0){


> $this->isBoss = 1;


Это неправильный код. Что хранит isBoss? Я думал, оно хранит 0/1, но после вызова getSalary (который судя по названию, не должен менять состояние объекта) там внезапно появляется какое-то другое число. То есть когда мы второй раз вызовем getSalary, оно уже будет работать неправильно из-за этого.

Вот я попробовал дописать код:

$vasya = new Analyst(1,0);
echo $vasya->getSalary() ."\n";
echo $vasya->getSalary() ."\n";
echo $vasya->getSalary() ."\n";

ссылка: https://ideone.com/tVTQvO

Мы ничего не сделали, а у Васи почему-то вдруг сама собой увеличилась зарплата.

И опять, у тебя в каждом классе-профессии скопирован однотипный код. Так быть не должно. Какой смысл его копировать 4 раза, он ведь отличается только цифрой базовой ставки. Значит, надо код расчета поместить в Employee, а в наследниках оставить только функцию, которая возвращает базовую ставку.

Если непонятно, уточняй. Важно с этим разобраться.

Далее, давай посмотрим на Департамент. Логично, если Департамент отвечает за 1) хранение списка работников, которые в нем работают (и может нанимать и увольнять работников) и 2) за расчет общих расходов на зарплату/кофе по департаменту. Логично, раз у него есть список работников, значит он может посчитать, сколько они в сумме расходуют средств.

Ты решил хранить в Департаменте массив с информацией о работниках. Но зачем? У нас ведь есть объект, который представляет одного работника. Выгоднее тогда хранить в Департаменте массив таких объектов. Соответственно, выглядеть это может так:

class Department
{
// Нанять
public function hireWorker(Employee $worker) {}
// уволить
public function fireWorker(Employee $worker) {}
}

Задавай вопросы, если что-то непонятно.
#881 #1097192
>>1097135

> Можно подробнее? Ведь у меня вычисление зарплаты и так в Employee. Или нет?


В коде тут https://ideone.com/8elAgD , который я проверял, вычисление зарплаты сделано в классах-наследниках:

> class Manager extends Employee


> public function getSalary($rank)


> } elseif($rank == 2){


> return 500 * 1.25;


И это скопипащено 4 раза. Разве это правильно? Я пишу о том, что в наследнике можно определять только базовую ставку, а домножение на 1.25 или 1.5 делать в классе Employee.

>Все что ниже написано сложновато понять.


Задавай уточняющие вопросы тогда.

>>1097151

Конструктор пишут в начале. Обычно порядок примерно такой:

- константы
- публичные поля
- непубличные поля
- абстрактные методы (иногда они идут после конструктора)
- конструктор
- публичные методы
- непубличные методы

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

> // Если это не босс, то переменной присваевается 1 чтобы при умножение не было ошибки.


> if($this->isBoss == 0){


> $this->isBoss = 1;


Это неправильный код. Что хранит isBoss? Я думал, оно хранит 0/1, но после вызова getSalary (который судя по названию, не должен менять состояние объекта) там внезапно появляется какое-то другое число. То есть когда мы второй раз вызовем getSalary, оно уже будет работать неправильно из-за этого.

Вот я попробовал дописать код:

$vasya = new Analyst(1,0);
echo $vasya->getSalary() ."\n";
echo $vasya->getSalary() ."\n";
echo $vasya->getSalary() ."\n";

ссылка: https://ideone.com/tVTQvO

Мы ничего не сделали, а у Васи почему-то вдруг сама собой увеличилась зарплата.

И опять, у тебя в каждом классе-профессии скопирован однотипный код. Так быть не должно. Какой смысл его копировать 4 раза, он ведь отличается только цифрой базовой ставки. Значит, надо код расчета поместить в Employee, а в наследниках оставить только функцию, которая возвращает базовую ставку.

Если непонятно, уточняй. Важно с этим разобраться.

Далее, давай посмотрим на Департамент. Логично, если Департамент отвечает за 1) хранение списка работников, которые в нем работают (и может нанимать и увольнять работников) и 2) за расчет общих расходов на зарплату/кофе по департаменту. Логично, раз у него есть список работников, значит он может посчитать, сколько они в сумме расходуют средств.

Ты решил хранить в Департаменте массив с информацией о работниках. Но зачем? У нас ведь есть объект, который представляет одного работника. Выгоднее тогда хранить в Департаменте массив таких объектов. Соответственно, выглядеть это может так:

class Department
{
// Нанять
public function hireWorker(Employee $worker) {}
// уволить
public function fireWorker(Employee $worker) {}
}

Задавай вопросы, если что-то непонятно.
#882 #1097210
>>1097048

>То есть память под строку освободится в момент возврата этой самой строки из функции?


Сначала вернет, потом освободит.
#883 #1097231
https://ru.wikipedia.org/wiki/Экстремальное_программирование

>TDD (от англ. test-driven development — разработка через тестирование). В соответствии с этим подходом сначала пишется тест, который изначально не проходит (так как логики, которую он должен проверять, ещё просто не существует), затем реализуется логика, необходимая для того, чтобы тест прошёл. TDD, в некотором смысле, позволяет писать код, более удобный в использовании — потому что при написании теста, когда логики ещё нет, проще всего позаботиться об удобстве будущей системы.



Это что еще за переворот игры?
#884 #1097265
>>1097048

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


Ну вот, к примеру, тут совсем, в самом начале на index.php (находится в public), где я автозагрузчик пытаюсь подключить. Когда я пишу:
require_once __DIR__ . '../vendor/autoload.php'
Вылезает ошибка:

>Fatal error: require_once(): Failed opening required >'C:\Apache24\htdocs\studentlist\public../vendor/autoload.php'


Без __DIR__ все работает.
#885 #1097267
ОП, прочитал статью https://habrahabr.ru/post/313796/

>благодаря этому интерфейсу, наше приложение все еще не зависит от конкретного логгера. Логгер же зависит от этой абстракции. Но оба "модуля" не зависят друг от друга.



Получается мы вставляем в ЗАВИСИМОЕ абстракцию (интерфейс), который сразу реализуем в ЗАВИСИМОСТИ, и тогда ни ЗАВИСИМОМУ, ни ЗАВИСИМОСТИ не нужно знать, что внутри каждого из них, между ними есть конкретный договор "ты должен предоставить вот эти методы, иначе я не смогу работать! — Ок, я должен проедоставить вот эти методы, иначе я не подхожу тебе".

М?
#886 #1097269
>>1097265
Так ты получается смешал и то и то.

__DIR__ (путь к папке, из которой ты вызываешь файл index.php, public), у тебя получается строка >'C:\Apache24\htdocs\studentlist\public'

и ты приклеиваешь к ней кусочек

>''../vendor/autoload.php'



Конечно такого файла у тебя нет

>'C:\Apache24\htdocs\studentlist\public../vendor/autoload.php'



>../vendor/autoload.php


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

'C:\Apache24\htdocs\studentlist\public\vendor\autoload.php'
Еще там какие-то кризы со слешами. Вроде в UNIX только прямой можно писать а на винде и прямой и обратный, но я не уверен, тут ОП тебе лучше объяснит.
#887 #1097271
>>1097269
Добра, анон. Что-то я затупил.
#888 #1097273
>>1097192

> а домножение на 1.25 или 1.5 делать в классе Employee



Тогда получается нужно убирать абстрактный класс и делать обычный из которого наследуются 4 профессии?

>Это неправильный код. Что хранит isBoss? Я думал, оно хранит 0/1, но после вызова getSalary (который судя по названию, не должен менять состояние объекта) там внезапно появляется какое-то другое число. То есть когда мы второй раз вызовем getSalary, оно уже будет работать неправильно из-за этого.



Понял. Спасибо. Тогда надо избавляться от абстрактного класса, чтобы создать тело в методе Employee ? А еще как передавать аргументы в этот объект?

......................

Спустя достаточно большой промежуток времени, я вроде исправил копипасту с зп и ошибку с $isBoss

>Далее, давай посмотрим на Департамент. Логично, если Департамент отвечает за 1) хранение списка работников, которые в нем работают (и может нанимать и увольнять работников) и 2) за расчет общих расходов на зарплату/кофе по департаменту. Логично, раз у него есть список работников, значит он может посчитать, сколько они в сумме расходуют средств. Ты решил хранить в Департаменте массив с информацией о работниках. Но зачем? У нас ведь есть объект, который представляет одного работника. Выгоднее тогда хранить в Департаменте массив таких объектов. Соответственно, выглядеть это может так:



Дальше код не совсем понимаю. Мы в качестве аргумента указываем объект?

>(Employee $worker)


Вот эта строчка непонятна.

Спасибо за ответ. https://ideone.com/9cLV0j
#889 #1097300
>>1097265

>require_once __DIR__ . '../vendor/autoload.php'



простое решение - попробуй require_once __DIR__ . '/../vendor/autoload.php'
без этого точно не сработает
#890 #1097322
>>1097080

>Зато будешь хотя бы немного разбираться в синтаксическом анализе


А оно мне может пригодиться? Я же решил вкатиться потому что нашел в своем мухосранске вакансию пхп-кодера, где не требуется опыт и во. Правда выяснилось что на самом деле там обычный верстальщик нужен, так что теперь и не знаю учить ли пхп дальше.
#891 #1097327
>>1097322

> так что теперь и не знаю учить ли пхп дальше



Стоит. Будет плюсом точно.

мимо
#892 #1097329
>>1097078

>Здесь не хватает типа для correctAnswer (так как он может быть разный). Если делать уж совсем правильно, тогда имеет смысл перенести это поле в наследники - ведь если ты не знаешь, какого оно типа, ты все равно не можешь с ним работать в базовом классе.


Но у меня есть метод getCorrectAnswer, который иначе придется дублировать в наследниках. В таком случае, я должен полагаться, что наследник Question всегда реализует поле protected $correctAnswer, что еще хуже, как по мне. Тайпхинт наследники все равно задают.

Задачки принял в работу, спасибо!
#893 #1097368
>>1095790

Нужно написать выражение примерно такого вида: буква, за ней пробелы, за ней "а" как отдельное слово. В твоем выражении "/^(\w)(,)(а)$/mu"; запятая ищется перед любым словом на букву "а".

>>1094971

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

При регистрации доменов, насколько я знаю, там введенные в Whois данные не проверяются (а вот в России могут потребовать скан паспорта, но требуют не у всех). Также, вдобавок у многих регистраторов есть услуга по скрытию этих данных из whois. Увы, в деталях не разбираюсь, тут лучше поискать информацию где-то еще.

> Мне видеться использовать JSON-объект с свойствами каждого вложения.


Скорее всего что-то такое и было.

> Они имели ввиду, что денормализовали данные на две "сущности"?


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

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

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

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

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

Самый простой и интуитивный вариант определения номера шарда - это взять остаток от деления id пользователя на число серверов: uid % N. Это быстро реализуется, но содержит подвохи:

- если у нас есть, допустим, 100 серверов, и надо добавить еще 10, то номера шардов меняются для большинства пользователей (было: uid=123, shard = 123 % 100 = 23, стало shard = 123 % 110 = 13), и нам надо по сути переносить большинство пользователей по сложным правилам. Этот перенос очень сложен, занимает много времени, и в течение этого времени наша система как-то должна продолжать работать (в том числе на запись)
- даже если мы распределим пользователей равномерно по N серверам, нагрузка на них может оказаться неодинаковой - где-то более активные и популярные пользователи, где-то менее. Но сделать тут ничего нельзя, и нам придется из-за этого "недогружать" сервера, чтобы иметь резерв.

Вот пример проблемы с неравномерной нагрузкой: https://habrahabr.ru/company/oleg-bunin/blog/313366/

> Одна история — еще из 2001 г., времен молодости SpyLOG-а — там шардинг был основан на пользователях. Что такое SpyLOG? Сейчас это Openstat. Он собирает статистику посещений, т.е. это такой трекер, счетчик, маленькая кнопочка на страничке.



> В общем, все сайты — как крупные, так и мелкие — были на тот момент распределены по 40 машинам. И, соответственно, сайты покрупнее жили вместе с сайтами помельче, т.е. ключом шардинга был ID сайта, например, анекдот.ру, рамблер.ру, яндекс.ру…



> Так получалось, что большие сайты реально укладывали наши машины, потому что один трафик, генерируемый одним ключом шардинга, был больше, чем одна машина могла принять.



Потому придумываются другие схемы, под общим названием consistent hashing ( https://en.wikipedia.org/wiki/Consistent_hashing ). Один из вариантов я видел в couchbase ( https://developer.couchbase.com/documentation/server/5.0/concepts/distributed-data-management.html ) - там данные разбивают на небольшие группы, vBuckets, и номер бакеты вычисляется через остаток от деления (если я не путаю). Но при этом размер бакета небольшой так, что на один шард попадают, например, сотни бакетов. В такой ситуации мы можем балансировать нагрузку между серверами, перенося между ними отдельные небольшие бакеты, что проще. Но в этом случае мы должны где-то хранить информацию о том, какой бакет на каком шарде хранится. Нужен какой-то конфиг, и конечно, он тоже должен быть распределенным, а не храниться на одном сервере (так как тогда он станет узким местом).

Вконтакте упомянули, что у них расширение делается удваиванием числа серверов, интересно почему? Может быть у них нет consistent sharding.

В случае шардинга мы должны использовать при поиске записей ключ шардинга (тот же uid). Если мы хотим, например, посчитать количество пользователей в определенном городе, то мы должны отправлять запрос на все шарды и аггрегировать результаты. Очевидно, что быстро работать это не будет.

Если у тебя нет нескольких серверов, "поиграть" в шардинг можно например, создав несколько баз данных.

Соответственно, можно представить, зачем вконтакте использует денормализацию. Кластер member-chats использует шардинг по memberId, а chats-members - по chatId. То есть в случае шардинга, если ты хочешь делать поиск по еще каким-то критериям, и таких запросов очень много, тебе надо создавать дополнительные кластеры.

Еще какая-то информация по используемым ими хранилищам есть в их гитхабе: https://github.com/vk-com/kphp-kdb/tree/master/docs/ru

> Как можно заранее построить схему, если со временём неизбежно придётся что-то менять, а данных слишком много?


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

А так, сохранять стоит все, что есть.

> Можно было использовать получившийся экземпляр text-engine и преобразовывать его для member-chats и chat-members. Как у них удалось получить дисинхрон в сообщениях?


Они наверно имеют в виду, что при добавлении новых данных (например, сообщения) код на PHP по очереди соединяется с хранилищами и отправляет в них эти данные. И в некоторые моменты времени данные уже есть в одном хранилище, но их еще нет в другом. То есть появляется временная несогласованность ( https://ru.wikipedia.org/wiki/Согласованность_в_конечном_счёте ).

А еще веселее, если 2 пользователя отправляют в большой чат сообщение примерно одновременно.

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

В хайлоаде такая версионность сильно усложняет систему и бьет по производительности, потому ее не используют. Также, у них нет транзакций, и в принципе возможен вариант, когда данные вставлены в одно хранилище, но не появились в другом. Не знаю, как они это решают. Может игнорируют такие несогласованные данные при чтении.
#893 #1097368
>>1095790

Нужно написать выражение примерно такого вида: буква, за ней пробелы, за ней "а" как отдельное слово. В твоем выражении "/^(\w)(,)(а)$/mu"; запятая ищется перед любым словом на букву "а".

>>1094971

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

При регистрации доменов, насколько я знаю, там введенные в Whois данные не проверяются (а вот в России могут потребовать скан паспорта, но требуют не у всех). Также, вдобавок у многих регистраторов есть услуга по скрытию этих данных из whois. Увы, в деталях не разбираюсь, тут лучше поискать информацию где-то еще.

> Мне видеться использовать JSON-объект с свойствами каждого вложения.


Скорее всего что-то такое и было.

> Они имели ввиду, что денормализовали данные на две "сущности"?


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

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

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

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

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

Самый простой и интуитивный вариант определения номера шарда - это взять остаток от деления id пользователя на число серверов: uid % N. Это быстро реализуется, но содержит подвохи:

- если у нас есть, допустим, 100 серверов, и надо добавить еще 10, то номера шардов меняются для большинства пользователей (было: uid=123, shard = 123 % 100 = 23, стало shard = 123 % 110 = 13), и нам надо по сути переносить большинство пользователей по сложным правилам. Этот перенос очень сложен, занимает много времени, и в течение этого времени наша система как-то должна продолжать работать (в том числе на запись)
- даже если мы распределим пользователей равномерно по N серверам, нагрузка на них может оказаться неодинаковой - где-то более активные и популярные пользователи, где-то менее. Но сделать тут ничего нельзя, и нам придется из-за этого "недогружать" сервера, чтобы иметь резерв.

Вот пример проблемы с неравномерной нагрузкой: https://habrahabr.ru/company/oleg-bunin/blog/313366/

> Одна история — еще из 2001 г., времен молодости SpyLOG-а — там шардинг был основан на пользователях. Что такое SpyLOG? Сейчас это Openstat. Он собирает статистику посещений, т.е. это такой трекер, счетчик, маленькая кнопочка на страничке.



> В общем, все сайты — как крупные, так и мелкие — были на тот момент распределены по 40 машинам. И, соответственно, сайты покрупнее жили вместе с сайтами помельче, т.е. ключом шардинга был ID сайта, например, анекдот.ру, рамблер.ру, яндекс.ру…



> Так получалось, что большие сайты реально укладывали наши машины, потому что один трафик, генерируемый одним ключом шардинга, был больше, чем одна машина могла принять.



Потому придумываются другие схемы, под общим названием consistent hashing ( https://en.wikipedia.org/wiki/Consistent_hashing ). Один из вариантов я видел в couchbase ( https://developer.couchbase.com/documentation/server/5.0/concepts/distributed-data-management.html ) - там данные разбивают на небольшие группы, vBuckets, и номер бакеты вычисляется через остаток от деления (если я не путаю). Но при этом размер бакета небольшой так, что на один шард попадают, например, сотни бакетов. В такой ситуации мы можем балансировать нагрузку между серверами, перенося между ними отдельные небольшие бакеты, что проще. Но в этом случае мы должны где-то хранить информацию о том, какой бакет на каком шарде хранится. Нужен какой-то конфиг, и конечно, он тоже должен быть распределенным, а не храниться на одном сервере (так как тогда он станет узким местом).

Вконтакте упомянули, что у них расширение делается удваиванием числа серверов, интересно почему? Может быть у них нет consistent sharding.

В случае шардинга мы должны использовать при поиске записей ключ шардинга (тот же uid). Если мы хотим, например, посчитать количество пользователей в определенном городе, то мы должны отправлять запрос на все шарды и аггрегировать результаты. Очевидно, что быстро работать это не будет.

Если у тебя нет нескольких серверов, "поиграть" в шардинг можно например, создав несколько баз данных.

Соответственно, можно представить, зачем вконтакте использует денормализацию. Кластер member-chats использует шардинг по memberId, а chats-members - по chatId. То есть в случае шардинга, если ты хочешь делать поиск по еще каким-то критериям, и таких запросов очень много, тебе надо создавать дополнительные кластеры.

Еще какая-то информация по используемым ими хранилищам есть в их гитхабе: https://github.com/vk-com/kphp-kdb/tree/master/docs/ru

> Как можно заранее построить схему, если со временём неизбежно придётся что-то менять, а данных слишком много?


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

А так, сохранять стоит все, что есть.

> Можно было использовать получившийся экземпляр text-engine и преобразовывать его для member-chats и chat-members. Как у них удалось получить дисинхрон в сообщениях?


Они наверно имеют в виду, что при добавлении новых данных (например, сообщения) код на PHP по очереди соединяется с хранилищами и отправляет в них эти данные. И в некоторые моменты времени данные уже есть в одном хранилище, но их еще нет в другом. То есть появляется временная несогласованность ( https://ru.wikipedia.org/wiki/Согласованность_в_конечном_счёте ).

А еще веселее, если 2 пользователя отправляют в большой чат сообщение примерно одновременно.

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

В хайлоаде такая версионность сильно усложняет систему и бьет по производительности, потому ее не используют. Также, у них нет транзакций, и в принципе возможен вариант, когда данные вставлены в одно хранилище, но не появились в другом. Не знаю, как они это решают. Может игнорируют такие несогласованные данные при чтении.
#894 #1097369
>>1094971

>> бинарный лог


Не логарифм, а "журнал". Это, условно говоря, файл, куда пишутся все изменения в БД с момента создания последнего снапшота (снимка). Можно почитать про эту систему у самих же разработчиков ВК:

https://github.com/vk-com/kphp-kdb/blob/master/docs/ru/DBMS_Storage_Comparison.wiki

А также увидеть на примере редиса:

https://redis.io/topics/persistence

Редис - это хранилище, которое хранит 100% данных в оперативной памяти. За счет этого оно может гарантировать выскокую скорость доступа к данным. Сохранение данных на диск же нужно для защиты от потери этих данных.

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

Также, журнал позволяет реализовать отказоустойчивость даже при пропадании питания, можно почитать про журналируемые файловые системы как пример: https://ru.wikipedia.org/wiki/Журналируемая_файловая_система

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

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

>>статических снимков и частичного образа в памяти


> Интересно какой софт они для этого использовали.


У них самописные хранилища на Си, примеры которых можно увидеть на гитхабе (раньше весь хайлоад так и делался). В наши дни некоторые из них можно заменить тем же редисом, который написан по похожим принципам. Ну и еще в наши дни есть Го, на котором это писать приятнее.

Универсальные БД вроде MySQL все же содержат много лишних накладных расходов (парсинг SQL запросов, построение плана выполнения, данные могут не быть в оперативной памяти, сложная структура данных на диске), которые проявляются при очень высокой нагрузке. Потому пишут специализированные хранилища.

Также, есть еще разные NoSQL хранилища: CouchDB/Couchbase, Redis и тд. Монгу не буду вспоминать тут из-за противоречивости, но в ней вроде тоже есть что-то для масштабирования. key-value хранилища хорошо масштабируются по этому самому key.

Алсо, сайт с информацией по хайлоад-проектам, правда немного старая: https://www.insight-it.ru/highload/

Крупные компании иногда разрабатывают свои СУБД, например:

- Яндекс - clickhouse (колоночная БД, придуманная для сбора статистики): https://clickhouse.yandex/ и https://habrahabr.ru/company/yandex/blog/303282/
- Mail - тарантул https://opensource.mail.ru/tarantool
- Гугл - https://en.wikipedia.org/wiki/Spanner_(database) и https://en.wikipedia.org/wiki/Bigtable , https://research.google.com/archive/bigtable.html

> и хотел бы однажды применить некоторые описанные там технологии чтобы познакомиться с ними по лучше.


Самый простой способ - устроиться на работу в компанию с крупным хайлоад-проектом.
#894 #1097369
>>1094971

>> бинарный лог


Не логарифм, а "журнал". Это, условно говоря, файл, куда пишутся все изменения в БД с момента создания последнего снапшота (снимка). Можно почитать про эту систему у самих же разработчиков ВК:

https://github.com/vk-com/kphp-kdb/blob/master/docs/ru/DBMS_Storage_Comparison.wiki

А также увидеть на примере редиса:

https://redis.io/topics/persistence

Редис - это хранилище, которое хранит 100% данных в оперативной памяти. За счет этого оно может гарантировать выскокую скорость доступа к данным. Сохранение данных на диск же нужно для защиты от потери этих данных.

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

Также, журнал позволяет реализовать отказоустойчивость даже при пропадании питания, можно почитать про журналируемые файловые системы как пример: https://ru.wikipedia.org/wiki/Журналируемая_файловая_система

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

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

>>статических снимков и частичного образа в памяти


> Интересно какой софт они для этого использовали.


У них самописные хранилища на Си, примеры которых можно увидеть на гитхабе (раньше весь хайлоад так и делался). В наши дни некоторые из них можно заменить тем же редисом, который написан по похожим принципам. Ну и еще в наши дни есть Го, на котором это писать приятнее.

Универсальные БД вроде MySQL все же содержат много лишних накладных расходов (парсинг SQL запросов, построение плана выполнения, данные могут не быть в оперативной памяти, сложная структура данных на диске), которые проявляются при очень высокой нагрузке. Потому пишут специализированные хранилища.

Также, есть еще разные NoSQL хранилища: CouchDB/Couchbase, Redis и тд. Монгу не буду вспоминать тут из-за противоречивости, но в ней вроде тоже есть что-то для масштабирования. key-value хранилища хорошо масштабируются по этому самому key.

Алсо, сайт с информацией по хайлоад-проектам, правда немного старая: https://www.insight-it.ru/highload/

Крупные компании иногда разрабатывают свои СУБД, например:

- Яндекс - clickhouse (колоночная БД, придуманная для сбора статистики): https://clickhouse.yandex/ и https://habrahabr.ru/company/yandex/blog/303282/
- Mail - тарантул https://opensource.mail.ru/tarantool
- Гугл - https://en.wikipedia.org/wiki/Spanner_(database) и https://en.wikipedia.org/wiki/Bigtable , https://research.google.com/archive/bigtable.html

> и хотел бы однажды применить некоторые описанные там технологии чтобы познакомиться с ними по лучше.


Самый простой способ - устроиться на работу в компанию с крупным хайлоад-проектом.
#895 #1097370
>>1094744

Значит шторм просто не поддерживает эмуляцию терминала с управляющими кодами.

>>1094692

> Так у меня много мест где куки идут ниже по странице и хедеров тоже есть


А не должно быть. Ты сначала выполняешь всю логику на PHP и подготавливаешь данные, а только потом выводишь страницу.

> Щас исправил, только ордер бай по столбцам нельзя делать через prepare, иначе он выдаёт по айдишникам на любой запрос,


Потому что при подстановке через плейсхолдер получается ORDER BY 'name', то есть сортировка не по значению поля, а по константе. Так что да, ты правильно сделал.

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

> Я когда захожу из браузера меня логинит по кукам, которые задавались при регистрации, это ты имел ввиду?


Нет, в данном случае, тебя должно залогинить без регистрациии и без наличия кук. Под каким-то существующим аккаунтом.

>>1094685

> "<a href='script.php?{$link}'>


Ты при вставке URL в HTML-код, в атрибут href, не делаешь экранирование. Ну например, если в ссылке есть символ & то он дложен вставляться как & amp ;

Ты проверял, эта ссылка корректно воспроизводит все символы из примеров к задаче?

Ну и второй скрипт писать не требовалось, можно было сделать, чтобы ссылка указывала на тот же самый скрипт (index.php). Может это я, конечно, плохо сформулировал задачу.
#896 #1097372
>>1094436

Надо смотреть лог ошибок веб-сервера (если ты используешь mod_php и Апач), он на винде по умолчанию лежит в папке Апача, на линуксе в /var/log. Так гадать смысла нет.

>>1094366

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


Для этого и придуманы интеграционные тесты, которые тестируют совокупность нескольких модулей кода. И есть тесты, которые тестируют приложение целиком в сборе. Я не говорил, что они не нужны, хотя есть так называемая "пирамида тестирования": https://martinfowler.com/bliki/TestPyramid.html

> Например, что твой код корректно обрабатывает присланные каким-то сторонним сервером по АПИ данные.


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

> Тогда нужно создавать класс-мок и это уже по идее не юнит-тест


Я не уверен тут в терминологии, юнит- или не юнит-тест это. Мы же тестируем один класс, а не их совокупность.

> Или что при авторизации корректно создается файл куки.


Мне этот тест не нравится. У твоей программы какая цель? Создавать файлы кук? Или эти файлы как-то используются потом? Если второе, то лучше это и тестировать. А то тест получается, завязан на знание о внутренней логике работы программы. Завтра ты поменяешь имя файла или перенесешь куки в базу и тест сломается.

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

А также, АПи можно мокать. Есть даже программы, которые по моему могут записывать пары запрос/ответ, а потом ответ воспроизводить.

> Не тестировать их с помощью Phpunit, а, допустим, через codeception?


Ну, это не принципиально. Используй то, что удобнее.
#896 #1097372
>>1094436

Надо смотреть лог ошибок веб-сервера (если ты используешь mod_php и Апач), он на винде по умолчанию лежит в папке Апача, на линуксе в /var/log. Так гадать смысла нет.

>>1094366

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


Для этого и придуманы интеграционные тесты, которые тестируют совокупность нескольких модулей кода. И есть тесты, которые тестируют приложение целиком в сборе. Я не говорил, что они не нужны, хотя есть так называемая "пирамида тестирования": https://martinfowler.com/bliki/TestPyramid.html

> Например, что твой код корректно обрабатывает присланные каким-то сторонним сервером по АПИ данные.


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

> Тогда нужно создавать класс-мок и это уже по идее не юнит-тест


Я не уверен тут в терминологии, юнит- или не юнит-тест это. Мы же тестируем один класс, а не их совокупность.

> Или что при авторизации корректно создается файл куки.


Мне этот тест не нравится. У твоей программы какая цель? Создавать файлы кук? Или эти файлы как-то используются потом? Если второе, то лучше это и тестировать. А то тест получается, завязан на знание о внутренней логике работы программы. Завтра ты поменяешь имя файла или перенесешь куки в базу и тест сломается.

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

А также, АПи можно мокать. Есть даже программы, которые по моему могут записывать пары запрос/ответ, а потом ответ воспроизводить.

> Не тестировать их с помощью Phpunit, а, допустим, через codeception?


Ну, это не принципиально. Используй то, что удобнее.
#897 #1097373
>>1094311

Оформлен код очень аккуратно. Но я вижу тут проблемы с логикой:

> if ($creditBalance < $monthlyPayment) {


> if ($creditBalance > $monthlyPayment) {


А что, если они равны? Этот вариант почему-то не рассматривается. Тут лучше было использовать один блок if/else, а не 2 отдельных if.

> $creditBalance = $creditBalance - $monthlyPayment;


Это незачем 2 раза повторять.

В остальном, все решено верно.

>>1094306

> как сделать меру, в которой стимулируются аналитики



Нужно сделать базовую ставку изменяемой. Для этого надо завести под нее поле, при создании объекта записывать в него начальное значение, но добавить метод для изменения базовой ставки. То есть вначале можно подумать, что ставка неизменна (хаха, потому что я не стал об этом предупреждать), но потом внезапно оказалось, что она может меняться. И надо менять код. На практике обычно так и бывает, вот статья с хорошим примером: https://habrahabr.ru/post/153225/

> int $isBoss


Для вариантов да/нет есть булев тип: http://php.net/manual/ru/language.types.boolean.php

> getBasicSalary(): int


Это конечно не ошибка, и в задаче этого не требуется, но на практике "ставка" часто бывает с копейками (хотя int тут имеет то преимущество, что это точный тип данных, в отличие от приближенного float, и для денег точные типы данных подходят лучше).

> getWorker(int $number): AbstractWorker


> deleteWorker(int $number): void


Номера - это неудачное решение. Тем более что в работнике его номер не хранится, и непонятно, где его брать. Лучше сделать fireWorker(Worker $worker).

Глубокое клонирование сделано для компании, но не сделано для департамента - в клоне будут работать те же самые работники.

> addWorkersToDepartment


Сюда стоит добавить else, выдающий ошибку при неправильно указанной профессии.

> for ($i = 0; $i < $count; $i++){


Это можно было вынести из if, чтобы не копипастить.

> $department->addWorker


И это тоже.

> class AnticrisisSolutions


Классы не называют в множественном числе, так что было логичнее назвать AnticrisisService, AnticrisisHelper, AnticrisisCommittee (если я не опечатался в слове "комитет").

> public function cutEngineers(Company $basicCompany): void


этот метод делает слишком много: клонирует компанию, печатает отчеты. Лучше если он будет заниматься только применением антикризисных мер.

Отбор работников сделан очень сложно. Вот, как сделал бы я:

- вызвал метод поиска работников в департаменте и получил бы список работников определенных профессий и рангов
- отсортировал бы их в заданном порядке (usort)
- взял первые N из списка (array_slice)
- уволил/поощрил

Код будет в разы короче, а у тебя легко сделать ошибку, и трудно ее найти.

Строки, кстати, рекомендуется переносить при превышении 80-120 символов. В IDE даже линия есть для обозначения границы.

Ну и как и другим, напомню, что в этот треде есть еще пара задачек (попроще) на ООП проектирование, про продюсерское агенство и про гостиницу. Можешь тоже попробовать решить.
#897 #1097373
>>1094311

Оформлен код очень аккуратно. Но я вижу тут проблемы с логикой:

> if ($creditBalance < $monthlyPayment) {


> if ($creditBalance > $monthlyPayment) {


А что, если они равны? Этот вариант почему-то не рассматривается. Тут лучше было использовать один блок if/else, а не 2 отдельных if.

> $creditBalance = $creditBalance - $monthlyPayment;


Это незачем 2 раза повторять.

В остальном, все решено верно.

>>1094306

> как сделать меру, в которой стимулируются аналитики



Нужно сделать базовую ставку изменяемой. Для этого надо завести под нее поле, при создании объекта записывать в него начальное значение, но добавить метод для изменения базовой ставки. То есть вначале можно подумать, что ставка неизменна (хаха, потому что я не стал об этом предупреждать), но потом внезапно оказалось, что она может меняться. И надо менять код. На практике обычно так и бывает, вот статья с хорошим примером: https://habrahabr.ru/post/153225/

> int $isBoss


Для вариантов да/нет есть булев тип: http://php.net/manual/ru/language.types.boolean.php

> getBasicSalary(): int


Это конечно не ошибка, и в задаче этого не требуется, но на практике "ставка" часто бывает с копейками (хотя int тут имеет то преимущество, что это точный тип данных, в отличие от приближенного float, и для денег точные типы данных подходят лучше).

> getWorker(int $number): AbstractWorker


> deleteWorker(int $number): void


Номера - это неудачное решение. Тем более что в работнике его номер не хранится, и непонятно, где его брать. Лучше сделать fireWorker(Worker $worker).

Глубокое клонирование сделано для компании, но не сделано для департамента - в клоне будут работать те же самые работники.

> addWorkersToDepartment


Сюда стоит добавить else, выдающий ошибку при неправильно указанной профессии.

> for ($i = 0; $i < $count; $i++){


Это можно было вынести из if, чтобы не копипастить.

> $department->addWorker


И это тоже.

> class AnticrisisSolutions


Классы не называют в множественном числе, так что было логичнее назвать AnticrisisService, AnticrisisHelper, AnticrisisCommittee (если я не опечатался в слове "комитет").

> public function cutEngineers(Company $basicCompany): void


этот метод делает слишком много: клонирует компанию, печатает отчеты. Лучше если он будет заниматься только применением антикризисных мер.

Отбор работников сделан очень сложно. Вот, как сделал бы я:

- вызвал метод поиска работников в департаменте и получил бы список работников определенных профессий и рангов
- отсортировал бы их в заданном порядке (usort)
- взял первые N из списка (array_slice)
- уволил/поощрил

Код будет в разы короче, а у тебя легко сделать ошибку, и трудно ее найти.

Строки, кстати, рекомендуется переносить при превышении 80-120 символов. В IDE даже линия есть для обозначения границы.

Ну и как и другим, напомню, что в этот треде есть еще пара задачек (попроще) на ООП проектирование, про продюсерское агенство и про гостиницу. Можешь тоже попробовать решить.
#898 #1097374
>>1094257

Вообще, overtimeHours проще всего посчитать как totalHours - normalHours, и не пришлось бы писать цикл.

> if($hour <= 40){


> $hours += $hour;


> }else{


Вместо if/else можно использовать min/max.

> !!! сюда дописать овертайм


Есть стандартное слово TODO для таких целей, например:

// TODO не забыть решить задачки про агенство и гостиницу из этого же треда

> for (;$stringLen < $length; $stringLen++){


> $space .= " ";


Можно написать что-то вроде str_repeat(' ', $length);

А так, в общем, решено верно.

>>1097210

Так к освобожденной памяти обращаться нельзя (будет use-after-free уязвимость).

>>1097231

https://ru.wikipedia.org/wiki/Разработка_через_тестирование

Идея TDD в том, что ты по сути делаешь постановку задачи (задаешь требования) в виде тестов. Ну например, ты хочешь добавить на сайт возможность ставить лайки. И ты можешь написать тест (на класс сервиса, который за это отвечает, или на интерфейс сайта) в стиле:

Feature: возможность лайкать фото
Scenario: пользователь ставит лайк под фото
ДОПУСТИМ, есть какое-то фото.
- ЕСЛИ получить количество лайков у него
- И ЕСЛИ поставить ему лайк
- И ЕСЛИ получить количество лайков снова
- ТО оно ДОЛЖНО быть на 1 больше чем раньше

Feature: фото с большим числом лайков выводится выше
.....

(это я описал словами, а ты будешь писать в виде кода).

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

Там даже есть специальные синтаксис для более удобной записи требований без знания программирования. Например, Gherkin:

https://github.com/cucumber/cucumber/wiki/Gherkin
https://cucumber.io/docs/reference

Это придумано с расчетом на то, что менеджер или тестировщик сможет делать тесты без знания программирования.
#898 #1097374
>>1094257

Вообще, overtimeHours проще всего посчитать как totalHours - normalHours, и не пришлось бы писать цикл.

> if($hour <= 40){


> $hours += $hour;


> }else{


Вместо if/else можно использовать min/max.

> !!! сюда дописать овертайм


Есть стандартное слово TODO для таких целей, например:

// TODO не забыть решить задачки про агенство и гостиницу из этого же треда

> for (;$stringLen < $length; $stringLen++){


> $space .= " ";


Можно написать что-то вроде str_repeat(' ', $length);

А так, в общем, решено верно.

>>1097210

Так к освобожденной памяти обращаться нельзя (будет use-after-free уязвимость).

>>1097231

https://ru.wikipedia.org/wiki/Разработка_через_тестирование

Идея TDD в том, что ты по сути делаешь постановку задачи (задаешь требования) в виде тестов. Ну например, ты хочешь добавить на сайт возможность ставить лайки. И ты можешь написать тест (на класс сервиса, который за это отвечает, или на интерфейс сайта) в стиле:

Feature: возможность лайкать фото
Scenario: пользователь ставит лайк под фото
ДОПУСТИМ, есть какое-то фото.
- ЕСЛИ получить количество лайков у него
- И ЕСЛИ поставить ему лайк
- И ЕСЛИ получить количество лайков снова
- ТО оно ДОЛЖНО быть на 1 больше чем раньше

Feature: фото с большим числом лайков выводится выше
.....

(это я описал словами, а ты будешь писать в виде кода).

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

Там даже есть специальные синтаксис для более удобной записи требований без знания программирования. Например, Gherkin:

https://github.com/cucumber/cucumber/wiki/Gherkin
https://cucumber.io/docs/reference

Это придумано с расчетом на то, что менеджер или тестировщик сможет делать тесты без знания программирования.
#899 #1097375
>>1097265

__DIR__ . '/../something';

Ты слеш забыл, и у тебя точки приклеились к имени папки из DIR и получилось public.. вместо public/..

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

>>1097267

Мне конечно статья кажется не очень понятной. Сложно воспринимать эту схему со стрелочками без конкретного примера.

Идея там, как я понял, в том, что класс B использует всего пару методов из класса E, но при этом объявил весь класс как зависимость. И предлагается вместо этого сделать зависимость только от интерфейса с этой парой методов. Но что-то я плохо вижу, как это поможет - при изменении класса придется менять и интерфейс и то, что от него зависит. Наверно, тут бы пригодился нормальный пример кода.

Чем-то переусложненным сильно попахивает, паттерны ради паттернов. Есть такая статья по теме: https://habrahabr.ru/post/153225/

> Позднее связывание означает, что объект связывается с вызовом функции только во время исполнения программы, а не на этапе компиляции.


Ох, это неудачная фраза, она актуальна для языков вроде Си/Си++, и те, кто с ними не знаком, могут не понять ее.

> Когда проект планируется поддерживать намного дольше, нежели период поддержки вашего фреймворка, имеет смысл все используемые вещи завернуть в адаптеры.


Это малореально на практике. Ну как ту же Доктрину завернуть в адаптеры? И на что ее можно заменить потом? Если например поменяется синтаксис DQL, это никак не поможет.

> Или мы делаем очередную соц сеть, и нам надо как-то трекать репосты. Да, мы можем сделать это на MySQL но выйдет неудобно. Тут напрашиваются графовые базы данных


Вообще не имеет отношения к теме поста по моему.

> Получается мы вставляем в ЗАВИСИМОЕ абстракцию (интерфейс), который сразу реализуем в ЗАВИСИМОСТИ, и тогда ни ЗАВИСИМОМУ, ни ЗАВИСИМОСТИ не нужно знать, что внутри каждого из них, между ними есть конкретный договор "ты должен предоставить вот эти методы, иначе я не смогу работать! — Ок, я должен проедоставить вот эти методы, иначе я не подхожу тебе".



Во-первых, логгер о том, кто его вызывает, не знает в любом случае (ЗАВИСИМОСТЬ не знает о том, кому она нужна). Интерфейс просто позволяет не привязываться к конкретной реализации зависимости.

Без интерфейса: Классу A нужен объект класса B
С интерфейсом: классу A нужен объект любого класса, который умеет делать X (вести лог например)

Если я не ответил на твой вопрос (я сам что-то не уверен, что правильно его понял), то задавай уточняющие вопросы.

Если что, у меня есть урок про интерфейсы: https://github.com/codedokode/pasta/blob/master/php/interfaces.md и урок про DI https://github.com/codedokode/pasta/blob/master/arch/di.md
#899 #1097375
>>1097265

__DIR__ . '/../something';

Ты слеш забыл, и у тебя точки приклеились к имени папки из DIR и получилось public.. вместо public/..

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

>>1097267

Мне конечно статья кажется не очень понятной. Сложно воспринимать эту схему со стрелочками без конкретного примера.

Идея там, как я понял, в том, что класс B использует всего пару методов из класса E, но при этом объявил весь класс как зависимость. И предлагается вместо этого сделать зависимость только от интерфейса с этой парой методов. Но что-то я плохо вижу, как это поможет - при изменении класса придется менять и интерфейс и то, что от него зависит. Наверно, тут бы пригодился нормальный пример кода.

Чем-то переусложненным сильно попахивает, паттерны ради паттернов. Есть такая статья по теме: https://habrahabr.ru/post/153225/

> Позднее связывание означает, что объект связывается с вызовом функции только во время исполнения программы, а не на этапе компиляции.


Ох, это неудачная фраза, она актуальна для языков вроде Си/Си++, и те, кто с ними не знаком, могут не понять ее.

> Когда проект планируется поддерживать намного дольше, нежели период поддержки вашего фреймворка, имеет смысл все используемые вещи завернуть в адаптеры.


Это малореально на практике. Ну как ту же Доктрину завернуть в адаптеры? И на что ее можно заменить потом? Если например поменяется синтаксис DQL, это никак не поможет.

> Или мы делаем очередную соц сеть, и нам надо как-то трекать репосты. Да, мы можем сделать это на MySQL но выйдет неудобно. Тут напрашиваются графовые базы данных


Вообще не имеет отношения к теме поста по моему.

> Получается мы вставляем в ЗАВИСИМОЕ абстракцию (интерфейс), который сразу реализуем в ЗАВИСИМОСТИ, и тогда ни ЗАВИСИМОМУ, ни ЗАВИСИМОСТИ не нужно знать, что внутри каждого из них, между ними есть конкретный договор "ты должен предоставить вот эти методы, иначе я не смогу работать! — Ок, я должен проедоставить вот эти методы, иначе я не подхожу тебе".



Во-первых, логгер о том, кто его вызывает, не знает в любом случае (ЗАВИСИМОСТЬ не знает о том, кому она нужна). Интерфейс просто позволяет не привязываться к конкретной реализации зависимости.

Без интерфейса: Классу A нужен объект класса B
С интерфейсом: классу A нужен объект любого класса, который умеет делать X (вести лог например)

Если я не ответил на твой вопрос (я сам что-то не уверен, что правильно его понял), то задавай уточняющие вопросы.

Если что, у меня есть урок про интерфейсы: https://github.com/codedokode/pasta/blob/master/php/interfaces.md и урок про DI https://github.com/codedokode/pasta/blob/master/arch/di.md
#900 #1097376
>>1097273

> Тогда получается нужно убирать абстрактный класс и делать обычный из которого наследуются 4 профессии?



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

> Тогда надо избавляться от абстрактного класса, чтобы создать тело в методе Employee ?


не надо избавляться. Просто добавляешь метод в класс Employee.

> А еще как передавать аргументы в этот объект?


В какой именно объект? И что передать? При создании объекта аргументы передаются в конструктор, при вызове метода - как обычно.

>>(Employee $worker)


> Вот эта строчка непонятна


Это тайп-хинт

----

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

Мануал: http://php.net/manual/ru/language.oop5.typehinting.php

Обрати внимание, что php7 усовершенствовал систему тайп-хинтов - теперь можно в их качестве указывать примитивные типы вроде int/string, а в php7.1 стало можно указывать тайп-хинт для возвращаемого функцией значения: https://habrahabr.ru/post/267799/ , причем можно указать тип void, значащий, что функция ничего не возвращает.

-----

Твой вариант немного запутанный. Можно же сделать так:

class Employee
{
public function getSalary()
{
...
}

abstract protected function getBasicSalary();
}

class Manager extends Employee
{
protected function getBasicSalary()
{
return 500;
}
}
#900 #1097376
>>1097273

> Тогда получается нужно убирать абстрактный класс и делать обычный из которого наследуются 4 профессии?



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

> Тогда надо избавляться от абстрактного класса, чтобы создать тело в методе Employee ?


не надо избавляться. Просто добавляешь метод в класс Employee.

> А еще как передавать аргументы в этот объект?


В какой именно объект? И что передать? При создании объекта аргументы передаются в конструктор, при вызове метода - как обычно.

>>(Employee $worker)


> Вот эта строчка непонятна


Это тайп-хинт

----

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

Мануал: http://php.net/manual/ru/language.oop5.typehinting.php

Обрати внимание, что php7 усовершенствовал систему тайп-хинтов - теперь можно в их качестве указывать примитивные типы вроде int/string, а в php7.1 стало можно указывать тайп-хинт для возвращаемого функцией значения: https://habrahabr.ru/post/267799/ , причем можно указать тип void, значащий, что функция ничего не возвращает.

-----

Твой вариант немного запутанный. Можно же сделать так:

class Employee
{
public function getSalary()
{
...
}

abstract protected function getBasicSalary();
}

class Manager extends Employee
{
protected function getBasicSalary()
{
return 500;
}
}
#901 #1097377
>>1097322

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

>>1097329

> Но у меня есть метод getCorrectAnswer, который иначе придется дублировать в наследниках.


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

Если же указывать тип результата то нам придется делать в каждом классе свою версию getCorrectAnswer, мы увидим что это по сути разные методы.

В таком коде:

function doSomething(AbstractQuestion $q)
{
// !
$a = $q->getCorrectAnswer();
}

Мы не знаем какой конкретно класс у $q, какой будет тип $a и, как следствие, не можем с ним ничего сделать. То есть пользы от того, что у тебя есть этот метод - ноль. И потому логично его убрать.

Алсо, еще подвохи с наследованием:

http://sergeyteplyakov.blogspot.ru/2014/09/liskov-substitution-principle.html (проблема прямоугольника и квадрата)
http://al-zatv.livejournal.com/52115.html

я бы просто не стал делать класс для квадрата, обойдутся и прямоугольником

> В таком случае, я должен полагаться, что наследник Question всегда реализует поле protected $correctAnswer,


Ты не можешь на это полагаться и ты не должен использовать поля, не доступные в текущем классе. Ведь кто угодно может создать наследника твоего класса и он не обязательно добавит это поле.
#901 #1097377
>>1097322

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

>>1097329

> Но у меня есть метод getCorrectAnswer, который иначе придется дублировать в наследниках.


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

Если же указывать тип результата то нам придется делать в каждом классе свою версию getCorrectAnswer, мы увидим что это по сути разные методы.

В таком коде:

function doSomething(AbstractQuestion $q)
{
// !
$a = $q->getCorrectAnswer();
}

Мы не знаем какой конкретно класс у $q, какой будет тип $a и, как следствие, не можем с ним ничего сделать. То есть пользы от того, что у тебя есть этот метод - ноль. И потому логично его убрать.

Алсо, еще подвохи с наследованием:

http://sergeyteplyakov.blogspot.ru/2014/09/liskov-substitution-principle.html (проблема прямоугольника и квадрата)
http://al-zatv.livejournal.com/52115.html

я бы просто не стал делать класс для квадрата, обойдутся и прямоугольником

> В таком случае, я должен полагаться, что наследник Question всегда реализует поле protected $correctAnswer,


Ты не можешь на это полагаться и ты не должен использовать поля, не доступные в текущем классе. Ведь кто угодно может создать наследника твоего класса и он не обязательно добавит это поле.
#902 #1097408
>>1097374

>Так к освобожденной памяти обращаться нельзя (будет use-after-free уязвимость).


А мы к ней и не будем обращаться, накой оно нам? https://ideone.com/9vRQzQ
#903 #1097426
>>1097408

А, возврат значения с копированием строки (которое в идеале будет выоптимизировано). Понятно, что в реальности объект никто не возвращает (он тупо в регистры не поместится) и если сделать аналог на Си, то это выглядит примерно так:

void func(char **str1) {
*str1 = malloc(...);
strcpy(*str1, "...");
}

То есть функция выделяет кусок памяти в куче и сохраняет указатель на него в переданный ей объект string (если я ничего не напутал).

Код, вызвавший функцию, затем удалит объект string и вызовет free() для буфера с данными.

А теперь вопрос: если твоя функция находится в библиотеке, слинкованной с одной версией runtime library, а вызывает ее код, слинкованный с другой runtime library, так, что они используют разные кучи, будет ли это все работать корректно? Ведь библиотека и программа могут быть собраны не то что разной версией компилятора, а вообще разными компиляторами? То есть используется реализация malloc от одного runtime и free от другого.

В Си, как я понимаю, эта проблема не решается, а в Си++ она решена?

Собственно, по моим наблюдениям, что системные dll в Windows, что стандартная библиотека libc в линукс, такой подход не используют. Там всегда стараются сделать так, что память освобождает тот же, кто ее выделял. В линуксе обычно в функции есть статический буфер, возвращается указатель на него и получатель сразу же должен скопировать строку себе. В Windows обычно вызывающий функцию должен сам выделить буфер и передать указатель на него и его размер.
#904 #1097427
>>1097408

Я конечно мог ошибиться в своих рассуждениях и буду рад, если меня поправят.
#905 #1097443
Аноны, выкатывайтесь-ка в новый тред >>1097438 (OP)

Если я кого-то пропустил, напомните о себе в новом треде.
#906 #1097466
>>1097077

>Поле лучше переименовать в password_hash


дамп sql пофиксил

>параметры соединения надо вынести в конфиг


Вынес

>Не используй подчеркивание в начале


Ок, хорошо

>Здесь в сообщение желательно добавить подробности ошибки от mysqli


Добавил

>Ты можешь заметить, что шаблон "вызов функции mysqli - проверка на ошибки" повторяется довольно часто в коде


Пока думаю(1)

>SELECT COUNT(*)


Сделал

>Не вижу, какое отношение этот метод имеет к задачам работы с базой данных. Лучше вынести его отсюда.


Вынес в класс Util

>Но еще лучше будет сформировать SQL-запрос, который изменит сразу все поля.


Пока думаю(2)

> Также, надо учесть что при редактировании данных email может быть в базе, если он у того же самого пользователя.


Здесь не понял, но у меня есть проверка на емейл

>У тебя есть класс авторизации, в котором правильнее заниматься проверкой пароля. При этом сама работа с БД должна быть в классе TDG, конечно.


По идее сделал

>Лучше использовать DI и убрать с класса TableStudentGateway обязанность соединяться с БД. Урок про DI с объяснениями:


Сделал, но надо проверять, пасту раз 10 читал, не уверен что понял паттерн до конца, тяжело идёт

>По коду - тебе еще есть что исправлять, или все замечания исправлены и надо проверить код снова?


Ну можешь проверить за исключением двух пунктов указанных выше все замечания исправлены вроде
#906 #1097466
>>1097077

>Поле лучше переименовать в password_hash


дамп sql пофиксил

>параметры соединения надо вынести в конфиг


Вынес

>Не используй подчеркивание в начале


Ок, хорошо

>Здесь в сообщение желательно добавить подробности ошибки от mysqli


Добавил

>Ты можешь заметить, что шаблон "вызов функции mysqli - проверка на ошибки" повторяется довольно часто в коде


Пока думаю(1)

>SELECT COUNT(*)


Сделал

>Не вижу, какое отношение этот метод имеет к задачам работы с базой данных. Лучше вынести его отсюда.


Вынес в класс Util

>Но еще лучше будет сформировать SQL-запрос, который изменит сразу все поля.


Пока думаю(2)

> Также, надо учесть что при редактировании данных email может быть в базе, если он у того же самого пользователя.


Здесь не понял, но у меня есть проверка на емейл

>У тебя есть класс авторизации, в котором правильнее заниматься проверкой пароля. При этом сама работа с БД должна быть в классе TDG, конечно.


По идее сделал

>Лучше использовать DI и убрать с класса TableStudentGateway обязанность соединяться с БД. Урок про DI с объяснениями:


Сделал, но надо проверять, пасту раз 10 читал, не уверен что понял паттерн до конца, тяжело идёт

>По коду - тебе еще есть что исправлять, или все замечания исправлены и надо проверить код снова?


Ну можешь проверить за исключением двух пунктов указанных выше все замечания исправлены вроде
#907 #1097468
>>1097370

>Нет, в данном случае, тебя должно залогинить без регистрациии и без наличия кук. Под каким-то существующим аккаунтом.


Это как?
#909 #1097564
PHPStorm перестал нормально делать автозаполнение. Например не видит нужного метода Route, хотя в классе и так прописан use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
Или не понимает, что тут я пишу var_dump, хотя если я допишу название ф-ии ручками, то всплывёт подсказка.

В Include Path у меня всё содержимое папки vendor, В PHP Runtime выбрано всё.

Случилось это после того, как я сделал composer update и шторм мне предложил добавить vendor в Include Path. До этого он был пустой
#910 #1097572
>>1097372

>У твоей программы какая цель? Создавать файлы кук? Или эти файлы как-то используются потом? Если второе, то лучше это и тестировать. А то тест получается, завязан на знание о внутренней логике работы программы.



в принципе, цель данного функционала - всегда быть залогиненным при корректном пароле. и это как бы получается внутренняя логика, да. с другой стороны, это публичная библиотека и хочется на нее повесить плашку "100% code coverage" как у всех :) чтобы я пришел устраиваться на работу и на собеседовании такой эту плашку показал и мне сразу +10к к зп (просто я вижу, что на собеседованиях часто не настолько внимательно разбирают чужой код, как тут, например)

еще вопрос: есть приватный метод, который вызывается в публичном. например, мы делаем несколько запросов по апи (публичный метод addEntity(EntityInterface $entity)) и между ними должны выдерживать паузу в секунду, чтобы нас не забанили (приватный метод waitOneSec()) мы должны его тестировать через публичный, правильно? или вообще не должны?
#911 #1097575
>>1097564

>PHPStorm перестал нормально делать автозаполнение. Например не видит нужного метода Route, хотя в классе и так прописан use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;


>Или не понимает, что тут я пишу var_dump, хотя если я допишу название ф-ии ручками, то всплывёт подсказка.


>


это скроее всего что-то с индексацией, у меня иногда такое бывает. лечится через File - Invalidate cache/restart
#912 #1097583
>>1097572

> в принципе, цель данного функционала - всегда быть залогиненным при корректном пароле.



Это и надо проверять. Например, запросом какой-то страницы доступной только авторизованным пользователям. Наличие файла кук не признак залогиненности.
#913 #1097585
>>1097572

> еще вопрос: есть приватный метод, который вызывается в публичном. например, мы делаем несколько запросов по апи (публичный метод addEntity(EntityInterface $entity)) и между ними должны выдерживать паузу в секунду, чтобы нас не забанили (приватный метод waitOneSec()) мы должны его тестировать через публичный, правильно? или вообще не должны?



Это тот случай, где нужны моки и еще забыл, как это называется, в общем заглушки разного вида. Делается класс-заглушка вместо HTTP клиента и внедряется через DI. Вызывается метод addEntity нужное число раз, и проверяется, что метод класса-заглушки вызвыается с требуемой частотой (можно посчитать число вызовов и поделить на время между ними).

Альтернативный способ - сделать мок сервера с API и считать частоту входящих запросов на нем - но она наверно сложнее в реализации.
#914 #1097591
>>1097572

> повесить плашку "100% code coverage" как у всех :)


У кого "всех"? В реальной жизни никто на эти бесполезные цифры время не тратит, почитай:
- https://medium.com/@nicklee1/why-test-code-coverage-targets-are-a-bad-idea-1b9b8ef711ef
- http://www.databonanza.com/2012/08/the-evils-of-code-coverage-and-other.html
- https://news.ycombinator.com/item?id=14297289

> показал и мне сразу +10к к зп


Глупости. Тесты пишутся для того, чтобы меньше времени тратить на обнаружение и исправление багов, чтобы проще было обновляться (неважно что - фреймворк или версию PHP), чтобы проще можно было рефакторить, так как с тестами ты получаешь волшебную кнопку, которая рапортует тебе о возникших проблемах. И даже при наличии тестов может возникнуть проблема как у этого >>1097568 анона, тогда все твои 100% коту под хвост.
#915 #1097600
>>1097375
Я искал по вопросу "инверсия зависимостей", просто у меня в коде случилась ситуация, что чужой код, на который я полагаюсь, изменил вдруг свое API. И все полетело. А чтобы иправить, мне пришлось у себя искать все файлы, в которых вызывалось данное API (их много) в разных местах (тоже много) и все это править, плюс править свой код, потому что поменялось поведение. Простая DI тут оказалась бессильна.

Вот я подумал: неплохо бы иметь свою обертку над тем чужим кодом, которая всегда будет возвращать так как надо мне, а если что-то изменят, я в одном этом файле могу все поправить быстро. Гугление привело меня в эту статью.
#916 #1097602
>>1097600

Да не имеет это смысла скорее всего. Значительное обновление сторонних библиотек всегда подразумевает какие-то изменения в коде, тут вопрос уж скорее почему у тебя обращения к библиотеке раскиданы по всему коду, а не собраны где-то в одном слое.
#917 #1097619
>>1097585
спасибо.

> и еще забыл, как это называется, в общем заглушки разного вида


стабы, наверное
#918 #1097620
я тут недавно, может чего-то не понимаю, а почему пост >>1097568 и все ответы на него не видны в ленте треда?
#919 #1097621
>>1097620
все понял, сорян
#920 #1097647
Аноны, выкатывайтесь-ка в новый тред >>1097438 (OP)

Если я кого-то пропустил, напомните о себе в новом треде.

Тут будут только ответы на старые вопросы.
#921 #1098085
>>1097591

> И даже при наличии тестов может возникнуть проблема как у этого >>1097568 анона, тогда все твои 100% коту под хвост.



При наличии тестов он бы сразу обнаружил проблему (если бы на dev обновил PHP до той же версии и прогнал бы тесты).
#922 #1098220
Проверьте пожалуйста задание на приведение номеров к единому стандарту через регулярки

https://ideone.com/EQhCuF
#923 #1098319
>>1098220

Запости это в новый тред пожалуйста.

>>1089439

> Возможно, Вы мыслите в плане больших нагруженных проектов,


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

Либо считать номер первой записи отдельным запросом.

> Мне придется как-то добавить им всем их номера.


Пфф, скрипт простановки номеров писать 20 минут.

>>1089464

Никак. Но можно завернуть их в транзакцию, скорее всего это тебе и нужно.

>>1089481

> $lenght = strlen($textlow);


Надо использовать mb_strlen, урок https://github.com/codedokode/pasta/blob/master/php/strings-utf8.md
#924 #1098320
>>1090687

> Параметр AUTO_INCREMENT, который указывается в БД, делает идентификатор - уникальным?


Ну он же уникален, значит, да.

> ЧПУ - это любой URL, который может прочитать человек?


Посмотри определение в интернете. На западе это называют SEO friendly URL, то есть URL для поисковиков.

> Если я хочу в переменную $link запухнуть ссылку, мне обязательно нужно указать htmlspecialchars ?


$link = htmlspecialchars($_POST['link']);
Нет, ты вообще, смотрел, что делает эта функция? Она для вставки текста в HTML так, что он отображается как текст, какие бы символы в нем не были.

> if(empty($_POST['link'])){} - т.е. логика этого if "если ничего не передано, то ничего не делать?


Это надо спрашивать у автора кода, логики тут нет.

> я как-то не могу понять, почему перед переменной $select стоит @


Посмотри в мануале в списке операторов языка, что значит @

>>1091508

Спрашивай, что непонятно. Там получается простой скрипт вида

PHP-код
-------
HTML-страница с формой.

Алсо в помощь мануал http://php.net/manual/ru/language.variables.external.php

>>1091519

Молодец, все верно решено.
#924 #1098320
>>1090687

> Параметр AUTO_INCREMENT, который указывается в БД, делает идентификатор - уникальным?


Ну он же уникален, значит, да.

> ЧПУ - это любой URL, который может прочитать человек?


Посмотри определение в интернете. На западе это называют SEO friendly URL, то есть URL для поисковиков.

> Если я хочу в переменную $link запухнуть ссылку, мне обязательно нужно указать htmlspecialchars ?


$link = htmlspecialchars($_POST['link']);
Нет, ты вообще, смотрел, что делает эта функция? Она для вставки текста в HTML так, что он отображается как текст, какие бы символы в нем не были.

> if(empty($_POST['link'])){} - т.е. логика этого if "если ничего не передано, то ничего не делать?


Это надо спрашивать у автора кода, логики тут нет.

> я как-то не могу понять, почему перед переменной $select стоит @


Посмотри в мануале в списке операторов языка, что значит @

>>1091508

Спрашивай, что непонятно. Там получается простой скрипт вида

PHP-код
-------
HTML-страница с формой.

Алсо в помощь мануал http://php.net/manual/ru/language.variables.external.php

>>1091519

Молодец, все верно решено.
#925 #1098321
Этот тред закрыт. На все вопросы я вроде бы дал ответы.

Переходите в новый тред >>1097438 (OP)

Если я кого-то пропустил, напомните о себе в новом треде.
#926 #1099109
>>1097575
Спасибо, помогло!
#927 #1099125
>>1091208
Operating system level virtualization.
Linux namespaces.
Union file system.
Тред утонул или удален.
Это копия, сохраненная 5 декабря 2017 года.

Скачать тред: только с превью, с превью и прикрепленными файлами.
Второй вариант может долго скачиваться. Файлы будут только в живых или недавно утонувших тредах. Подробнее

Если вам полезен архив М.Двача, пожертвуйте на оплату сервера.
« /pr/В начало тредаВеб-версияНастройки
/a//b//mu//s//vg/Все доски