Вы видите копию треда, сохраненную 24 мая 2017 года.
Скачать тред: только с превью, с превью и прикрепленными файлами.
Второй вариант может долго скачиваться. Файлы будут только в живых или недавно утонувших тредах. Подробнее
Если вам полезен архив М.Двача, пожертвуйте на оплату сервера.
Пожалуйста, пишите один большой пост вместо нескольких маленьких и не флудите не по теме. ОПу ведь все это читать придется.
Это тред для начинающих. Не написал за свою жизнь ни одной программы и имеешь тройку по математике? Ты наш человек.
Устанавливать пока что ничего не требуется, разве что редактор кода вроде Sublime Text 3, Notepad++, Visual Studio Code, Netbeans PHP или PhpStorm (с ним будет удобнее).
Что самое главное для программиста? Умение аккуратно оформлять код (читай второй пост, прежде чем писать код).
Правила: ведем себя воспитанно, помогаем новичкам, постим ссылки на решения задачек, ОП их проверяет и дает советы и замечания. ОП заходит редко, где-то раз в 2-3 дня, у него мало времени, не жди его, решай задачки дальше. ОП отвечает на все вопросы по его задачкам и учебнику, а вот насчет каких-то других вещей - только если останется время. Но в треде немало анонимных экспертов разного уровня, так что вряд ли вопрос останется без ответа.
У нас есть уроки по основам PHP, они собраны и выложены по адресу http://archive-ipq-co.narod.ru/ Это учебник для изучающих с нуля, то есть если ты вообще ничего не знаешь, то надо начать с него. Он простой и понятный (по крайней мере в начале). Там есть задачи, их надо решать обязательно (чтобы стать программистом, надо писать код — иначе никак). Пости ссылки на решения в тред, мы их проверим, напишем замечания и дадим советы по улучшению.
Если не знаешь как решать, запости код, напиши в каком месте остановился и попроси подсказку.
Ты прошел весь учебник? Молодец, но это были лишь основы языка 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 2/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
- Можно подробнее про поиск работы, собеседования - нет, ОП писать не будет, но может кто из анонов захочет рассказать. Поищите тред перезвонивших, а также раздел /wrk/.
- Сколько времени надо изучать все это? - все зависит от тебя, но не меньше 6-8 месяцев
- Посоветуйте редактор кода - Sublime Text 3, Notepad++, PhpStorm
- Нужен ли ООП, фреймворки, MVC, git, composer? — Да, однозначно. Посмотри любую вакансию.
- Что самое главное для программиста? Умение аккуратно оформлять код.
- ОП, сделай за меня мою работу или домашнее задание? — Это конечно, хорошая идея, но нет.
- Подскажи сайты для поиска работы, я не умею гуглить? — hh.ru, geekjob.ru, moikrug.ru (склеен с brainstorage.me), fl.ru, upwork.com (бывший одеск). Имей в виду, что кроме фриланса есть еще постоянная удаленная работа (remote job) когда тебе не надо тратить время на поиск заказов и переговоры с неадекватными заказчиками.
-------------------
Код нужно писать не как попало, а аккуратно и по правилам. Почему? Потому, что на неакуратно написанный код не хочется даже смотреть.
Если тебе лень выравнивать код руками, закачай его на 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
Блядь, что за криворукий рукожоп создал тред? Где ссылка на прошлый? Где 4 пикчи? Где второй и третий посты. Мод, удаляй это, Настоящий оп пересоздаст.
В прошлом треде больше тысячи сообщений, твой оп-слоупок раньше пересоздать не мог?
в Lampp создал новый проект (laravel new test).
При php artisan migrate получаю
[Illuminate\Database\QueryException]
could not find driver (SQL: select * from information_schema.tables where table_schema = testdb and table_name = migrations)
[PDOException]
could not find driver
В laracasts он подымает mariadb сервер, но хотелось бы использовать Ксамповский.
Это норма вообще, зачем оно если я не запускал сервер?
Это не оправдывает то, что ты сраный криворук, который не может в элементарный копипаст.
Я удалил непонятный блок с хуй пойми какими ссылками и не добавил ссылку на предыдущий тред. Остальное оставил как есть. Ну и картинку только одну добавил (они все равно говно), а тот тред ушел на такое днище, что я поначалу подумал, что тут вообще треда про пхп нет (и охуел). Пусть твой "настоящий оп" в следующий раз ушами не хлопает, а следит за своим тредом. Алсо, ты можешь нормальную по твоему мнению шапку или нужную ее часть закинуть сообщением, все равно их пока еще мало. че как маленький?
Оно же тебе пишет, что не может найти драйвер. Еще один вкатывальщик, который не знает английский?
Второй пост с стандартами кодирования ты проебал. И кидай ссылку на перекаты в прошлый тред, там все еще люди сидят.
PHPч, что делать в такой ситуации:
Получаю json пакет с массивами массивов (пикрелейтед 1 и 2).
декодирую его через
json_decode($data, true)
и получаю пикрелейтед 3
казалось бы, всё чики пики, но при попытке обращения к массиву [users]
выходит уведомление о несуществующем индексе users
Notice: Undefined index: users in ...
и
var_dump(jsonDecoded["users"])
выводит NULL. Хотя, казалось бы, данные вот они есть. Щто делать?
Видят, но я например знаю, что если делают перекат, то в старый тред кидают ссылку. Если ссылки нет, значит продолжаем текущий тред. Каталог или нулевую я практически никогда не просматриваю.
>Щто делать
Это похапэ, в нём важно не что делать, а как это делать.
САМОСТОЯТЕЛЬНО ВСЁ ДЕЛАТЬ, вот как.
Бамп
Я давно скачивал (в прошлом году), качал с nnm-club. Ищи там, если осталось
Всё, отбой. Разобрался.
Если будет неплохой скилл, то могут закрыть глаза на отсутствие образования?
<?php
// Инициализируем наше приложение
require __DIR__ . '/../bootstrap.php';
// Получаем список объявлений
$posts = $postService->getAllPosts();
// Вызываем вид, чтобы отобразить их
require __DIR__ . '/../view/post-list.phtml';
Почему у нас контроллер "не видит" модель? Нам достаточно того, что уже затребован bootstrap.php, который как раз "видит" модель? Это обязательное требование - не указывать модель в контроллере, а делать вот так опосредованно?
Ну вот мы же вызываем в браузере контроллер по http://localhost:8001/list.php?
А в контроллере у нас инициализируется $posts = $postService->getAllPosts(); - а это у нас из модели.
Получается, контроллер "видит" $postService->getAllPosts() благодаря тому, что bootstrap.php их затребовал?
>Что значит "не видит", то что нет require?
Ну да, почему именно так, почему нет require __DIR__ . '/../PostService.php'; и require __DIR__ . '/../Post.php'; в самом контроллере? Для чего такой вот буфер, обязательно ли это вообще?
Традиционно в bootstrap отправляют всю инициализацию приложения. Т.е. все что придется делать в начале каждого контроллера. В этом случае я полагаю: подключение к базе данных и создание экземпляра PostService. Нужно избегать повторений кода. Если что то нужно писать больше одного раза, то пора думать как это вынести в функцию, класс или вот такой bootstrap.
Плюс есть еще автозагрузка классов. Это когда есть функция которая занимается подгрузкой нужных файлов при обращении к классам. Подробнее про автозагрузку: https://github.com/codedokode/pasta/blob/master/php/autoload.md
Про базовую структуру есть немного в задаче про список абитуриентов из ОП-поста.
Зовут вот сюда. Что значит базовые знания? Может есть что почитать по пыхопе применительно к практической его части(сайты, например)
Или просто процесс разработки проекта с какими-то примерами кода. Реально такие в интернетах найти?
>Традиционно в bootstrap отправляют всю инициализацию приложения. Т.е. все что придется делать в начале каждого контроллера. В этом случае я полагаю: подключение к базе данных и создание экземпляра PostService. Нужно избегать повторений кода. Если что то нужно писать больше одного раза, то пора думать как это вынести в функцию, класс или вот такой bootstrap.
Спасибо, теперь понятно.
>Плюс есть еще автозагрузка классов. Это когда есть функция которая занимается подгрузкой нужных файлов при обращении к классам. Подробнее про автозагрузку: https://github.com/codedokode/pasta/blob/master/php/autoload.md
Не вполне понятно, где прописывать функцию автозагрузки и обязательная ли она? Если у меня в проекте, допустим, всё так или иначе явно инициализируется?
До задачи про список студентов мне ещё далеко, я туда даже пока и не смотрю
В конкретно замкнулся на автоисправлении "чю/щю"
https://3v4l.org/67RW6
попробуй либо fbox.php
Для задачи про студентов я писал в том же bootstrap.php. Тут тебе решать, если приложение маленькое, то можно и без нее наверно, когда классов становится больше до автозаргузка функций сильно упрощает жизнь. Вообще ее можно написать в учебных целях один раз, т.к. composer (менеджер пакетов для php) предлагает свою функцию. Нужно только разобраться с psr-4 и пространством имен в php. Учись в своем темпе не перегружайся пока.
сначала идет +7 или 8, за ними ровно 10 цифр, между которыми может быть любое число скобок, минусов, пробелов
я понимаю что сначала идет так:
/^(\s|[+])*?
а потом что? Как сделать так чтобы он искал что между цифрами могут быть пробелы скобки и тире?
>>959193
Спасибо, обнадежили. Просто мне знакомые с вышками говорили, что без них вообще сейчас никуда.
Привет! Я сейчас тоже делаю этот урок, но на другой задаче. Может, эту задачу я выполнил неправильно, но по предоставленным ОПом номерам она работает.
>Как сделать так чтобы он искал что между цифрами могут быть пробелы скобки и тире?
Тут как в математике, тебе надо вынести за скобки ((любое количество скобок-тире-пробелов)(любая цифра)(любое количество скобок-тире-пробелов)) * 10 раз.
И заодно подскажите, как надо настроить регулярку? А то она у меня в предложении:
"после таких знаков:восклицательного!И даже"
отсутствие пробела в "знаков:восклицательного" вылавливает, а уже в "восклицательного!И" не вылавливает.
Покажи задания. Интересно посмотреть.
По той ссылке лишь основы программирования (на пхп), это даже не минимум.
Могу устно написать пример. Написать скрипт, что бы в будние дни писался один текст, а в выходные-другой( как я понимаю используется функция date() ) . За это дают 500р. Но заказ уже ушел куда то
http://srp.stanford.edu/design.html
Хочу понять принцип, но везде объясняют туговато для меня (алгебра и матан на нуле). Можно разобрать на примере например https://github.com/RuslanZavacky/srp-6a-demo/tree/master/public или под твоим руководством написать своё.
>>959728
>>959725
А потому что у тебя идет вхождение "знаков:восклицательного", и для следующего вхождения с восклицательным знаком нет начальных буков в регэкспе. Сравни: https://regex101.com/r/XdmE2c/1
Но! Даже здесь не войдет вот такая строка "Что?О!Боги!", так что подумай ещё над условием.
public function getController()
{
if (class_exists($this->controller))return new $this->controller;
}
Ну вы понел. Проблема в том, что не работает с пространствами имен. Т.е. если сделать класс с нужными названием прямо в файле где сделан объект-роутер, то будет работать. А вот прописать такую хуитку return new Controllers\$this->controller уже нельзя. Как можно решить мою траблу? Или я все таки вообще не туда свернул? Аволоад работет нормально, проверял.
>объект-роутер не только у меня разбирает урл, но еще и возвращает объект нужного контроллера
Так это же и есть все цели роутера? Или я что-то не так понял?
Я в йии такой принцип увидел, показалось очень разумным вот и пытаюсь реализовать своими силами.
>А потому что у тебя идет вхождение "знаков:восклицательного", и для следующего вхождения с восклицательным знаком нет начальных буков в регэкспе.
Если я сделаю регулярку типа /(!|;|\.|,|\?)[^ ]/, тогда я не смогу выполнить первое условие задачи, что мол надо возвращать ошибку с куском текста, поэтому я и хотел брать слова целиком. Какой можно еще вариант придумать, чтобы и ошибку поймать, и кусочек текста вывести с ошибкой?
Если тебе нужен именно принцип, а не детали (в которых, как известно, дьявол), то тут всё в принципе просто.
Мы можем передавать пароль плейнтекстом, сервер сравнит его с хранящимся у себя на сервере плейнтекст паролем.
Мы можем передавать пароль плейнтекстом, сервер сделает с ним математическую магию и сравнит с хранящейся у себя математической магией, профит в том, что сервер не знает твой пароль, и не может его слить, минусы в том, что мониторящий трафик злой человек знает твой пароль.
Мы можем делать математическую магию на клиенте и отправлять её по сети, проблема в том, что это эквивалент пароля, мониторящий трафик человек знает хеш, он не знает плейнекстом твой пароль, но он может залогиниться в этот сервис, используя этот хеш в любом случае.
И вот тут начинаются изъебы, как аутентифицировать себя так, чтоб не передавать пароль или эквивалент пароля.
Например, клиент отправляет серверу рандомное число, получает в ответ рандомное число, делает с ними двумя и своим паролем математическую магию, сервер делает с своей копией этих чисел и паролем то же самое, если они совпадают, то ты аутентификацию прошёл. Профит в том, что теперь эти данные одноразовые, так что мониторящий трафик человек не сможет потом залогиниться в сервис, используя то, что он услышал. Новая проблема в том, что зная эти два числа и результат, злой человек сможет попытаться угадать пароль, подставляя свои значения пароля и сравнивая их с результатом.
Один из способов побороть эту проблему, это вот твой срп.
Как можно проще - есть алгоритм Диффи-Хеллмана, согласно ему, клиент придумывает рандомное число a, сервер придумывает рандомное число b, после вычислений, за которыми на википедию, клиент получает A, сервер получает B, после чего они ими обмениваются и клиент получает ключ из серверного B, используя свой a, сервер получает ключ из клиентского A, используя свой b, в итоге у них получается одно и то же число. Идея состоит в том, что подслушивающий знает A и B, но из них математически невозможно получить a и b, которые необходимы для попыток угадывания, и которые не передаются по сети, как в предыдущем способе. СРП пароль в эту адскую смесь, из-за чего это может считаться механизмом аутентификации.
А теперь, почему это всё равно не нужно.
Во-первых, все эти механизмы исходят из того, что сервер уже знает что-то, с чем можно сравнить твой пароль. Так что при изначальной регистрации тебе что-то нужно будет туда передать в любом случае, так что если злой мониторящий человек перехватит момент регистрации, у него всё равно будет твой пароль или его эквивалент. Что ты можешь с этим сделать? Надеяться на https.
СРП вычисления будут исполняться в твоем браузере яваскриптом. Откуда ты получаешь скрипты? От сервера. Как ты можешь доверять этому скрипту и знать что злой человек по пути не подсунул туда что-то другое? Надеяться на https. Так что если ты хочешь чтоб регистрация на твоем сайте была уровня "ввел логин, ввел пароль, нажал войти", можно сразу надеяться на https и делать как обычно.
>>959760
>new Controllers\$this->controller
$newClass = '\Controllers\' . $this->controller;
return new $newClass;
?
Если тебе нужен именно принцип, а не детали (в которых, как известно, дьявол), то тут всё в принципе просто.
Мы можем передавать пароль плейнтекстом, сервер сравнит его с хранящимся у себя на сервере плейнтекст паролем.
Мы можем передавать пароль плейнтекстом, сервер сделает с ним математическую магию и сравнит с хранящейся у себя математической магией, профит в том, что сервер не знает твой пароль, и не может его слить, минусы в том, что мониторящий трафик злой человек знает твой пароль.
Мы можем делать математическую магию на клиенте и отправлять её по сети, проблема в том, что это эквивалент пароля, мониторящий трафик человек знает хеш, он не знает плейнекстом твой пароль, но он может залогиниться в этот сервис, используя этот хеш в любом случае.
И вот тут начинаются изъебы, как аутентифицировать себя так, чтоб не передавать пароль или эквивалент пароля.
Например, клиент отправляет серверу рандомное число, получает в ответ рандомное число, делает с ними двумя и своим паролем математическую магию, сервер делает с своей копией этих чисел и паролем то же самое, если они совпадают, то ты аутентификацию прошёл. Профит в том, что теперь эти данные одноразовые, так что мониторящий трафик человек не сможет потом залогиниться в сервис, используя то, что он услышал. Новая проблема в том, что зная эти два числа и результат, злой человек сможет попытаться угадать пароль, подставляя свои значения пароля и сравнивая их с результатом.
Один из способов побороть эту проблему, это вот твой срп.
Как можно проще - есть алгоритм Диффи-Хеллмана, согласно ему, клиент придумывает рандомное число a, сервер придумывает рандомное число b, после вычислений, за которыми на википедию, клиент получает A, сервер получает B, после чего они ими обмениваются и клиент получает ключ из серверного B, используя свой a, сервер получает ключ из клиентского A, используя свой b, в итоге у них получается одно и то же число. Идея состоит в том, что подслушивающий знает A и B, но из них математически невозможно получить a и b, которые необходимы для попыток угадывания, и которые не передаются по сети, как в предыдущем способе. СРП пароль в эту адскую смесь, из-за чего это может считаться механизмом аутентификации.
А теперь, почему это всё равно не нужно.
Во-первых, все эти механизмы исходят из того, что сервер уже знает что-то, с чем можно сравнить твой пароль. Так что при изначальной регистрации тебе что-то нужно будет туда передать в любом случае, так что если злой мониторящий человек перехватит момент регистрации, у него всё равно будет твой пароль или его эквивалент. Что ты можешь с этим сделать? Надеяться на https.
СРП вычисления будут исполняться в твоем браузере яваскриптом. Откуда ты получаешь скрипты? От сервера. Как ты можешь доверять этому скрипту и знать что злой человек по пути не подсунул туда что-то другое? Надеяться на https. Так что если ты хочешь чтоб регистрация на твоем сайте была уровня "ввел логин, ввел пароль, нажал войти", можно сразу надеяться на https и делать как обычно.
>>959760
>new Controllers\$this->controller
$newClass = '\Controllers\' . $this->controller;
return new $newClass;
?
Алсо, чтобы опытным товарщам не было скучно, то для них можно будет добавить "задачи со звездочкой", в котором нужно будет реазиловать какие-то более сложные функции.
А я потом буду отдавать проекты заказчикам и получать бабло
Наркомания какая-то, такого ты хочешь штоле.
https://3v4l.org/a86Md
Мне не кажется это разумным, роутер должен работать с роутами. Определить какой контроллер отвечает - несомненно, самому его создавать - нахуй надо, просто передать информацию дальше, иначе это лишает тебя возможности, например, ввести систему ивентов в свой фреймворк, где операции "контроллер для роутера определен" и "контроллер создан, метод контроллера вызван" идут отдельно друг от друга и юзер может между ними вставить какую-то свою логику.
http://ideone.com/l2XaUx
Я бы даже рад поучаствовать, да со всеми этими заказами, своими проектами и работой я не могу ухватиться за соломинку того времени, когда можно просто пострадать херней.
>>959829
Хех, а вот это
>В тексте найдена ошибка: " а
чем отличается от
>В тексте найдена ошибка: !И
м? Всё у тебя хорошо там, ну можешь отделить показ ошибок в отдельную функцию и там то уж форматировать вывод как хочешь, с пояснениями и скриншотами.
Пиздоноблядь порвалась?
>Молодец, отличная штука. Ты её сам делаешь, или пулл реквесты принимаешь? У меня есть несколько предложений по улучшению структуры проекта, архитектуры и других вещей. Я могу их подробно описать, потом мы это обсудим в треде или на гитхабе. Как тебе идея? Будет интересный опыт создания чего-то общего нашим уютным тредом.
Любая помощь будет полезна. Мне на самом деле пригодился бы кто-нибудь кто мог поддерживать проект пока меня нет.
Насчет поддерживать проект не знаю, но возможно смогу предоставить тебе бесплатный хостинг для него (включая хранилище под картинки). Только не сейчас, а в конце апреля - начале мая. По коду я могу отписать проблемы какие заметил, насчет фиксить и дополнять я на самом деле не знаю, работа занимает большинство моего времени, но возможно в следующем месяце у меня будет его побольше. Оставь свою почту, куда тебе можно отписать и обсудить эти вопросы. Структуру проекта я думаю лучше обсуждать на гитхабе или где-нибудь в другом месте, чтобы не засорять тред.
>дат фил когда видишь неофита, который не знает что IDE почти всегда ставят вместо таба 4 пробела и что это общепринятый знак хорошего тона
Дай мне роту пробелов и я разобью армию табов.
Ты либо наглухо отбитый, либо тралишь. За таб вместо 4х пробелов в приличной компании уволить могу за нехуй, это нарушение уровня забивания болта на стандарты.
>4 раза жать пробел вместо 1 таба
ну если ты не ценишь свое время, то это причина тебя уволить безусловно.
Просто ты макака которая среду разработки настроить не может.
такие петушинные стандарты могут быть только в петушиных конторах, куда нормальный человек устраиваться не будет
что примечательно, даже на хабрапомойке, несмотря на лютое засилие быдлокодерских пидерах пробелобляди всегда всасывают во всех холиварах
хотя, пробелодебилу нет смысла что-то доказывать, если человек настолько туп что не способен сам особзнать убогость пробелодрисни, с ним не нужно спорить, ему нужно молча ссать в рот
А потом какое-то хуйло поудалет по одному пробелу и кое-где будет не 4 пробела а 3, а другое хуйло превращает таб не в 4 пробела а в 2 и энджой ё пробелопомойка.
Логика очень проста, ты вызываешь new <стринг>, соответственно неймспейс тоже должен быть частью этого стринга, пхп мозгов не хватает литерал неймспейса с стрингом правильно соединить, ай гесс.
Во всех нормальных редакторах, давно табуляция автоматически = 4 пробела.
А дальше каждый дрочит как хочет. Какого хуя вы бугуртите-то тут?
> Интересно, откуда такая логика, что можно сделать $a = new $b, но тоже самое нельзя сделать с неймспейсом?
Можно и с неймспейсами, дело тут не в них, а в приоритетах между операторами new и . (конкатенация): https://secure.php.net/manual/en/language.operators.precedence.php
У new самый высокий приоритет. Такой код будет работать:
$className = 'std' . 'Class';
new $className;
А такой нет:
new 'std' . 'Class';
PHP пытается сначала выполнить new 'std', класса 'std' не находит и падает с ошибкой.
>>960112
>>960103
>>960081
>>960069
Зачем вы на толстоту ведётесь, тот неадекват пришёл сюда не за конструктивным диалогом, вы вступили в грязь, а теперь размазываете её по треду.
>>959035
Есть на архиваче: https://arhivach.org/thread/245785/
https://habrahabr.ru/post/120615/
В статье генерация капчи и хранение md5 от результата в куках.
Почему достаточно будет один раз разгадать капчу и использовать это же значение чтобы потом пробиться?
Никак не могу понять. В скрипте же постоянно всё заново перегенерируется.
Лол, зная лично автора статьи могу сказать, что в 2011 её писал ебаный школьник, так что поискал бы ты что-то получше.
А насчет почему - потому что хранится в куках, блеать.
Сервер отдает тебе куки с хешем капчи, потом от тебя же этот куки забирает и сравнивает его с кодом, который тоже приходит от тебя. Таким образом у тебя после одного удачного угадывания есть пара из кода и куки с хешем, которые проходят проверку, ты можешь теперь игнорировать новые куки и сабмитить всё ту же пару.
Как может получиться 25 человек в департаменте закупок, если
>Департамент закупок: 9×ме1, 3×ме2, 2×ме3, 2×ма1 + руководитель департамента ме2
>9+3+2+2+1=17
?
Вот так решил просто то, что требовалось: https://3v4l.org/ce8iF
Сначала думал сразу сделать так, чтобы антикризисные меры можно было применить (был класс Компания, который создавал департаменты, департаменты создавали работников - в прошлом треде ещё вы подсказывали, за что спасибо), но нет, это для меня пока сложно.
А у меня до этого места просто не доходит. Я не понял изначально где была ошибка, подумал что ошибка в расположении IF. Вот изначальный код с ошибками http://codepad.org/nm9jPcpd
>pasted on Sep 14:
Што?
Ну а так ты прав: ошибка в
if ($creditBalance < 0)
Там, во-первых, $creditBalance никогда не должен быть меньше нуля, он может быть только равен нулю, сам подумай.
А во-вторых, условие там должны быть такое: если $creditBalance с прибавленными 3-мя процентами и тысячей рублей равен нулю. То есть сначала у нас крутится цикл с прибавлением тысячи и трёх процентов, а затем в самом последнем круге выплата с прибавленными процентами и тысячей за обслуживание становится меньше пяти тысяч - анон её выплачивает, после чего цикл останавливается.
>$month <= 20
Неверное условие, слишком не по-программистски это! ОП почему-то не исправил до сих пор. Но он хитёр, это может быть такой задумкой, да.
Там лучше указать такое условие: пока $creditBalance не выплачен (то есть не равен нулю) - это самое естественное условие.
>>960231
Палю годноту: https://www.youtube.com/watch?v=jmIn0dQJF28&index=1&list=PLa9lO_Eq-vZWucOH1auan_m-POa3n7fV6
Вполне можно, сам так хочу сделать, азаза
Конечно, надо где-то увидеть, как это всё функционирует. Программистам в вузиках же показывают всё наглядно, а кто тебе покажет наглядно?
И фреймворк посмотришь, и прочее.
У ОПа так-то про MVC почитай, про БД, это всё тоже поможет.
Я пьян.
Если в цикле, то это должно выглядеть как-то так:
for ($i = 0; $i < 12; $i++). У тебя. До 12 цикл не доходит.
for ($i = 0; $i <= 12; $i++) - дойдет
На самом деле есть простое правило, если начинаешь с 0, то всегда используй < N, если с 1, то <= N, чтоб количество итераций было равно N и ты не путался.
Платиновый вопрос. Нет, так делать не стоит. Будешь ходить по кругу без понимания технологий на которых фреймворк работает, максимум научишься повторять как все делается в видосиках. А вот сделаешь студентов, поймешь что такое MVC, разберешься в ООП и прочем - тогда и фреймворки хорошо зайдут.
А что там показывать то? Я просто не понимаю зачем поперед батьки в пекло лезть. Для тех же студентов надо считай только MVC знать, все остальное гуглится, можно тут спрашивать. Я пока их делал считай свой мини-фреймворк написал, с роутингом, и контроллерами.
Ну вот ты видел, как играют в футбол, даже сам играл, наверное?
А представь, как объяснить человеку, который не видел ни мяча, ни бегать не умеет, как играть в футбол.
Иногда надо просто увидеть, почувствовать, тогда сам начинаешь ощущать себя увереннее и свободнее.
Если он задался целью, то потом всё равно сделает всё как нужно.
>как объяснить человеку, который не видел ни мяча, ни бегать не умеет, как играть в футбол.
Надо показать ему мяч и объяснить правила игры в футбол, не? Ну серьезно же. Пускай язык учит, а потом уже экосистему языка.
>Даже если прочитать и понять исходники фреймворка?
Ебанешься, серьезно. Ну слим еще ладно, может осилишь исходники, но все равно буде куча вопросов "а почему так а не так". Фреймворк так это же готовая архитектура, вот ее и надо понимать.
Cпасибо анон
>Да, с него и собирался начать.
Вот и правильно, там очень понятная и маленькая документация.
Тем более эти МИКРО фреймворк. Например Модель данных ты можешь разрабатывать полностью сам. В общем там минимум абстракций. Можно легко во всем разобраться и делать как тебе хочется.
>а почему так а не так
Это уже вопрос другой плоскости. Есть разные реализации одного интерфейса.
Если ты такой нуб, как говоришь, то лучше написать свой велосипед и не париться. Код фреймворка читать дело очень полезное, но не на этом этапе. Сейчас у тебя просто каша в голвое окажется, какие-то мелочи, выдранные из контекста.
Так он бегать не умеет! Никогда мяч не видел! Не понимает, где свои ворота, а где чужие!
(Я же фигурально.)
Во-первых, если ты реально способен вот просто сесть почитать исходники и разобраться, то ты и студентов написать способен. Во-вторых, когда человеку показывают, как делать, без понимания того, зачем делать - это хуево, это очень хуево. Может если какая-то серия видосиков, где кто-то будет этот фреймворк разбирать по строчке, и то ньюфаг же тупо не сможет отличить, учат ли его нормальным практикам, или какой-то индусской хуйне.
Профит написания своих велосипедов именно в том, чтоб самому прочувствовать, зачем эти компоненты нужны. Типично человек смотрит на незнакомую систему из дохуя компонентов, мозг ему говорит СЛОЖНАБЛЯДЬ, и у него начинаются вопросы "а зачем то, а зачем это, зачем напридумывали тут хуйни, а почему в один файл не засунуть, етц", а вот если он с обратной стороны начнет, засунет всё в один файл и охуеет потом от того, как ему надо будет копипастить код в 15 местах для минимальных изменений, вот этот момент прозрения ничего не заменит.
Ни кто же не говорит брать мастхев типо симфони, юи, лару.
Микро фреймворки - это элементарщина, все что там есть - роутинг, контроллеры, обработчики http запросов и внедрение зависимостей.
>все что там есть - роутинг, контроллеры, обработчики http запросов и внедрение зависимостей.
Гораздо лучше уж самому все это написать.
Я про микрофреймворки и говорю, послать кого угодно читать исходники симфони это, конечно, экспириенс.
Вот эту элементарщину и надо самому писать, роутинг, контроллеры и обработчики, криво, хуево, с хуевым распределением обязанностей, с смешиванием роутера и контроллера в единый организм говно, но своё. Это совершенно не заберет много времени, но предоставит возможность набить все необходимые шишки.
А вот мне например кажется, что косяков будет так много, что человек просто будет топтаться на месте большую часть времени. Вед веб разработка просто нереально быстро развивается даже в области бек-энда.
Есть всё разница между - выучить шаблоны "банды четырех" и зубрить шаблоны в книге Мэтта Занстры.
Есть некоторые фундаментальные вещи, которые нужно знвть, а есть вещи для, которых есть справочник в который можно всегда подсмотреть. Если не отсеивать лишнюю информацию, можно голову забить до уровня шизы, а толку от этого будет мало, ведь время идет технологии меняются.
Если человек будет топтаться на месте при написании примитивнейшнего фронт контроллера, то я боюсь представить, сколько косяков у этого человека будет при использовании более адвансед технологий, может стоит задуматься о другой профессии?
>просто нереально быстро развивается
Угу, все эти блидинг эдж концепты как хттп запрос и ответ, сессии, мвц, ооп и вытекающие. Просто вчера придумали, к завтрашнему дню устареют.
> хттп запрос и ответ, сессии, мвц, ооп
Это все просто абстракции, и да, их реализации меняются.
Ах, да. Это охуительная задачка из учебника про школьника и айфон в кредит. Заранее спасибо.
Охуеть абстракции. Начали говорить про методику обучения, внезапно человека понесло в какую-то метафизику. Всё абстракции над машинным кодом, ёпта. Хттп запросы у него уже абстракции, ну приехали теперь. Нахуя их учить, ведь завтра просто возьмет и поменяется. URI больше не будем парсить, хедеры не будем отправлять, POST GET и прочие отменят. Хуякции, блядь.
Прости, я подумал что вопрос платиновый и не стал вдаваться в подробности.
На пике задача. И мой результат не сходится с тем, что в учебнике.
Я, кстати, тоже на этом же моменте. И у меня тоже почему то выходит не правильно. Идет только до 12 месяца . Хм.
Можно. Мне вот писание своего велосипедного МВЦ ничего ровным счетом не дало. Сейчас даже не вспомню, как его делал, и повторю только с гуглом. А в фреймворках все простенько: в контроллерах роуты, в моделях - работа с бд, во вью хтмл код. хуяк хуяк и готово, в уи даже регистрация и логин сразу из коробки сделаны.
Блять, мудак ну сиди и учи машинные коды, мы тебе перезвоним.
Ну давай вместе думать. Я пока вручную всё посчитаю.
Я разобрался. Ответ под спойлером. В условии надо ставить не 5к, а 4. Вот код если что: http://ideone.com/ZXJxEN
Спасибо, анон. А я все сидел тупил
ОП, у меня тоже была проблема с тем, что по ошибке выдали бан и стёрли все посты. Я отписал в /d, с указанием номера бана (обязательно) и причины, и меня разбанили. Попроси ещё, чтобы посты восстановили.
>не вспомню, как его делал, и повторю только с гуглом
Я не понимаю, как можно было настолько хуево разобраться в такой довольно простой вещи, чтобы быть не в состоянии в любой момент из головы воспроизвести сносное мвс. Если ты не в состоянии, то может ты так ничего и не понял? Нагородил издали похожей хуйни, не вникая, лишь бы работало, и решил что квест комплит?
Посты стерли во второй раз. Я вот сейчас сижу думаю, не пора ли просто перейти на доброчан.
У меня времени нет по 3 раза каждый ответ постить. И на спам и вайп, который мне тут приписывают, у меня тоже времени нет.
Два чаю. Увидел что ОП отвечает в тред, пока мылся всё стерли. При перекате набегают трали, или вообще рандом перекатывает, "Я удалил непонятный блок с хуй пойми какими ссылками". На доброчане хотя бы премодерация есть и треды бесконечные.
Проблема в том, что даже если и разбанят, то слова из спам-листа никто не выбросит, то есть можно опять в бан попасть по непонятной причине. Мне в /d так никто и не объяснил, из-за каких именно слов меня забанили. Захожу на сосач только ради PHP-треда, так что я за Доброчан.
+1 за доброчан.
Но зачем мне эти велосипеды, если я могу взять фреймворк и не париться?
а может, разумнее сначала проводить все операции с суммой платежа, а потом уже проверять, меньше ли она ежемесечного платежа или нет? Прост я смотрю и как-то у тебя реализовано слишком сложно.
и только после этих проверок вычитать из суммы долга 5 тыщ либо сколько там осталось.
>>960424
и да, проверь, твой алгоритм неправильный. Например, если сумма долга будет всего 1000, а не 40 тысяч, то этот долг школьник будет отдавать у тебя 2 месяца. Не очень логично, не находишь?
jQuery, который Джек не строил #3. Первые две jQuery задачи я исправил по твоим советам и все работает (включая плавный скролл на мозилле), не вижу смысла кидать - время у опа отнимать. Алсо использовал букву "X" вместо unicode символа, так как >>958999 .
Желтый фон, если что для визуализации блока. В решении его быть не должно, поэтому я не использую для него css свойство filter, которым я воспользовался для...
> Виджет должен работать с полями ввода любых размеров, цветов (в том числе с белым текстом на черном фоне)
Я получаю JSON, декодирую, и выходит массив array ('response' => 1), в котором к элементу с индексом response я обращаюсь как массив->response, хотя логично будет массив["response"].
У меня есть свой массив, в котором к элементу message я обращаюсь массив["message"], но никак не могу массив->message.
Знаю, что тупой, но я первый день это дело пердолю и не совсем втыкаю. Походу я совсем тупой. В чём проблема?
$zalupa = (object)[ "key" => value]
Если массив привести к типу обьекта, то ключи массива можно использовать как открытые свойства класса.
$zalupa->key;
Для этого у функции json_decode есть второй параметр, он отвечает за то, вернет ли функция объект ($array->key) или обычный массив ($array['key'])
http://php.net/manual/en/function.json-decode.php
При выполнении echo $link;
Ошибка "Catchable fatal error: Object of class mysqli could not be converted to string in "
Алсо
$link = mysqli_connect (HOST, USER, PASS, DB) or die('No connect to Server');
Что нужно с ответом сделать, чтобы можно было использовать $link в mysqli_query($link, $query)?
это я в кратце. если нужно всю функцию то она на первом пике
Если без echo, то ошибка Notice: Undefined variable: link in file.php on line 16
Кажется ошибка именно в том как link принимается я хз
$link вне функции, передавай ее как аргумент
>echo $link;
Ну тебе же пишут, что не может конвертировать объект в строку.
>Что нужно с ответом сделать, чтобы можно было использовать $link в mysqli_query($link, $query)?
Нужно изучить область видимости переменных в PHP. В твоем случае в функции создается новая переменная с именем $link. Нужно передать линк как пораметр функции или объявить $link глобальной переменной.
http://php.net/manual/ru/language.variables.scope.php
>Ну тебе же пишут, что не может конвертировать объект в строку.
Объект надо разбить в массив?
В функцию добавил global $link;. Проблема Undefined variable: link in ушла.
Не уверен, что это как то решило мою проблему.
Функций много и для каждой писать не вариант.
С $GLOBALS еще не пойму как массив захуячить правильно что бы для всех функций было понятно какое свойство у $link.
Пиздец кароче, запутался уже. Не варит башка.
яхз. Наверное рано мне с php связываться ещё. не получается даже объект в строку конвертировать.
Кинга - "Создаем динамические веб-сайты с помощью PHP, MySQL и JavaScript"
Нормальная? Можно по ней учиться?
Ты даже аргумент функции передать не можешь, почитай учебники какие-нибудь или видео курсы на ютабе.
И как перенести данные на 'новую' схему? Для этого нужно использовать Doctrine Migrations? Там есть возможность преобразовать все данные на новый лад? В частности, сгенерировать id для всех записей?
Я мог бы в ручную отредактировать дамп-файл, но будет ли это правильным путем?
>А чем обусловлена необходимость иметь @Id у всех сущностей в Doctrine?
Это с Doctrine связанно, а с самой СУБД И БД.
>>960475
>И как перенести данные на 'новую' схему? Для этого нужно использовать Doctrine Migrations? Там есть возможность преобразовать все данные на новый лад? В частности, сгенерировать id для всех записей?
Если ты изменил сущность ( поля новые добавил/убрал или поменял), то просто делай doctrine:shceme:update
СУБД тут не причем, просто без id доктрина не сможет искать записи. Когда ты делаешь
$em->remove($entity);
$em->flush();
Доктрине как-то надо сгенерировать запрос на удаление, и для этого и нужен id, чтобы получилось
DELETE FROM x WHERE id = ?
или
DELETE FROM x WHERE id1= ? AND id2= ?
Для составных ключей.
Насчет Doctrine migrations: вы оба по моему не поняли, для чего это. В любом нормальном проекте никто не обновляет базу на живую. Генерируются скрипты обновления - миграции - и они уже запускаются. Это позволяет всем разработчикам автоматически обновлять свои копии баз данных.
Есть такой проект: http://docs.doctrine-project.org/projects/doctrine-migrations/en/latest/reference/introduction.html
Это можно использовать даже без Doctrine ORM, оно просто позволяет вручную писать миграции и автоматически прогонять еще не примененные.
Также, есть опция генерации миграции путем сравнения текущей схемы БД и схемы, заданной в описании сущностей: http://docs.doctrine-project.org/projects/doctrine-migrations/en/latest/reference/generating_migrations.html
Но тут я хочу предупредить, что не всегда хорошая идея генерировать схему по описаниям сущностей. Если писать SQL вручную, получается больше возможностей по тонкой настройке таблиц, индексов, ограничений итд. Я думаю, что на практике лучше писать SQL и миграции руками, а автоматическая генерация годится разве что для тех случаев, когда делается по-быстрому какой-то прототип, и никакие подстройки не нужны.
Соответственно doctrine:scheme:update годится разве что для тестирования, так как она не генерирует миграции. Обновлять БД в команде надо через миграции, если человек пишет один то можно конечно и без них, но лучше бы сразу их осваивать.
Самому же удобно, прогнал миграцию на локальном сервере, проверил, если все ок - прогнал на продакшене. А как иначе обновлять несколько баз? руками? руки отвалятся.
СУБД тут не причем, просто без id доктрина не сможет искать записи. Когда ты делаешь
$em->remove($entity);
$em->flush();
Доктрине как-то надо сгенерировать запрос на удаление, и для этого и нужен id, чтобы получилось
DELETE FROM x WHERE id = ?
или
DELETE FROM x WHERE id1= ? AND id2= ?
Для составных ключей.
Насчет Doctrine migrations: вы оба по моему не поняли, для чего это. В любом нормальном проекте никто не обновляет базу на живую. Генерируются скрипты обновления - миграции - и они уже запускаются. Это позволяет всем разработчикам автоматически обновлять свои копии баз данных.
Есть такой проект: http://docs.doctrine-project.org/projects/doctrine-migrations/en/latest/reference/introduction.html
Это можно использовать даже без Doctrine ORM, оно просто позволяет вручную писать миграции и автоматически прогонять еще не примененные.
Также, есть опция генерации миграции путем сравнения текущей схемы БД и схемы, заданной в описании сущностей: http://docs.doctrine-project.org/projects/doctrine-migrations/en/latest/reference/generating_migrations.html
Но тут я хочу предупредить, что не всегда хорошая идея генерировать схему по описаниям сущностей. Если писать SQL вручную, получается больше возможностей по тонкой настройке таблиц, индексов, ограничений итд. Я думаю, что на практике лучше писать SQL и миграции руками, а автоматическая генерация годится разве что для тех случаев, когда делается по-быстрому какой-то прототип, и никакие подстройки не нужны.
Соответственно doctrine:scheme:update годится разве что для тестирования, так как она не генерирует миграции. Обновлять БД в команде надо через миграции, если человек пишет один то можно конечно и без них, но лучше бы сразу их осваивать.
Самому же удобно, прогнал миграцию на локальном сервере, проверил, если все ок - прогнал на продакшене. А как иначе обновлять несколько баз? руками? руки отвалятся.
>Если ты изменил сущность ( поля новые добавил/убрал или поменял), то просто делай doctrine:shceme:update
У меня возникали ошибка когда я делал это. Я думал, это потому что нельзя делать апдейт поверх данных, но теперь я погуглил что это за ошибки и исправил их.
>>960491
>СУБД тут не причем, просто без id доктрина не сможет искать записи.
Легко было предположить что на этом завязано её устройство. Я ещё предполагал, что есть некоторая договоренность между программистами делать для каждой таблицы колонку с id.
>Обновлять БД в команде надо через миграции, если человек пишет один то можно конечно и без них, но лучше бы сразу их осваивать.
Сейчас освою...
>>960423
Я сделал всё через жопу, но оно работает.
http://ideone.com/ZXJxEN
Вот так на свет и появляются говнокодеры.
Хочу забыдлокодить диванный стартап, очередной никому не нужный сервис. Я правильно выбирают технологию?
Что рассматриваю:
1. быстро и легко кодить, крутые фреймворки
2. низкая стоимость владения. vps не нужен. пойдет копеешный шаред хостинг (этот пункт еще актуален?)
>for (;;)
Плохой подход.
Попробуй заменить на другой тип цикла: foreach или while.
>if ($credit<4000)
Это вообще никак разумно не объяснить, откуда взялись 4к, откуда взялось это условие?
Неверный подход, хотя и считает вроде бы верно, потому что говнокод, который не поддерживается и не имеет смысла.
Теперь, когда ты разобрался в работе цикла, мог бы переписать.
Но ты не станешь, ведь ты же ленивая задница, ага, да, я тебя знаю.
>if ($credit<4000)
Это из-за того что, каждый месяц начисляется 1000 рублей комиссии. Если ставить 5000, то он ещё один круг делает. Что-то пока не получается придумать альтернативный вариант.
>for (;;)
Заменил на while ($credit>0)
>Пацаны. php еще жив?
Более чем. С седьмой версией очень приятный стал, с тайпхинтингом и быстротой. Дальше они еще JIT компиляцию сделают, если все пойдет хорошо.
>Я правильно выбирают технологию?
Зависит от задач. Если ты хочешь сделать что-нибудь в реалтайме (чат, к примеру), то PHP тут вряд ли подойдет. Если у тебя что попроще (обработать запрос пользователя, отдать ему ответ и завершить выполнение) то вполне можешь брать PHP.
>пойдет копеешный шаред хостинг (этот пункт еще актуален?)
Тут уже зависит от того насколько нагруженным будет проект и как ты архитектуру построишь.
>СУБД тут не причем, просто без id доктрина не сможет искать записи. Когда ты делаешь
Это просто фейспалм. Почитай хоть про индексацию и нормализацию данных в бд.
Я тут вообще мимо проходил, а div и mod не завезли в пхп? Число символов после запятой не многова-то?
>Если ты хочешь сделать что-нибудь в реалтайме (чат, к примеру), то PHP тут вряд ли подойдет.
Ето мы еще посмотрим.
Я знаю что есть Ratchet, но никогда не видел чтобы его в продакшене кто-нибудь использовал. Легче взять проверенные временем библиотеки на ноду или пайтон.
Нет, просто ты дол>>960612
>никогда не видел чтобы его в продакшене кто-нибудь использовал.
Если ты не видел - это не значит, что его никто не использует.
Я вообще на симфоновском http://symfony.com/doc/current/components/http_foundation.html#streaming-a-response буду пытаться сначала сделать.
Если понадобится более производительный чат, то перепешу это сервер на Го или Си/C++ на крайняк.
Но обмазываться питоном да еще И Н О Д О Й я точно не буду.
>Дальше они еще JIT компиляцию сделают, если все пойдет хорошо.
Поясните ньюфагу, что это изменит для среднего крокодила? Просто скорость выполнения скриптов увеличится?
> скорость выполнения скриптов увеличится
Да, но это не точно. + переносимость, не придется таскать с собой все исходники, чтобы что-то запустить.
Они уже делали разок так. И у них ничего не получилось.
>Это из-за того что, каждый месяц начисляется 1000 рублей комиссии. Если ставить 5000, то он ещё один круг делает.
Ну вот хоть тресни - не пойму, почему 4к, а не 3к, не 2к? Если бы как-то было связано с имеющимися значениями - было бы понятно.
Представь, это работающее приложение, а другому программисту что-то надо в нём поменять, - так он же не поймёт этого условия.
>Что-то пока не получается придумать альтернативный вариант.
Нужно исходить из того, в чём суть действий, это и ставить в условия.
1. Анону нужно выплатить кредит, поэтому цикл должен, поэтому цикл будет продолжаться, пока сумма кредита больше нуля.
2. Когда сумма кредита (с процентами и тысячей за обслуживание!) меньше 5000 - выплачиваем только её и завершаем цикл.
Всё, тут больше ничего нет.
>>960603
О, вот тут уже всё отлично!
>$total=$total+5000;
Лучше избегать использования подобных цифр, когда у нас есть переменная для обозначения сути. Это же $payment, так пусть там и будет она.
Отлично, братишка, верной дорогой идёшь!
Прости за "ленивую задницу", был не прав.
>переносимость, не придется таскать с собой все исходники, чтобы что-то запустить.
Это в принципе тогда можно будет заказчику отдавать байткод, а исходный код у тебя остается до оплаты проекта. Для фриланса очень круто.
Ну да впринципе. Сейчас тоже так можно делать, но это денег стоит.
Как быстро вкотиться в конструктор битрикса? Посоветуйте видеокурс или что-то вроде (русский, доступный на шару) Чтоб за пару-тройку часов уже уметь верстать лендинги и прочие несложные страницы? Верстать более-менее умею, там вообще какие-то есть отличия от html/css или других визивиг-редакторов веб-страниц? Может, кто возьмется помочь через скайп/телеграм/етц? Да, я чому-то не вижу на торрентах этого самого битрикса, его где брать, только с офф-сайта качать триал? Оно мне в системе не насрет?
Не по себе стало от её зомбированности.
Ты чего такой злой?
Ну контроллер это я имею ввиду что-то типа books/categories, если страница заглавная то и контроллера нет.
>Ну контроллер это я имею ввиду что-то типа books/categ
Ну тогда все заебись.
Еще в место ?some_param=some_value
можно просто парсить значение из URL.
/controller/action/some_value
friendly url же давно во всех нормальных решениях, станет site.com/this-is-my-hello-world-page/param1value/param2value
контроллер и экшн исчезают, на их место приходит какой-то генерируемый из контента тайтл, параметры все без ?, = и &, просто слэшами разделены.
Большое спасибо, всё исправил. Теперь выглядит красиво и понятно.
Да, она самая.
>>960932
Ну нет, спасибо, анон, но это для меня пока еще чертовщина какая-то, какие-то непонятно вообще как работающие классы-айди... С ходу (если не смотреть в хеад на линки на жс) вообще выглядит как какой-то умный хтмл, лол. Я до бутстрапа пока еще не дорос, мне бы в азах jQuery разобраться сначала...
К середине лета я уже буду вовсю пользоваться своим первым приложением.
>>960965
Хочу друга с хотя бы одним общим интересом.
Круто, у меня почти та же фигня, я бы тоже хотел хотя бы одного друга. Но нет желания учить 100500 говнофреймворков на полгода. жКвери, бутстрап - да, в свое время. Ресты, боны, ангуляры - нахуйнахуй, мне не так много платят за это дерьмо. А ближайшие два месяца у меня госы и диплом, вот.
Что там понимать, бутстрап js подключается, он крутит эту карусель. Надо только структуру как там задать, структура ниже объяснена еще.
Что у вас спрашивали при первом собеседование по пхп?в понедельник иду на собеседование, немного волнуюсь, поэтому спрошу у вас.
Как долго длилось собеседование, что спрашивали?
>Английский на уровне чтения технической документации
Как они проверять его будут?типа дадут листик и попросят прочитать или как?
Стоит ли забивать на универ или как?
Специальность разработчик программного обеспечения, она нужна мне или лучше что-то другое выбрать?
>Специальность разработчик программного обеспечения, она нужна мне или лучше что-то другое выбрать?
Тебе нужно что угодно, что может прокатить за бакалавра в IT (computer sience, computer networking etc) для последующей эмиграции. Т.е. нужно узнать смогли ли выпускники твоего ВУЗа устроится на этом вашем западе. Как узнать? Найти в соц. сецях и спросить "Были ли проблемы с подтверждением диплома при получении разрешения на работу?".
>Если ты хочешь сделать что-нибудь в реалтайме (чат, к примеру), то PHP тут вряд ли подойдет.
чаты на пхп были еще на заре инета
>Потребление кофе или зарплата не являются свойствами так как они вычисляются из других свойств и хранить их не надо.
ОП, ну зачем это? Понятно, что тут при создании работника надо тупо проверять профессию, чтобы определить кофе, зарплату и страницы.
Но не усложнение ли это?
Вот тут я сделал без такого: >>960162
Почему бы просто не сделать это всё свойством класса?
Смотришь на класс и свойства - видишь кофе, зарплату, страницы, а так надо смотреть в метод addEmployee, чтобы это всё узнать или поменять?
Это сделать не проблема же, просто смысл в чём, ведь неудобно же! Захочешь поменять - меняешь в свойстве соответствующего класса, а не в этом методе.
Я хочу вкатываться постепенно. Хочу код, который могу допиливать, а не сделатьохуенно.мин.жс
Ну вот так сделал, как предлагаешь в подсказках: https://3v4l.org/IC9kb
Реально кажется это менее удобным, чем если бы было в свойствах.
Я помню, ты всегда говорил, что всё то, что может вычисляться, не надо хранить, но если мы представим, что нам надо создать миллионы экземпляров работников, то это будет большей нагрузкой, чем просто хранить свойства в их классах, разве нет?
Загоняюсь, но ведь ты способствуешь этому и это хорошо.
У else не может быть условия. Для этого есть elseif.
http://php.net/manual/en/control-structures.elseif.php
Ох, каков я аутист. Не надо было у else писать что-то. Чего то ступил.
Что ты имеешь ввиду под "учить вместе"?
Да как-то из головы вылетел. Знал же.
Такая же проблема с числами.
Потому что у тебя в блоке if оператор присваивания, а не сравнения.
http://php.net/manual/en/language.operators.comparison.php
Почитай документацию основам языка прежде чем такие вопросы задавать.
Ну зачем ты так?
попробуй так еще if ($p = count("Hitler"))
Бамп Бампоевич Бампов.
https://3v4l.org/RpEMF
https://github.com/TheSidSpears/TestHub/blob/master/src/AppBundle/Entity/User.php
https://github.com/TheSidSpears/TestHub/blob/master/src/AppBundle/Entity/Test.php
Создаю связь author-test OneToMany, ожидаю увидеть в логе нормальные значения, но почему то автора не выводит. В чём может быть косяк?
Про кубики, все написал от руки, всё работает, но в моём браузер не работает перенос строки. Т.е это \n не работает. Всё пишется сплошняком, а в опере вообще траблы с кодировкой. Меня такие мелочи волнуют.
https://ideone.com/eIgrnT
Кодировкапроблемы.
>>961180
Вообще-то в фигурный скобки. http://ru.stackoverflow.com/questions/192085/Зачем-нужны-кавычки-и-фигурные-скобки-this-name
Да, я сразу же пофиксил, просто ссылку забыл в после поменять. Однако почему не работает перенос строки в брауезере?
Файл index.php, запущен openserver.
Анон, не игнорь меня пожалуйста.
Пиздец я тупой? Почему это не работает? Цикл прогоняется ровно 1 раз, почему?
> нормальные значения
Ты хочешь, чтобы тесты сразу джойнились с автором? Доктрина по умолчанию не джойнит всё, что возможно, а создаёт прокси-классы: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/working-with-objects.html
Для получения теста с автором можно использовать DQL с джойном, можно указать доктрине подгружать конкретную связь жадно (указав fetch="EAGER" в ManyToOne аннотации), но это наверное не очень гибко.
Ещё у тебя там метод setAuthorId в классе Test, зачем? Доктрина это о том, как работать с объектами, а не с айдишниками из БД.
>>961192
HTML разметка игнорирует переводы строк. Если нужно их сохранить, то можно обернуть вывод echo в тег <pre>
>>961210
> if ($bank = 1000000) {
Это присвоение, а не сравнение. Может будет интересно: https://ru.wikipedia.org/wiki/Условия_Йоды/
Апач-то у шаред хостеров.
Я бы вообще новичкам советовал встроенный в PHP веб-сервер - никакой мороки с установкой + запуск проще некуда + все ошибки сразу в консоль, не нужно искать логи (некоторые новички о них просто не знают). А то люди банально не осиливают установку всего руками и скатываются к васяносборкам.
http://docs.doctrine-project.org/projects/doctrine-migrations/en/latest/reference/introduction.html#use-as-supplement
Если я использую Pimple и PSR-4 могу я загрузить этот класс через них?
bootstrap.php
use Doctrine\DBAL\Migrations;
$container['Migrations'] = function () {
return new Migrations();
};
...
http://docs.doctrine-project.org/projects/doctrine-migrations/en/latest/reference/introduction.html#configuration
>The last thing you need to do is to configure your migrations. You can do so by using the –configuration option to manually specify the path to a configuration file.
-configuration это опция чего? Через doctrine:migrations -configuration ошибка о несуществующей команде.
Я создал вручную файл migrations.xml и скопировал туда код из манула поменяв путь к папке с классами миграциий.
При выполнении любой комманды в консоле возникает ошибка:
Loading configuration from file: migrations.xml
[Symfony\Component\Debug\Exception\FatalThrowableError]
Class 'DOMDocument' not found
http://docs.doctrine-project.org/projects/doctrine-migrations/en/latest/reference/introduction.html#use-as-supplement
Если я использую Pimple и PSR-4 могу я загрузить этот класс через них?
bootstrap.php
use Doctrine\DBAL\Migrations;
$container['Migrations'] = function () {
return new Migrations();
};
...
http://docs.doctrine-project.org/projects/doctrine-migrations/en/latest/reference/introduction.html#configuration
>The last thing you need to do is to configure your migrations. You can do so by using the –configuration option to manually specify the path to a configuration file.
-configuration это опция чего? Через doctrine:migrations -configuration ошибка о несуществующей команде.
Я создал вручную файл migrations.xml и скопировал туда код из манула поменяв путь к папке с классами миграциий.
При выполнении любой комманды в консоле возникает ошибка:
Loading configuration from file: migrations.xml
[Symfony\Component\Debug\Exception\FatalThrowableError]
Class 'DOMDocument' not found
nl2br($string) в php используй же.
Вообще-то правильно настроенный апач + php-fpm не хуже nginxа.
Вон почитай
https://dracony.org/stop-using-php-fpm-to-argue-using-nginx-vs-apache/
Делаю chown -R usarname /opt/lampp/htdocs/projectname/
chmod -R 755 /opt/lampp/htdocs/projectname/
Но доступа нету
http://sqlfiddle.com/#!9/c53f34/1
Долго ломал голову и исписал не один лист в длинющих таблицах из декартовых произведений.
У меня несколько решений разной степени неадекватности.
1) с использованием таблицы 'всё_что_можно_лайкнуть': http://sqlfiddle.com/#!9/3cfb52/2
Плюсы:
- легко добавить новый вид сущности, которую можно лайкать (просто добавляем новую таблицу)
Недостатки:
- Костыли при каждой вставке сущности
2) все лайкабельные сущности в одну таблицу: http://sqlfiddle.com/#!9/989697/3
Плюсы:
- вставка сущностей без костылей
Недостатки:
- Для каждой новой сущности нужно добавлять новый столбец в таблице likes, нужно не забыть добавить уникальный ключ.
1, только полиморфные связи осуществляются не только по id, но и по table_name/model_name. В целом фреймворки работу с такими вещами автоматиизируют вполне.
>>961558
Вроде бы идею полиморфных связей понял, таблица лайков будет выглядеть так:
| id| from_user | likeable_type | likeable_id|
| 1 | 1_______| PHOTO_____| 1_______|
| 2 | 1_______| USER______| 2_______|
(Юзер 1 поставил лайк Фотографии 1 и Юзеру 2)
Но внешний ключ тут можно проставить только для from_user, а как ставить ограничения на likeable_id - непонятно.
Используй силу, люк. Что хочешь, то и пиши, только свич не везде подходит. Есть мнение что то иф, то сфитч медленнее (мнения расходятся), но это такая себе на спичках экономия. Я еще неистово злоупотребляю словарями, что поидее и того и другого медленее, но когда у меня полсотни обработчиков для динамических данных можно ебануться в условия впихивать.
Cмотри по ситуации. Обычно switch-case читается проще, чем нагромождение из if-elseif-elseif. Но у switch есть недостатки:
- он по умолчанию использует нестрогое сравнение (==)
- в if-ах можно делать более хитрые проверки, например if ($a instanceof Foo)
Я наверное не совсем правильно выразился. Имел виду, что сохранять данные на диск мне не нужно, мне нужно все распарсить, а потом использовать для создания своей страницы. Все на ходу, без сохранения.
То есть мне нужно создать класс Profile, предусмотреть в нем все необходимые переменные, потом создать объект этого класса и запихнуть туда распарсенные данные. Правильно?
Сделай две таблицы, photo_likes и user_likes, которые содержат связи like_id-photo_id или user_id. На них уже можешь внешние ключи ставить. А в твоей таблице тогда только первые 3 колонки останутся.
В php есть DOM, в него грузишь твою страницу, потом используешь xquery, чтобы получить данные из нужных узлов. Это не задача класса Profile, он должен уже готовые данные получать через конструктор. Пишешь другой класс HtmlStatsLoader, который весь XML парсит и данные в нужных местах отдает, потом связываешь с Profile через конструктор. Получится что-то вроде $profile = new Profile($loader->getUser(), $loader->getLevel(), $loader->getStats(), $loader->getEquipment()) ну и дальше в таком духе. Дальше чтобы сохранить Profile, пишешь класс XmlProfileSaver, который в конструктор принимает твой объект класса Profile, вытаскивает из него данные и сохраняет в xml через тот же php dom.
Не юзал твой phpQuery, судя по описанию просто какая-то тупая надстройка над DOm в стиле jquery. Обычно DOMа и Xquery для всех подобных задач по уши хватает, синтакс там не сложный.
Я когда-то пробовал и обосрался с иксквери. Ну вот смотри, что выходит с этой библиотекой. Красиво же по большим кускам сразу разобрал, а потом эти большие куски уже разребу по переменным.
Вот целый код, чет не догадался сразу весь заскринить.
В xquery ты точно так же эти куски получить можешь прямыми запросами. Дальше ты просто тот же дом юзаешь, как у тебя на скринах. Не вижу смысла со стороннюю либу мучать, если делает все то же самое, что встроенные в php средства.
Ну фиг знает, я купился еще на то, что в какой-то статье говорилось о сравнении скорости работы, и эта штука работала "в 8 раз быстрее, чем встроенные в пхп методы".
Пикрилейтед моя предыдущая попытка, я там обосрался и мне надоело гуглить, так что можешь не пояснять в чем была проблема.
С виду все правильно, вангую у нод были свои childnodes, их надо было тоже через dom или xquery доставать. Тут var_dump/die помогает.
По скорости - первая ссылка в гугле говорит, что phpquery твой парсит заново документ на каждой итерации, т.е. при каждом запросе селектора. Так что уже тормознее будет. Если скорость важна, вообще лучше через expat parser в php читать, он просто один раз проходит по всем нодам и кидает тебе эвенты, весь dom даже не нужно в память грузить.
Вполне возможно, у меня средней сложности xml импортер на expat переписать заняло дня 2. Если плохо в dom ориентируешься, уйдет больше.
Распарсил таки с помощью phpQuery, очень легко вышло. В результате имею объект, который могу вертеть, как захочу.
https://github.com/Si0n/fileshare-project
http://archive-ipq-co.narod.ru/l1/functions.html
https://ideone.com/VHVCW8
Я верно посчитал?
Меня лишь смутил ввод новой переменной ради единовременной выплаты за открытие счета в последнем банке, кажется это лишнее и нужно как-то покрасивее это сделать.
Третий банк не наебал.
Юзаю <br>, потому что код проверю в браузере, а он не переносит строку с помощью /n.
Нет, задача решена неверно.
Второй банк нужен для того, чтобы после задачи про Айфон проверить правильность работы скрипта. Во втором банке должно было получиться 61270, ты что, про Айфон не решал задачу?
Также у тебя не определена переменная $sum перед циклом как пустая, как ноль или подобное. Функции должны работать с известными им переменными, которые или в аргументах туда идут (в скобках), или внутри самой функции определяются.
https://ideone.com/zSuvX5
Теперь верно, но я пока не догоняю почему так. Я всего лишь вынес вычисление остатка по кредиту за условие, в начало цикла.
Скрин. Избавляйся, иначе в большом приложении вообще не будет работать, это Идеоне такой лояльный.
Также лучше разделять пробелами выражения, а то сложно читается в таком виде:
>$value+$comiss+($value*$persent/100);
>Я всего лишь вынес вычисление остатка по кредиту за условие, в начало цикла.
Так и должно быть - сначала сумма кредита увеличивается на проценты и тысячу за обслуживание, а потом подпадает под действия условий в if...else.
В контроллере использовал use Illuminate\Http\Request; и use Request;
Далее
public function store {
$input = Request::all();
return $input;
}
Но как сделать такое же с Collective\Html? Request:all уже не работает.
Не стукайте только, я меньше недели занимаюсь
PDO ships with PHP 5.1, and is available as a PECL extension for PHP 5.0; PDO requires the new OO features in the core of PHP 5, and so will not run with earlier versions of PHP.
ebat' ti ostryak pryam ahuet'
どうもありがとう
Таки какой вопрос, такой и ответ, гой.
Ежу понятно, что в таком виде это огромная дыра в безопасности, потому что было так:
https://github.com/grigoryMovchan/auth/blob/auth_mvc/app/models/AuthModel.php
а стало так:
https://github.com/grigoryMovchan/STKApps/blob/master/app/models/AuthModel.php
Как вообще белые люди делают, когда стоит такая задача?
Киркоров, Билан, Басков.
Ну не знаю, вроде неплохо, а где дыра?
А еще спасибо ОП-у за паттерн TDG. С отделением SQL кода от основного намного свободнее себя чувствую.
У меня есть годовалый сайтик для 50 человек, где я внезапно обнаружил уже ~900к файлов сессий, из них >850к пустых, гостевых.
Как так и что делать?
И да, удалять сессии по лайфтайму не хочу. Хочу реюзать сессии четче и не создавать их для гостей.
Зачем мне читать про нормализацию, если я писал про нее уроки?
Каким образом "индексация" (и что это такое, кстати? Это ты так пишешь слово "индекс"?) требует наличия первичного ключа? Не надо сбивать людей с толку.
В MySQL можно создавать таблицы без первичных ключей. И можно делать составные первичные ключи.
Тебе самому сначала стоит почитать документацию.
>>960612
Как можно писать что-то на ноде или питоне если там даже тайп-хинтов нет?
>Как можно писать что-то на ноде или питоне если там даже тайп-хинтов нет?
Но ведь TypeScript в котором более развиты тайпхинты чем сейчас в PHP
Как бы да, но надо уточнить, проверяется ли хэш на "истинность" на стороне сервера по ip. Так-то айпишник используется в генерации хэша.
Подозреваю, что всем на все пох - спер куку, перенес на другую машину и привет, хоть обзапрещайся.
Если бы я параноил, то, наверное, сделал бы лайфтайм для сессии или большую кнопку ВЫХОД.
Белые люди, кстати, еще делают педаль "выйти из всех сессий".
Закрываю вопрос. Пока оставлю как есть
>>962164
Сайт-визитку можно за несколько дней сделать по уроку https://laravel.ru/docs/v5/quickstart-intermediate
- DOM который построил Джек, 5: проверено тут http://arhivach.org/thread/245785/#956739
- https://github.com/never3ver/fileshare - проверено 19 марта: http://arhivach.org/thread/245785/#956732
Далее, на доброчане в /s/ в PHP треде (ссылку на всякий случай давать не буду, а то у нас тут свободное общение) я проверил некоторые другие задачи, почитайте ответы к ним:
>>958664 задача с регулярками и телефонным номером, от 22 марта
- студенты https://github.com/sylenien/students-exercise/tree/master
- блог https://github.com/honeydev/s-blog/
- p-sch 19/03/17 >>956914 - вопрос по обработке исключений
- https://github.com/grigoryMovchan/auth/
- https://bitbucket.org/learning_acc/discounts/
- https://github.com/kubk/students
- https://github.com/greenTea242/MinesweeperMVC
Зайдите, посмотрите.
Ну и как всегда, если кого-то из предыдущего треда пропустил, напомните о себе.
>Сайт-визитку можно за несколько дней сделать по уроку
Хотя, уже не советую. Только что вспомнил, что в последней версии ларавела есть отличия от информации из урока. Без некоторых знаний можно не въехать даже прочитав советы в комментариях.
Я еще и вагрант неделю пердолил, пока разобрался. Теперь понимаю, почему многие программисты так высокомерно к новичкам относятся - очень быстро забываешь, как пердолился с чем-то одним неделями.
Видел ответ в прошлом треде. Многие советы реально улучшили мой код. Спасибо.
Не все еще успел изучить и применить. Надо пока одну поделку допилить и приступлю к урокам из оппоста
Кстати, вот та поделка на основе авторизации. Код говно, но это зато поддерживать хоть как-то можно, благодаря MVC, а отличии от того что было.
https://github.com/grigoryMovchan/STKApps
В presta shop миграция БД специальными скриптами, где sql схема смешана с вызовами Php функций, которые в отдельных файлах лежат.
Пример:
https://github.com/PrestaShop/PrestaShop/blob/develop/install-dev/upgrade/sql/1.6.1.1.sql
А вот парсер этого:
https://github.com/PrestaShop/PrestaShop/blob/e1e72b4faa122013684d3b202311cab48a2c3ba8/src/PrestaShopBundle/Install/Upgrade.php
Норм такая схема миграции, или лучше бывает?
return App\Category::all(); возвращает мне всё как надо в JSON, но я хочу сделать API без 'user_id'. Куда копать?
Забыл, laravel 5.4
>>958750
Он не может найти драйвер для соединения с БД. одно из двух: либо в конфиге ларавеля у тебя выбран неправильный, либо у тебя не установлено какое-то расширение PHP (pdo, pdo_mysql и тд).
>>958791
>>958904
Ты наверно кроме PHP еще что-то ставил.
Судя по интернету, php-fpm ставится только пакетом php5-fpm, соответственно ты его наверно выбрал. Проблем никаких нет, ты легко можешь отключить сервис php-fpm с помощью systemctl disable, погугли статьи про systemd вроде такой: http://vladimir-stupin.blogspot.ru/2013/02/systemd-1.html
>>958849
php companion
docblockr
emmet (для HTML/CSS)
jshint gutter
По всем этим расширениям конечно надо прочесть документацию, сами по себе они ничего не делают.
>>958999
Нужен как минимум шрифт, содержащий эти символы.
Можно попробовать выполнить советы отсюда: http://unicode.org/help/display_problems.html
Тут пишут, немного по другой проблеме (юникодные символы то появляются, то исчезают) https://superuser.com/questions/520355/permanent-fix-for-unicode-characters-not-displaying-correctly-as-boxes что иногда помогает создание на рабочем столе файла с японскими символами в тексте.
Но я не уверен, что это надо делать. Если ты используешь их на сайте, твои пользователи вряд ли будут что-то менять в настройках и устанавливать. Тебе лучше всего подключить на страницу веб-шрифт (font-face), в котором они есть, чтобы они 100% отображались.
У меня например кандзи отображаются, а многие юникодные символы - тоже нет.
Тут есть примеры шрифтов с указанием диапазонов символов в них: https://en.wikipedia.org/wiki/Unicode_font
Какие символы есть в веб-шрифтах, легко проверить на Google Fonts.
>>958750
Он не может найти драйвер для соединения с БД. одно из двух: либо в конфиге ларавеля у тебя выбран неправильный, либо у тебя не установлено какое-то расширение PHP (pdo, pdo_mysql и тд).
>>958791
>>958904
Ты наверно кроме PHP еще что-то ставил.
Судя по интернету, php-fpm ставится только пакетом php5-fpm, соответственно ты его наверно выбрал. Проблем никаких нет, ты легко можешь отключить сервис php-fpm с помощью systemctl disable, погугли статьи про systemd вроде такой: http://vladimir-stupin.blogspot.ru/2013/02/systemd-1.html
>>958849
php companion
docblockr
emmet (для HTML/CSS)
jshint gutter
По всем этим расширениям конечно надо прочесть документацию, сами по себе они ничего не делают.
>>958999
Нужен как минимум шрифт, содержащий эти символы.
Можно попробовать выполнить советы отсюда: http://unicode.org/help/display_problems.html
Тут пишут, немного по другой проблеме (юникодные символы то появляются, то исчезают) https://superuser.com/questions/520355/permanent-fix-for-unicode-characters-not-displaying-correctly-as-boxes что иногда помогает создание на рабочем столе файла с японскими символами в тексте.
Но я не уверен, что это надо делать. Если ты используешь их на сайте, твои пользователи вряд ли будут что-то менять в настройках и устанавливать. Тебе лучше всего подключить на страницу веб-шрифт (font-face), в котором они есть, чтобы они 100% отображались.
У меня например кандзи отображаются, а многие юникодные символы - тоже нет.
Тут есть примеры шрифтов с указанием диапазонов символов в них: https://en.wikipedia.org/wiki/Unicode_font
Какие символы есть в веб-шрифтах, легко проверить на Google Fonts.
Объект модели создается в bootstrap.php, и сохраняется в переменную $postsService . Контроллер просто обращается к этой переменной. Так как переменная глобальная (создана не внутри функции), то она видна везде.
Если ты изучал Си, то в PHP include/require это совсем другая вещь. require просто выполняет код из указанного файла. То есть достаточно где-то один раз сделать require для класса, этот класс будет описан в файле, PHP его запомнит, и второй раз делать require уже не надо.
Так как приложение маленькое то проще всего вызвать файлы с описанием классов в bootstrap, создать все нужные объекты и потом не мучаться. В большом приложении используем PSR-4 и автозагрузку классов, и DI container.
>>959289
Думаю, это то, что описано в моем учебнике + на всякий случай перечитать мануал PHP.
По созданию сайтов можешь посмотреть наше задание про студентов в шапке либо код популярной CMS вроде Wordpress (сложно, лучше сначала сделать студентов).
>>959353
Логично автозагрузку сделать в bootstrap-файле, так как он отвечает за подготовку приложения к работе, и в том числе настройку автозагрузки. Ведь она понадобится в любом случае, и куда еще ее поместить?
Использовать автозагрузку не обязательно, можно просто руками зареквайрить все классы в bootstrap, если их мало.
Для чю/щю хватит одной регулярки. Просто надо в выражении для замены использовать $0, $1, $2 ... - это выражение берет кусок строки, захваченный соответствующими скобками в регулярке или всей регуляркой для $0. Подробнее в мануале по preg_replace.
Так мы можем поставить букву (ч/щ), которая была в исходном тексте.
Пример:
echo preg_replace("/(ж|ш)([аоуэыи])/ui", '0 = $0, 1 = $1, 2 = $2', 'шипы'); // 0 = ши, 1 = ш, 2 = и
Вместо того, чтобы передавать type числом, лучше бы совместить поиск и замену в одной функции.
>>959464
Я тебе помочь не смогу. Без цифр пока программировать не получится. Не понимаю, почему тебя это пугает, ведь считать придется компьютеру, а не тебе.
>>959545
Некоторые компании на наличие диплома смотрят. Нужно иметь уровень выше других, иначе отстутствие диплома будет минусом при прочих равных.
>>959663
Так и надо, поставить скобки и указать повторение 10 раз.
любые буквы в любом количестве - зак - любые буквы в любом количестве
>>959723
Было бы полезно еще усвоить основы HTML/CSS/JS, основы SQL, какую-нибудь простую CMS. Ну и имей в виду, что на простые задачи конкурс большой, сам понимаешь, чем больше способных справиться, тем ниже цена.
Если хочешь побыстрее, можно начать с верстки, но там конкуренция выше.
>>959725
Вместо твоих магических цифр лучше передавать в checking() фразу для замены.
А еще можно сделать массив вида [ регулярка => замена ] и циклом его обойти.
Выражение /\bз(д[а-яё]+ заменит "здание" на "сдание".
> ([^,;.])( )(а|но)
Это выражение ошибется если идет запятая, за ней 2 пробела и за ними слово.
> if ($error == true){
Можно просто if (count($matches[0]) > 0)
Сама идея решения верная, надо регулярки доработать.
> И заодно подскажите, как надо настроить регулярку? А то она у меня в предложении:
> "после таких знаков:восклицательного!И даже"
> отсутствие пробела в "знаков:восклицательного" вылавливает, а уже в "восклицательного!И" не вылавливает
Это потому, что твоя регулярка при совпадении захватывает идущие за символами буквы, и поиск нового совпадения начинается после них. Надо либо не захватывать все слово после знака препинания, либо использовать утверждения при поиске (http://php.net/manual/ru/regexp.reference.assertions.php )
То есть для поиска символов перед "но" можно попробовать использовать утверждение (?<) но там есть свои ограничения.
Также, еще один вариант - просто применять регулярку в цикле, пока есть что заменять.
любые буквы в любом количестве - зак - любые буквы в любом количестве
>>959723
Было бы полезно еще усвоить основы HTML/CSS/JS, основы SQL, какую-нибудь простую CMS. Ну и имей в виду, что на простые задачи конкурс большой, сам понимаешь, чем больше способных справиться, тем ниже цена.
Если хочешь побыстрее, можно начать с верстки, но там конкуренция выше.
>>959725
Вместо твоих магических цифр лучше передавать в checking() фразу для замены.
А еще можно сделать массив вида [ регулярка => замена ] и циклом его обойти.
Выражение /\bз(д[а-яё]+ заменит "здание" на "сдание".
> ([^,;.])( )(а|но)
Это выражение ошибется если идет запятая, за ней 2 пробела и за ними слово.
> if ($error == true){
Можно просто if (count($matches[0]) > 0)
Сама идея решения верная, надо регулярки доработать.
> И заодно подскажите, как надо настроить регулярку? А то она у меня в предложении:
> "после таких знаков:восклицательного!И даже"
> отсутствие пробела в "знаков:восклицательного" вылавливает, а уже в "восклицательного!И" не вылавливает
Это потому, что твоя регулярка при совпадении захватывает идущие за символами буквы, и поиск нового совпадения начинается после них. Надо либо не захватывать все слово после знака препинания, либо использовать утверждения при поиске (http://php.net/manual/ru/regexp.reference.assertions.php )
То есть для поиска символов перед "но" можно попробовать использовать утверждение (?<) но там есть свои ограничения.
Также, еще один вариант - просто применять регулярку в цикле, пока есть что заменять.
Надеюсь, сам общий принцип (клиент доказывает серверу, что знает пароль, а сервер - клиенту, при этом сам пароль не передается) тебе понятен и нужны пояснения только по математике?
Это довольно важное свойство, так как значит, что если злоумышленник захватит или подменит сервер, он все равно не получит пароль от клиента. В ssh для защиты от подмены сервера используют уникальные ключи у каждого сервера, но если сервер не подменен, а взломан, то тут они не помогут.
Вот от каких атак защищает алгоритм:
- перехват переданных по сети данных
- взлом сервера и попытка восстановить пароль из базы данных на диске
- взлом сервера, с целью дождаться соединения пользователя, и вычислить или выманить его пароль. Злоумышленник сможет перехватить в этом случае зашифрованные данные после расшифровки, но сам пароль - нет.
Также, там упомянуто, что на сервере не хранится сам пароль, а хранится "cryptographic verifier derived from the password", то есть это даже не хеш от пароля, а число, полученное из хеша.
Рассмотрим сам алгоритм.
> q and N = 2q + 1 are chosen such that both are prime (which makes q a Sophie Germain prime and N a safe prime). N must be large enough so that computing discrete logarithms modulo N is infeasible.
Это пока понятно.
> g is a generator of the multiplicative group.
Вот это уже сложнее. Это уже пошла сложная математика, попробуем разобраться:
Кликаем по ссылке и читаем описание:
1) https://ru.wikipedia.org/wiki/Сравнение_по_модулю
(тут, если читать постепенно, все относительно понятно)
2) https://ru.wikipedia.org/wiki/Мультипликативная_группа_кольца_вычетов
> Мультипликативная группа кольца вычетов
В криптографии часто используется арифметика с использованием модуля (остатка от деления) на какое-то число N. Это усложняет выполнение обратных операций. Одно дело, если мы возвели число в квадрат - мы всегда можем взять корень и получить исходное число, а другое дело, если мы например взяли от результата только 3 последние цифры (остаток от деления на 1000) - тут уже корень взять становится труднее, мы будет вынуждены использовать перебор (возводим числа от 1 до N в квадрат и сравниваем последние цифры), что сильно замедлит нам нахождение исходного числа. Может и есть какие-то пути ускорить этот перебор, но в любом случае, выполнение обратной операции получается дольше, чем исходной (возведение в квадрат).
При операциях с модулем N числа a - 2N, a - N, a, a + N, a + 2N сравнимы, так как дают тот же остаток от деления на N. Более того, некоторые математические операции с ними дадут сравнимый результат (то есть одинаковый остаток).
Например, a в квадрате и (a + N) в квадрате дадут сравнимый результат (если взять остаток от деления на N). Проверь.
Набор таких сравнимых чисел называют "классом вычетов числа a по модулю N" (congruence class or residue class). Таких классов будет ровно N и вместе они называются "полная система вычетов по модулю N" (complete residue system modulo n). "вычет" - видимо значит "остаток от деления".
Систему "вычетов" можно рассматривать как ограниченное множество чисел (от 0 до N-1), и можно определить, какие есть свойства у этих "чисел", что получается при выполнении разных операций над ними (все операции с учетом модуля N). Это подробно расписано в первой статье.
Далее, мы можем из этих чисел еще убрать те, которые имеют общие делители с N (ну например, если N = 14, то число 6 мы убираем, так как 6 и 14 оба делятся на 2, убираем 7 и 8, а 9 оставляем так как оно взаимно простое с 14). Если мы оставим только взаимно простые с N числа, то получается "Приведённая система вычетов по модулю N" (reduced residue system modulo n).
Особенности таких "систем вычетов" описываются во второй статье, "Мультипликативная группа кольца вычетов". "Мультипликативная" - это от слова "умножение" по-латински, "группа" - это какой-то математический термин, "кольцо" - тоже. Можешь сам поискать определения.
"Группы", "поля" и "кольца" появились, когда математики начали абстрагировать операции вроде сложения и умножения, и применять их не только к числам, но к "классам вычетов", каким-то функциям, многочленам и т.д, и выяснять, как эти операции работают над множествами этих объектов. Можешь поискать их определения, если хочешь.
Возвращаясь к генератору, что же такое генератор? Я погуглил, и нашел это:
- https://crypto.stanford.edu/pbc/notes/numbertheory/gen.html
- https://ru.wikipedia.org/wiki/Первообразный_корень_(теория_чисел)
- http://e-maxx.ru/algo/primitive_root
Генератор (или primitive root, или первообразный корень группы), это такое число, которое мы берем из этой группы, возводим в степени от 1 до x и получаем все другие числа в этой группе (с учетом остатка от деления разумеется). Тут важно понимать, что как только мы получим в результате возведения сам генератор, то круг замкнется, числа начнут повторяться, и если мы не успели получить все числа в группе к этому моменту, то уже никогда их не получим.
Вот там приводили пример для N = 9, и группы из чисел {1, 2, 4, 5, 7, 8}. Если мы берем в качестве генератора 2, и возводим его в разные степени, то получаем:
2 ^ 1 ~ 2
2 ^ 2 ~ 4
2 ^ 3 ~ 8
2 ^ 4 ~ 7 (остаток от деления 16 на 9 = 7)
2 ^ 5 ~ 5 ( = 32 % 9)
2 ^ 6 ~ 1 (= 64 % 9)
2 ^ 7 ~ 2
2 ^ 8 ~ 4
и далее снова будут получаться те же числа. Число 2 при возведении дает все остальные числа из группы. Потому число 2 может служить генератором для этой группы.
А если мы попробуем взять число 4:
4 ^ 1 ~ 4
4 ^ 2 ~ 7
4 ^ 3 ~ 1
4 ^ 4 ~ 4
Оно дает нам только числа 4, 7, 1 и не даст остальные числа из группы. 4 не является генератором группы N = 9.
Число 2 хорошо тем, что если его возводить в разные степени, получаются все возможные числа из группы. Число 4 плохо тем, что получаются не все числа. Зачем это нужно?
Операция возведения g в степень по модулю труднообратима. Если мы возьмем секрет w, и получим из него открытый ключ W = g ^ w mod N, то восстановить w, зная g, N и W очень сложно и долго. Эта операция называется дискретное логарифмирование: https://ru.wikipedia.org/wiki/Дискретное_логарифмирование
Она будет использована в алгоритме для того, чтобы защитить секретные числа при передаче.
Ты бы мог заметить, что хеш-функция тоже труднообратима, чем она хуже? У возведения в степень есть интересная особенность, которой нет у хеш-функции:
(g ^ a) ^ b = g ^ (ab) = (g ^ b) ^ a
Допустим Иван знает число a, а Петр знает b. Иван вычисляет A = g ^ a, Петр вычисляет B = g ^ b, они ими обмениваются в открытую. Затем Иван вычисляет S = B ^ a = (g^b) ^ a = g ^ (ab), а Петр вычисляет A ^ b и получает то же число S. Теперь они оба знают общий секрет S, а злоумышленник, хоть и видит A и B, не может из них получить a и b и вычислить S. На этом свойстве и основам алгоритм обмена. У хеш-функции такой особенности нет, она тут не подходит. Кстати, это я описал протокол Диффи-Хеллмана, если ты с ним знаком (советую прочесть):
https://ru.wikipedia.org/wiki/Протокол_Диффи_—_Хеллмана
> Хотя сама показательная функция вычисляется достаточно эффективно, даже самые современные алгоритмы вычисления дискретного логарифма имеют очень высокую сложность, которая сравнима со сложностью наиболее быстрых алгоритмов разложения чисел на множители.
Важно, чтобы g было именно генератором группы. Генератор при возведении в степень дает любое число из группы. Если это не так, то при возведении в степень будет получаться не любое число, а только часть чисел из группы, и будет проще подобрать число, которое при возведении в степень даст такое же W.
..... далее ниже
Надеюсь, сам общий принцип (клиент доказывает серверу, что знает пароль, а сервер - клиенту, при этом сам пароль не передается) тебе понятен и нужны пояснения только по математике?
Это довольно важное свойство, так как значит, что если злоумышленник захватит или подменит сервер, он все равно не получит пароль от клиента. В ssh для защиты от подмены сервера используют уникальные ключи у каждого сервера, но если сервер не подменен, а взломан, то тут они не помогут.
Вот от каких атак защищает алгоритм:
- перехват переданных по сети данных
- взлом сервера и попытка восстановить пароль из базы данных на диске
- взлом сервера, с целью дождаться соединения пользователя, и вычислить или выманить его пароль. Злоумышленник сможет перехватить в этом случае зашифрованные данные после расшифровки, но сам пароль - нет.
Также, там упомянуто, что на сервере не хранится сам пароль, а хранится "cryptographic verifier derived from the password", то есть это даже не хеш от пароля, а число, полученное из хеша.
Рассмотрим сам алгоритм.
> q and N = 2q + 1 are chosen such that both are prime (which makes q a Sophie Germain prime and N a safe prime). N must be large enough so that computing discrete logarithms modulo N is infeasible.
Это пока понятно.
> g is a generator of the multiplicative group.
Вот это уже сложнее. Это уже пошла сложная математика, попробуем разобраться:
Кликаем по ссылке и читаем описание:
1) https://ru.wikipedia.org/wiki/Сравнение_по_модулю
(тут, если читать постепенно, все относительно понятно)
2) https://ru.wikipedia.org/wiki/Мультипликативная_группа_кольца_вычетов
> Мультипликативная группа кольца вычетов
В криптографии часто используется арифметика с использованием модуля (остатка от деления) на какое-то число N. Это усложняет выполнение обратных операций. Одно дело, если мы возвели число в квадрат - мы всегда можем взять корень и получить исходное число, а другое дело, если мы например взяли от результата только 3 последние цифры (остаток от деления на 1000) - тут уже корень взять становится труднее, мы будет вынуждены использовать перебор (возводим числа от 1 до N в квадрат и сравниваем последние цифры), что сильно замедлит нам нахождение исходного числа. Может и есть какие-то пути ускорить этот перебор, но в любом случае, выполнение обратной операции получается дольше, чем исходной (возведение в квадрат).
При операциях с модулем N числа a - 2N, a - N, a, a + N, a + 2N сравнимы, так как дают тот же остаток от деления на N. Более того, некоторые математические операции с ними дадут сравнимый результат (то есть одинаковый остаток).
Например, a в квадрате и (a + N) в квадрате дадут сравнимый результат (если взять остаток от деления на N). Проверь.
Набор таких сравнимых чисел называют "классом вычетов числа a по модулю N" (congruence class or residue class). Таких классов будет ровно N и вместе они называются "полная система вычетов по модулю N" (complete residue system modulo n). "вычет" - видимо значит "остаток от деления".
Систему "вычетов" можно рассматривать как ограниченное множество чисел (от 0 до N-1), и можно определить, какие есть свойства у этих "чисел", что получается при выполнении разных операций над ними (все операции с учетом модуля N). Это подробно расписано в первой статье.
Далее, мы можем из этих чисел еще убрать те, которые имеют общие делители с N (ну например, если N = 14, то число 6 мы убираем, так как 6 и 14 оба делятся на 2, убираем 7 и 8, а 9 оставляем так как оно взаимно простое с 14). Если мы оставим только взаимно простые с N числа, то получается "Приведённая система вычетов по модулю N" (reduced residue system modulo n).
Особенности таких "систем вычетов" описываются во второй статье, "Мультипликативная группа кольца вычетов". "Мультипликативная" - это от слова "умножение" по-латински, "группа" - это какой-то математический термин, "кольцо" - тоже. Можешь сам поискать определения.
"Группы", "поля" и "кольца" появились, когда математики начали абстрагировать операции вроде сложения и умножения, и применять их не только к числам, но к "классам вычетов", каким-то функциям, многочленам и т.д, и выяснять, как эти операции работают над множествами этих объектов. Можешь поискать их определения, если хочешь.
Возвращаясь к генератору, что же такое генератор? Я погуглил, и нашел это:
- https://crypto.stanford.edu/pbc/notes/numbertheory/gen.html
- https://ru.wikipedia.org/wiki/Первообразный_корень_(теория_чисел)
- http://e-maxx.ru/algo/primitive_root
Генератор (или primitive root, или первообразный корень группы), это такое число, которое мы берем из этой группы, возводим в степени от 1 до x и получаем все другие числа в этой группе (с учетом остатка от деления разумеется). Тут важно понимать, что как только мы получим в результате возведения сам генератор, то круг замкнется, числа начнут повторяться, и если мы не успели получить все числа в группе к этому моменту, то уже никогда их не получим.
Вот там приводили пример для N = 9, и группы из чисел {1, 2, 4, 5, 7, 8}. Если мы берем в качестве генератора 2, и возводим его в разные степени, то получаем:
2 ^ 1 ~ 2
2 ^ 2 ~ 4
2 ^ 3 ~ 8
2 ^ 4 ~ 7 (остаток от деления 16 на 9 = 7)
2 ^ 5 ~ 5 ( = 32 % 9)
2 ^ 6 ~ 1 (= 64 % 9)
2 ^ 7 ~ 2
2 ^ 8 ~ 4
и далее снова будут получаться те же числа. Число 2 при возведении дает все остальные числа из группы. Потому число 2 может служить генератором для этой группы.
А если мы попробуем взять число 4:
4 ^ 1 ~ 4
4 ^ 2 ~ 7
4 ^ 3 ~ 1
4 ^ 4 ~ 4
Оно дает нам только числа 4, 7, 1 и не даст остальные числа из группы. 4 не является генератором группы N = 9.
Число 2 хорошо тем, что если его возводить в разные степени, получаются все возможные числа из группы. Число 4 плохо тем, что получаются не все числа. Зачем это нужно?
Операция возведения g в степень по модулю труднообратима. Если мы возьмем секрет w, и получим из него открытый ключ W = g ^ w mod N, то восстановить w, зная g, N и W очень сложно и долго. Эта операция называется дискретное логарифмирование: https://ru.wikipedia.org/wiki/Дискретное_логарифмирование
Она будет использована в алгоритме для того, чтобы защитить секретные числа при передаче.
Ты бы мог заметить, что хеш-функция тоже труднообратима, чем она хуже? У возведения в степень есть интересная особенность, которой нет у хеш-функции:
(g ^ a) ^ b = g ^ (ab) = (g ^ b) ^ a
Допустим Иван знает число a, а Петр знает b. Иван вычисляет A = g ^ a, Петр вычисляет B = g ^ b, они ими обмениваются в открытую. Затем Иван вычисляет S = B ^ a = (g^b) ^ a = g ^ (ab), а Петр вычисляет A ^ b и получает то же число S. Теперь они оба знают общий секрет S, а злоумышленник, хоть и видит A и B, не может из них получить a и b и вычислить S. На этом свойстве и основам алгоритм обмена. У хеш-функции такой особенности нет, она тут не подходит. Кстати, это я описал протокол Диффи-Хеллмана, если ты с ним знаком (советую прочесть):
https://ru.wikipedia.org/wiki/Протокол_Диффи_—_Хеллмана
> Хотя сама показательная функция вычисляется достаточно эффективно, даже самые современные алгоритмы вычисления дискретного логарифма имеют очень высокую сложность, которая сравнима со сложностью наиболее быстрых алгоритмов разложения чисел на множители.
Важно, чтобы g было именно генератором группы. Генератор при возведении в степень дает любое число из группы. Если это не так, то при возведении в степень будет получаться не любое число, а только часть чисел из группы, и будет проще подобрать число, которое при возведении в степень даст такое же W.
..... далее ниже
продолжение
В нашем алгоритме, к счастью, вычислять генератор не требуется. В нем и q, и g выбираются заранее, например, берутся из какого-нибудь справочника, спецификации. Также, их можно сгенерировать командой openssl dhparam, указав требуемую сложность в битах. Вот тут пример: https://wiki.openssl.org/index.php/Diffie-Hellman_parameters
Вот пример команды: openssl dhparam -text 1024
Она сгенерирует и выведет простое число q и генератор g для N = 2^q + 1.
У меня это вывело длинное простое число q, закодированоое в 16-чном виде и генератор, равный 2.
То есть мы закладываем q, N, g на этапе написания кода.
Также заранее мы вычисляем число k по формуле k = H(N, g), где H - хеш-функция (например, md5, sha1 и тд). Мы как-то смешиваем N и g (например, разделив их двоеточием) и берем хеш. Тут при вычислении хеша лучше числа кодировать не цифрами вроде "123", а в двоичном виде, и брать хеш от двоичной строки.
Теперь вернемся к описанию алгоритма. Для начала, нам надо на сервере из пароля получить что-то менее подбираемое, чтобы злоумышленник не мог, захватив базу, восстановить пароль:
> x = H(s, p) (s is chosen randomly)
Мы генерируем случайную соль, получаем хеш пароля с солью (простейший пример: $hash = md5("$salt:$pass")). Для надежности советуют в хеш еще и логин, и имя хоста добавить (чтобы они были разные даже при одинаковых паролях у 2 пользователей).
> v = g^x (computes password verifier)
Затем получаем password verifier путем возведения в степень (разумеется по модулю N). Этот v мы и сохраняем на сервере, вместе с логином пользователя I и солью s (тройку I, s, v). Как я понимаю, восстановить по нему исходный пароль можно разве что перебором.
Заметь, что пароль обработан дважды: сначала хеш-функцией, затем возведением. Это усиливает защиту на тот случай, если в одном из двух алгоритмов найдется слабость. Соль нужна, чтобы для одинаковых паролей у 2 пользователей хеши получались разные и нельзя было понять, что пароли одинаковые.
Теперь посмотрим, как происходит обмен данными:
> User -> Host: I, A = g^a (identifies self, a = random number)
Пользователь генерирует случайное (большое) число a и вычисляет из него A. Он отправляет на сервер логин и это число A.
Число a - это что-то вроде секрета, который знает только пользователь. Получить a из A очень трудно и долго.
> Host -> User: s, B = kv + g^b (sends salt, b = random number)
Сервер в ответ генерирует случайное число b, вычисляет из него B и шлет пользователю пару (s, B). b - это секрет сервера. Число B составлено смешиванием v и случайного числа b, так что восстановить из него v нельзя, не зная b, а b знает только сервер.
a и b стоит хранить в памяти (не сохранять на диск) и очищать ее после разрыва соединения. Как только a и b уничтожены, восстановить что-то по перехваченным данным становится очень сложно.
Оба они затем вычисляют параметр u:
> Both: u = H(A, B)
Опять же, тут мы смешиваем числа A, В, например, разделив их двоеточием, и берем хеш. Хеш наверно нужен для повышения стойкости?
Пользователь далее вычисляет сессионный ключ K:
> User: x = H(s, p) (user enters password)
> User: S = (B - kg^x) ^ (a + ux)
Здесь мы видим, что пользователь по сути вычисляет то же самое число v (g^x), что хранится на сервере, затем по формуле B - kg^x вычисляет g^b и возводит его в степень (a + ux). Попробуем немного преобразовать выражение для S:
(B - kg^x) = g^b (смотри выше формулу для B)
S = (g^b) ^ (a + ux) = g ^ (b *(a + ux)) = g ^ (ba + bux) = g ^ ba * g ^ (bux) = g ^ ba * (g ^ x) ^ (bu)
Тут надо вспомнить что g ^ x = v, подставим это в выражение.
S = g ^ ba * v ^ (bu)
Ну и далее из S мы зачем-то вычисляем хеш и получаем сессионный ключ:
> User: K = H(S)
Теперь посмотрим, что делает сервер:
> Host: S = (Av^u) ^ b (computes session key)
Преобразуем формулу для S:
A = g^a
S = (Av^u) ^ b = ((g ^ a) * v ^ u) ^ b = (g ^ a) ^ b * (v ^ u) ^ b = g^(ab) * v ^ (ub).
да это тот же самый ключ, что посчитал пользователь! То есть получается так:
- пользователь отправляет на сервер логин и число A, вычисленное из случайного секретного числа a
- сервер отправляет пользователю соль s и B, вычисленное из секретного случайного b и числа, полученного из пароля v
- они делают вычисления и получают одинаковый сессионный ключ S. Берут от него хеш K.
При этом важно, что сторонний наблюдатель, перехвативший A, B, s, не способен из них получить S. Тут используется факт необратимости хеш-функции, и то, что для операции g ^ a по модулю трудно произвести обратную операцию.
Имея K, сервер и клиент проверяют, что они получили одинаковое число (чтобы проверить, что они оба - те, за кого себя выдают). Затем этим K шифруются данные с помощью симметричного шифрования.
Также там есть несколько проверок на нулевые значения, так как умножение на ноль дает тоже ноль и видимо что-то ломает в формулах выше.
Разберем принципы устройства алгоритма:
- стойкость алгоритма основана на 2 принципах: сложности обратимости хеша и сложности обращения возведения в степень по модулю. Это сделано для защиты при обнаружении слабости в одном из алгоритмов.
- случайные (криптографически случайные) числа a, b нужны, чтобы сессионный ключ был непредсказуем, не вычислен из каких-то известных значений. b еще используется для защиты v при передаче числа B.
- v используется при вычислении S, чтобы сессионный ключ еще зависел от пароля и без знания пароля его было не получить.
- v является общим секретом, который знают и пользователь, и сервер
- злоумышленник не знает ни a, ни b, ни v
- g выбирается по определенным правилам, чтобы оно было генератором, чтобы при возведении его в степень мы могли получить любое другое число из группы (а не часть этих чисел, что может упростить перебор).
Важно еще то, что K вычисляется из случайный чисел a, b, хранящихся только в памяти и уничтожающихся после генерации K. После закрытия соединения K тоже уничтожается.
Ну вот теперь у тебя достаточно знаний, чтобы попробовать реализовать это в программе.
продолжение
В нашем алгоритме, к счастью, вычислять генератор не требуется. В нем и q, и g выбираются заранее, например, берутся из какого-нибудь справочника, спецификации. Также, их можно сгенерировать командой openssl dhparam, указав требуемую сложность в битах. Вот тут пример: https://wiki.openssl.org/index.php/Diffie-Hellman_parameters
Вот пример команды: openssl dhparam -text 1024
Она сгенерирует и выведет простое число q и генератор g для N = 2^q + 1.
У меня это вывело длинное простое число q, закодированоое в 16-чном виде и генератор, равный 2.
То есть мы закладываем q, N, g на этапе написания кода.
Также заранее мы вычисляем число k по формуле k = H(N, g), где H - хеш-функция (например, md5, sha1 и тд). Мы как-то смешиваем N и g (например, разделив их двоеточием) и берем хеш. Тут при вычислении хеша лучше числа кодировать не цифрами вроде "123", а в двоичном виде, и брать хеш от двоичной строки.
Теперь вернемся к описанию алгоритма. Для начала, нам надо на сервере из пароля получить что-то менее подбираемое, чтобы злоумышленник не мог, захватив базу, восстановить пароль:
> x = H(s, p) (s is chosen randomly)
Мы генерируем случайную соль, получаем хеш пароля с солью (простейший пример: $hash = md5("$salt:$pass")). Для надежности советуют в хеш еще и логин, и имя хоста добавить (чтобы они были разные даже при одинаковых паролях у 2 пользователей).
> v = g^x (computes password verifier)
Затем получаем password verifier путем возведения в степень (разумеется по модулю N). Этот v мы и сохраняем на сервере, вместе с логином пользователя I и солью s (тройку I, s, v). Как я понимаю, восстановить по нему исходный пароль можно разве что перебором.
Заметь, что пароль обработан дважды: сначала хеш-функцией, затем возведением. Это усиливает защиту на тот случай, если в одном из двух алгоритмов найдется слабость. Соль нужна, чтобы для одинаковых паролей у 2 пользователей хеши получались разные и нельзя было понять, что пароли одинаковые.
Теперь посмотрим, как происходит обмен данными:
> User -> Host: I, A = g^a (identifies self, a = random number)
Пользователь генерирует случайное (большое) число a и вычисляет из него A. Он отправляет на сервер логин и это число A.
Число a - это что-то вроде секрета, который знает только пользователь. Получить a из A очень трудно и долго.
> Host -> User: s, B = kv + g^b (sends salt, b = random number)
Сервер в ответ генерирует случайное число b, вычисляет из него B и шлет пользователю пару (s, B). b - это секрет сервера. Число B составлено смешиванием v и случайного числа b, так что восстановить из него v нельзя, не зная b, а b знает только сервер.
a и b стоит хранить в памяти (не сохранять на диск) и очищать ее после разрыва соединения. Как только a и b уничтожены, восстановить что-то по перехваченным данным становится очень сложно.
Оба они затем вычисляют параметр u:
> Both: u = H(A, B)
Опять же, тут мы смешиваем числа A, В, например, разделив их двоеточием, и берем хеш. Хеш наверно нужен для повышения стойкости?
Пользователь далее вычисляет сессионный ключ K:
> User: x = H(s, p) (user enters password)
> User: S = (B - kg^x) ^ (a + ux)
Здесь мы видим, что пользователь по сути вычисляет то же самое число v (g^x), что хранится на сервере, затем по формуле B - kg^x вычисляет g^b и возводит его в степень (a + ux). Попробуем немного преобразовать выражение для S:
(B - kg^x) = g^b (смотри выше формулу для B)
S = (g^b) ^ (a + ux) = g ^ (b *(a + ux)) = g ^ (ba + bux) = g ^ ba * g ^ (bux) = g ^ ba * (g ^ x) ^ (bu)
Тут надо вспомнить что g ^ x = v, подставим это в выражение.
S = g ^ ba * v ^ (bu)
Ну и далее из S мы зачем-то вычисляем хеш и получаем сессионный ключ:
> User: K = H(S)
Теперь посмотрим, что делает сервер:
> Host: S = (Av^u) ^ b (computes session key)
Преобразуем формулу для S:
A = g^a
S = (Av^u) ^ b = ((g ^ a) * v ^ u) ^ b = (g ^ a) ^ b * (v ^ u) ^ b = g^(ab) * v ^ (ub).
да это тот же самый ключ, что посчитал пользователь! То есть получается так:
- пользователь отправляет на сервер логин и число A, вычисленное из случайного секретного числа a
- сервер отправляет пользователю соль s и B, вычисленное из секретного случайного b и числа, полученного из пароля v
- они делают вычисления и получают одинаковый сессионный ключ S. Берут от него хеш K.
При этом важно, что сторонний наблюдатель, перехвативший A, B, s, не способен из них получить S. Тут используется факт необратимости хеш-функции, и то, что для операции g ^ a по модулю трудно произвести обратную операцию.
Имея K, сервер и клиент проверяют, что они получили одинаковое число (чтобы проверить, что они оба - те, за кого себя выдают). Затем этим K шифруются данные с помощью симметричного шифрования.
Также там есть несколько проверок на нулевые значения, так как умножение на ноль дает тоже ноль и видимо что-то ломает в формулах выше.
Разберем принципы устройства алгоритма:
- стойкость алгоритма основана на 2 принципах: сложности обратимости хеша и сложности обращения возведения в степень по модулю. Это сделано для защиты при обнаружении слабости в одном из алгоритмов.
- случайные (криптографически случайные) числа a, b нужны, чтобы сессионный ключ был непредсказуем, не вычислен из каких-то известных значений. b еще используется для защиты v при передаче числа B.
- v используется при вычислении S, чтобы сессионный ключ еще зависел от пароля и без знания пароля его было не получить.
- v является общим секретом, который знают и пользователь, и сервер
- злоумышленник не знает ни a, ни b, ни v
- g выбирается по определенным правилам, чтобы оно было генератором, чтобы при возведении его в степень мы могли получить любое другое число из группы (а не часть этих чисел, что может упростить перебор).
Важно еще то, что K вычисляется из случайный чисел a, b, хранящихся только в памяти и уничтожающихся после генерации K. После закрытия соединения K тоже уничтожается.
Ну вот теперь у тебя достаточно знаний, чтобы попробовать реализовать это в программе.
Один вопрос, который я не очень понял, зачем в алгоритме число k?
Тут написано: для защиты от атаки, позволяющей проверить 2 пароля за соединение: http://crypto.stackexchange.com/questions/6328/why-does-the-srp-6-calculation-of-b-include-a-multiplier-k-3/18724#18724
И тут анон еще тебе прокомментировал вопрос: >>959839
>>959760
Вообще, это не задача роутера, создавать контроллер. Обычно он просто получает на вход УРЛ и возвращает имя контроллера, действия и дополнительные параметры.
Иногда роутер объединяют с фронт-контроллером и он еще и создает и вызывает контроллер.
То, что ты предалгаешь, не логично.
>>959839
Случаи бывают разные, может мы заносим пароли в сервер, а потом несем его в дата-центр и после этого подключаемся удаленно. Также, при регистрации мы можем использовать еще какое-то шифрование, того же Диффи-Хеллмана.
Этот алгоритм отличается от Диффи-Хеллмана парой особенностей: он проводит аутентификацию, как клиента сервером, так и сервера клиентом. Это важно, если злоумышленник перерезал наш канал и воткнул туда свой сервер - Диффи-Хеллман тут никак не спасет, он только шифрует данные от перехвата.
Ну просто для сравнения, в случае ssh, если злоумышленник внедрился в процесс sshd, он получит пароль. А в SRP - нет, хоть и получит передаваемые по каналу данные.
Плюс, он хорошо защищает хранящиеся на сервере верификаторы пароля от восстановления.
> СРП вычисления будут исполняться в твоем браузере яваскриптом.
А если программа-клиент?
>>959846
Похожих букв конечно больше. Для исправления слов лучше наверно сделать так:
- разбить текст на слова
- проверить каждое регуляркой
- в случае обнаружения проблемы, заменить буквы используя strtr и массив замен
ну и твоя программа не найдет английские слова с русскими буквами внутри.
Один вопрос, который я не очень понял, зачем в алгоритме число k?
Тут написано: для защиты от атаки, позволяющей проверить 2 пароля за соединение: http://crypto.stackexchange.com/questions/6328/why-does-the-srp-6-calculation-of-b-include-a-multiplier-k-3/18724#18724
И тут анон еще тебе прокомментировал вопрос: >>959839
>>959760
Вообще, это не задача роутера, создавать контроллер. Обычно он просто получает на вход УРЛ и возвращает имя контроллера, действия и дополнительные параметры.
Иногда роутер объединяют с фронт-контроллером и он еще и создает и вызывает контроллер.
То, что ты предалгаешь, не логично.
>>959839
Случаи бывают разные, может мы заносим пароли в сервер, а потом несем его в дата-центр и после этого подключаемся удаленно. Также, при регистрации мы можем использовать еще какое-то шифрование, того же Диффи-Хеллмана.
Этот алгоритм отличается от Диффи-Хеллмана парой особенностей: он проводит аутентификацию, как клиента сервером, так и сервера клиентом. Это важно, если злоумышленник перерезал наш канал и воткнул туда свой сервер - Диффи-Хеллман тут никак не спасет, он только шифрует данные от перехвата.
Ну просто для сравнения, в случае ssh, если злоумышленник внедрился в процесс sshd, он получит пароль. А в SRP - нет, хоть и получит передаваемые по каналу данные.
Плюс, он хорошо защищает хранящиеся на сервере верификаторы пароля от восстановления.
> СРП вычисления будут исполняться в твоем браузере яваскриптом.
А если программа-клиент?
>>959846
Похожих букв конечно больше. Для исправления слов лучше наверно сделать так:
- разбить текст на слова
- проверить каждое регуляркой
- в случае обнаружения проблемы, заменить буквы используя strtr и массив замен
ну и твоя программа не найдет английские слова с русскими буквами внутри.
на картинке числа от балды поставлены.
Антикризисные меры я бы сделал так: делаем класс АнтикризисныйКомитет и у него 3 метода в стиле применитьМеруN(компания). Метод принимает на вход компанию и что-то в ней меняет, например, увольняет людей. Ну или если тебе хочется заморочиться, можно как-то сделать 3 класса, каждый для своей меры, но не вижу смысла.
У твоего наследования есть один недостаток: нельзя никак догадаться, что при наследовании мы обязаны определить значения вроде $coffee. Лучше сделать в базовом классе абстрактный метод getBasicSalary(), а в наследниках - его реализации. Тогда забыть его реализовать точно не получится.
> public function addEmployee($profession, $number, $rank = 1, $boss = false) {
> for ($i = 0; $i < $number; $i++) {
> $this->employees[] = new $profession($rank, $boss);
Это не очень правильно, что департамент сам создает работников. Лучше сделать метод, в который передается уже созданный employee. А так у тебя нельзя создать отдельно работника и назначить его в департамент.
Да и ты закладываешь ограничение, что у любого работника ровно 2 аргумента в конструкторе. А что если завтра напишут новый класс профессии, где 3 аргумента (например добавится опыт в годах)?
> getTheValues
Лучше printValues
> foreach ($departments as $key => $value) {
Названия плохие. Надо так: foreach ($departments as $department)
Может, еще стоит сделать класс Компания?
>>960231
Лучше бы сначала без, а потом можно добавить Slim или Silex. Это микрофрейморки.
>>960251
Начинающему надо начинать просто с создания отдельных страниц, а не браться за фреймворки, ни написав ни одного index.php
>>960262
Анон еще ни одной страницы не сделал, равновато брать фреймворки, даже микро.
>>960270
Ну вот, а не лучше ли начать с написания своего роутера из ифов, чтобы понять преимущества слимовского с выражениями и зачем он нужен?
>>960279
Есть урок по MVC на гитхабе, там почти целиком пример готового приложения, можно просто сделать как там.
>>960285
Не надо сюда эту идеологию работника на конвейере вбрасывать. У нас нет цели учить людей переписывать примеры кода из видеоурока. У нас есть цель объяснить что и зачем нужно.
на картинке числа от балды поставлены.
Антикризисные меры я бы сделал так: делаем класс АнтикризисныйКомитет и у него 3 метода в стиле применитьМеруN(компания). Метод принимает на вход компанию и что-то в ней меняет, например, увольняет людей. Ну или если тебе хочется заморочиться, можно как-то сделать 3 класса, каждый для своей меры, но не вижу смысла.
У твоего наследования есть один недостаток: нельзя никак догадаться, что при наследовании мы обязаны определить значения вроде $coffee. Лучше сделать в базовом классе абстрактный метод getBasicSalary(), а в наследниках - его реализации. Тогда забыть его реализовать точно не получится.
> public function addEmployee($profession, $number, $rank = 1, $boss = false) {
> for ($i = 0; $i < $number; $i++) {
> $this->employees[] = new $profession($rank, $boss);
Это не очень правильно, что департамент сам создает работников. Лучше сделать метод, в который передается уже созданный employee. А так у тебя нельзя создать отдельно работника и назначить его в департамент.
Да и ты закладываешь ограничение, что у любого работника ровно 2 аргумента в конструкторе. А что если завтра напишут новый класс профессии, где 3 аргумента (например добавится опыт в годах)?
> getTheValues
Лучше printValues
> foreach ($departments as $key => $value) {
Названия плохие. Надо так: foreach ($departments as $department)
Может, еще стоит сделать класс Компания?
>>960231
Лучше бы сначала без, а потом можно добавить Slim или Silex. Это микрофрейморки.
>>960251
Начинающему надо начинать просто с создания отдельных страниц, а не браться за фреймворки, ни написав ни одного index.php
>>960262
Анон еще ни одной страницы не сделал, равновато брать фреймворки, даже микро.
>>960270
Ну вот, а не лучше ли начать с написания своего роутера из ифов, чтобы понять преимущества слимовского с выражениями и зачем он нужен?
>>960279
Есть урок по MVC на гитхабе, там почти целиком пример готового приложения, можно просто сделать как там.
>>960285
Не надо сюда эту идеологию работника на конвейере вбрасывать. У нас нет цели учить людей переписывать примеры кода из видеоурока. У нас есть цель объяснить что и зачем нужно.
Пара советов:
- число 5000 повторяется много раз, его надо вынести в переменную
- лучше не писать длинные выражения в шапке цикла, плохо читается, лучше писать их в теле цикла
- выражение ($credit+($credit*0.03+1000)); повторяется, надо избавиться от повторов
> if ($credit+$service<5000)
Это условие неправильное, так как оно не учитывает проценты, а только комиссию.
Можно сделать так:
- прибавляем проценты и комиссию к остатку долга (!не вычитаем ничего пока!)
- если остаток маленький, выплачиваем сколько осталось и уходим
- иначе платим 5000
«Платим» здесь значит уменьшаем долг и увеличиваем общую сумму выплаченного.
>>961194
на Доброчан запостил потому что, там хоть отвечать на пост можно.
>>960436
Немного не по теме задачи, но почему table? Это же флоатами или на худой конец display: table верстается прекрасно. Если что, у нас есть задачи по HTML/CSS.
Вот кстати решение без использования JS: https://codepen.io/shidhincr/pen/ICLBD - догадаешься, как? Я не догадался.
> var btn = $($("#template-clear-btn").html());
Тут наверно было выгоднее вписать код строчкой, например $('<span...>'), чтобы плагин было проще подключить к странице. Хотя конечно вопрос, что делать, если код более сложный? Простого ответа тут нет. Кто-то в строки вписывает, кто-то в отдельный шаблон и потом как-то собирает в единый файл.
> if (methods.isChromeOrMacClient() &&
> methods.isSearchType(input))
Здесь, к сожалению, есть проблема, что это довольно ненадежный подход:
- где гарантия, что ты перечислил все браузеры, в которых есть крестик?
- где гарантия, что ты не указал тот браузер, где крестика нет?
- что если что-то поменяется в определенной версии браузера?
Как например насчет яндекс-браузера и прочей армии хромоколонов?
Сложно найти какое-то оптимальное решение, я бы наверно попробовал перечислить старые браузеры, в которых крестика точно нет (и которых меньше). Лучше всего конечно просто избегать ситуаций, где надо проверять userAgent, vendor, лучше стараться тестировать фичи, если возможно. Или например выводить крестик снаружи инпута, чтобы точно ни с чем не совпал. Или запретить использовать плагин с полями типа search.
Вот тут человек пытается по нестандартным CSS-селекторам обнаружить наличие крестика:
- http://stackoverflow.com/questions/16234268/detect-input-type-search-clear-button-in-chrome-and-ie10
- http://stackoverflow.com/questions/6942207/html-type-search-detect-clear-button-support
> if (html.attr("dir") == "rtl")
Тут есть важный момент. Ты читаешь атрибут dir, если он задан на html. Но во-первых, dir логично читать на инпуте или его обертке, он может быть разный. Во-вторых, там есть значение auto, когда браузер определяет его сам по содержимому. Что с ним делать?
Я тут поэкспериментировал, и увидел что в Хроме вычисление
window.getComputedStyle($0).direction (это CSS-свойство direction)
дает либо ltr, либо rtl даже при атрибуте dir="auto". Может оно поможет?
Я бы еще обратил внимание на CSS-псевдокласс dir(), который можно было использовать: https://developer.mozilla.org/en-US/docs/Web/CSS/:dir - только оно пока нигде не поддерживается.
Также, есть CSS-правила вроде html[dir=...] .xyz, но они наверно не помогут прочитать dir с инпута.
Насчет позиционирования крестика, обычно просто оборачивают инпут в враппер (инлайн-блок например без указания размеров), и позиционируются относительно враппера. Это имеет те преимущества, что например при растяжении/анимации инпута крестик поедет за ним. Но имеет и недостатки, что добавление враппера может сломать верстку. То есть универсального решения тут нет.
> if (!target.closest(".outer-clear-btn")) {
Это никогда не вернет false так как возвращается объект jQUery. Надо проверять closest().length
Кстати, обнаружил интересную особенность события input при вводе в японской раскладке. Там сначала печатается латинская буква, а когда их набирается несколько, они превращаются в иероглиф. При этом генерируются события keydown/keyup/input, а keypress не генерируется. Оно генерируется только для ввода в латинской или русской раскладке. С другой стороны, совсем древние браузеры input не генерируют.
Так в общем, особых ошибок я не вижу.
Пара советов:
- число 5000 повторяется много раз, его надо вынести в переменную
- лучше не писать длинные выражения в шапке цикла, плохо читается, лучше писать их в теле цикла
- выражение ($credit+($credit*0.03+1000)); повторяется, надо избавиться от повторов
> if ($credit+$service<5000)
Это условие неправильное, так как оно не учитывает проценты, а только комиссию.
Можно сделать так:
- прибавляем проценты и комиссию к остатку долга (!не вычитаем ничего пока!)
- если остаток маленький, выплачиваем сколько осталось и уходим
- иначе платим 5000
«Платим» здесь значит уменьшаем долг и увеличиваем общую сумму выплаченного.
>>961194
на Доброчан запостил потому что, там хоть отвечать на пост можно.
>>960436
Немного не по теме задачи, но почему table? Это же флоатами или на худой конец display: table верстается прекрасно. Если что, у нас есть задачи по HTML/CSS.
Вот кстати решение без использования JS: https://codepen.io/shidhincr/pen/ICLBD - догадаешься, как? Я не догадался.
> var btn = $($("#template-clear-btn").html());
Тут наверно было выгоднее вписать код строчкой, например $('<span...>'), чтобы плагин было проще подключить к странице. Хотя конечно вопрос, что делать, если код более сложный? Простого ответа тут нет. Кто-то в строки вписывает, кто-то в отдельный шаблон и потом как-то собирает в единый файл.
> if (methods.isChromeOrMacClient() &&
> methods.isSearchType(input))
Здесь, к сожалению, есть проблема, что это довольно ненадежный подход:
- где гарантия, что ты перечислил все браузеры, в которых есть крестик?
- где гарантия, что ты не указал тот браузер, где крестика нет?
- что если что-то поменяется в определенной версии браузера?
Как например насчет яндекс-браузера и прочей армии хромоколонов?
Сложно найти какое-то оптимальное решение, я бы наверно попробовал перечислить старые браузеры, в которых крестика точно нет (и которых меньше). Лучше всего конечно просто избегать ситуаций, где надо проверять userAgent, vendor, лучше стараться тестировать фичи, если возможно. Или например выводить крестик снаружи инпута, чтобы точно ни с чем не совпал. Или запретить использовать плагин с полями типа search.
Вот тут человек пытается по нестандартным CSS-селекторам обнаружить наличие крестика:
- http://stackoverflow.com/questions/16234268/detect-input-type-search-clear-button-in-chrome-and-ie10
- http://stackoverflow.com/questions/6942207/html-type-search-detect-clear-button-support
> if (html.attr("dir") == "rtl")
Тут есть важный момент. Ты читаешь атрибут dir, если он задан на html. Но во-первых, dir логично читать на инпуте или его обертке, он может быть разный. Во-вторых, там есть значение auto, когда браузер определяет его сам по содержимому. Что с ним делать?
Я тут поэкспериментировал, и увидел что в Хроме вычисление
window.getComputedStyle($0).direction (это CSS-свойство direction)
дает либо ltr, либо rtl даже при атрибуте dir="auto". Может оно поможет?
Я бы еще обратил внимание на CSS-псевдокласс dir(), который можно было использовать: https://developer.mozilla.org/en-US/docs/Web/CSS/:dir - только оно пока нигде не поддерживается.
Также, есть CSS-правила вроде html[dir=...] .xyz, но они наверно не помогут прочитать dir с инпута.
Насчет позиционирования крестика, обычно просто оборачивают инпут в враппер (инлайн-блок например без указания размеров), и позиционируются относительно враппера. Это имеет те преимущества, что например при растяжении/анимации инпута крестик поедет за ним. Но имеет и недостатки, что добавление враппера может сломать верстку. То есть универсального решения тут нет.
> if (!target.closest(".outer-clear-btn")) {
Это никогда не вернет false так как возвращается объект jQUery. Надо проверять closest().length
Кстати, обнаружил интересную особенность события input при вводе в японской раскладке. Там сначала печатается латинская буква, а когда их набирается несколько, они превращаются в иероглиф. При этом генерируются события keydown/keyup/input, а keypress не генерируется. Оно генерируется только для ввода в латинской или русской раскладке. С другой стороны, совсем древние браузеры input не генерируют.
Так в общем, особых ошибок я не вижу.
Удобнее делать миграции в коде, например в виде php файлов или классов. Больше возможностей.
Например, можно пройтись по строкам таблицы циклом и что-то поменять.
Можно увидеть примеры тут: http://docs.doctrine-project.org/projects/doctrine-migrations/en/latest/reference/migration_classes.html
Чтобы переносы строк нормально работали и в браузере и в ideone (и в консоли), можно использовать для этого \n, а в начале программы поставить
header("Content-Type: text/plain; charset=utf-8");
Это заставит браузер воспринимать то, что выводит твоя программа, как обычный текст, а не HTML, и уважать переносы строк в нем (так как в языке HTML перенос строки равносилен пробелу).
Иначе перенос строки будет в исходном коде страницы (его можно увидеть нажав Ctrl + U), но на самой странице его не будет.
Заодно указание кодировки исправит проблемы с отображением букв. А то как браузер узнает, в какой кодировке страница? Либо заголовок, либо meta charset нужен.
header можно использовать только до вывода текста, даже один пробел нельзя перед ним вывести. Если ты сохранил файл в utf-8 c BOM то этот символ BOM в начале файла уже все портит. Сохраняй без него
https://ru.wikipedia.org/wiki/Маркер_последовательности_байтов
Если вдруг интересно, есть еще сложный урок про кодировки https://github.com/codedokode/pasta/blob/master/cs/strings.md
То его надо поставить в начало документа. Хотя тут речь о выводе текста с переводами строк, а не HTML. Кодировку так же можно задать тегом meta в HTML.
> Кодировку так же можно задать тегом meta в HTML.
Я так и сделал. Хтмл я ещё не забыл, а пхп начал с нуля, ну и засунул php-код в html, что бы мог кодировку в этом html-е указать. Щас снёс всё, оставил только php и header заработал.
Ищешь символ с индексом 0 в слове, делаешь его заглавным. Что сложного?
Это русская разработка? Выглядит как мокрописька, что-то страшно такое ставить.
И никаких исходников даже.
>Программы в комплекте
>Skype — Общение;
>TeamViewer — Удалённый помощник;
>uTorrent
Ой-ёй, не-не, такое мне не надо, извините.
>Если ты изучал Си, то в PHP include/require это совсем другая вещь. require просто выполняет код из указанного файла. То есть достаточно где-то один раз сделать require для класса, этот класс будет описан в файле, PHP его запомнит, и второй раз делать require уже не надо.
Спасибо!
Я не изучал программирование до РНР, иду практически с нуля.
>Может, еще стоит сделать класс Компания?
Я не могу представить, как должно выглядеть следующее: Компания создаёт Департамент, который создаёт Работников. Как, например, в этом случае потом отдельно создавать работников и включать их в компанию? Не могу осмыслить...
>Антикризисные меры я бы сделал так: делаем класс АнтикризисныйКомитет и у него 3 метода в стиле применитьМеруN(компания). Метод принимает на вход компанию и что-то в ней меняет, например, увольняет людей. Ну или если тебе хочется заморочиться, можно как-то сделать 3 класса, каждый для своей меры, но не вижу смысла.
Сложнота для меня, но если разберусь с классом Компания, то и тут пойму, наверное.
>У твоего наследования есть один недостаток: нельзя никак догадаться, что при наследовании мы обязаны определить значения вроде $coffee. Лучше сделать в базовом классе абстрактный метод getBasicSalary(), а в наследниках - его реализации. Тогда забыть его реализовать точно не получится.
О, я дальше сделал так, как ты советовал в подсказках, - до этого я делал без чтения подсказок.
Вот тут: >>961014
Действительно, теперь если появится дополнительный параметр (потребление воды из кулера, использование мыла или выкуривание сигарет - для примера), достаточно его прописать в методе addEmployee(), в соответствии с профессией.
>> public function addEmployee($profession, $number, $rank = 1, $boss = false) {
>> for ($i = 0; $i < $number; $i++) {
>> $this->employees[] = new $profession($rank, $boss);
>Это не очень правильно, что департамент сам создает работников. Лучше сделать метод, в который передается уже созданный employee. А так у тебя нельзя создать отдельно работника и назначить его в департамент.
То есть я вообще неверно понимал, что Компания должна создавать Департаменты, Департамент должен создавать Работника... Получается, этим всем могут заниматься простые функции, а методы в этих классах работают только с подсчётом всего по компании или департаменту?
>Да и ты закладываешь ограничение, что у любого работника ровно 2 аргумента в конструкторе. А что если завтра напишут новый класс профессии, где 3 аргумента (например добавится опыт в годах)?
Ну, тогда можно ведь в конструктор добавить $this->experience = $experience;, а в аргументах поставить по умолчанию $experience = false, чтобы уже имеющииеся работники у нас создавались нормально? Горожу что-то непонятное, конечно.
>> getTheValues
>Лучше printValues
Хм, да, действительно.
>> foreach ($departments as $key => $value) {
>Названия плохие. Надо так: foreach ($departments as $department)
Точно, спасибо, это я машинально записал, а потом не подчистил.
Спасибо за такой подробный разбор! Постараюсь разобраться - задача интересная.
>Может, еще стоит сделать класс Компания?
Я не могу представить, как должно выглядеть следующее: Компания создаёт Департамент, который создаёт Работников. Как, например, в этом случае потом отдельно создавать работников и включать их в компанию? Не могу осмыслить...
>Антикризисные меры я бы сделал так: делаем класс АнтикризисныйКомитет и у него 3 метода в стиле применитьМеруN(компания). Метод принимает на вход компанию и что-то в ней меняет, например, увольняет людей. Ну или если тебе хочется заморочиться, можно как-то сделать 3 класса, каждый для своей меры, но не вижу смысла.
Сложнота для меня, но если разберусь с классом Компания, то и тут пойму, наверное.
>У твоего наследования есть один недостаток: нельзя никак догадаться, что при наследовании мы обязаны определить значения вроде $coffee. Лучше сделать в базовом классе абстрактный метод getBasicSalary(), а в наследниках - его реализации. Тогда забыть его реализовать точно не получится.
О, я дальше сделал так, как ты советовал в подсказках, - до этого я делал без чтения подсказок.
Вот тут: >>961014
Действительно, теперь если появится дополнительный параметр (потребление воды из кулера, использование мыла или выкуривание сигарет - для примера), достаточно его прописать в методе addEmployee(), в соответствии с профессией.
>> public function addEmployee($profession, $number, $rank = 1, $boss = false) {
>> for ($i = 0; $i < $number; $i++) {
>> $this->employees[] = new $profession($rank, $boss);
>Это не очень правильно, что департамент сам создает работников. Лучше сделать метод, в который передается уже созданный employee. А так у тебя нельзя создать отдельно работника и назначить его в департамент.
То есть я вообще неверно понимал, что Компания должна создавать Департаменты, Департамент должен создавать Работника... Получается, этим всем могут заниматься простые функции, а методы в этих классах работают только с подсчётом всего по компании или департаменту?
>Да и ты закладываешь ограничение, что у любого работника ровно 2 аргумента в конструкторе. А что если завтра напишут новый класс профессии, где 3 аргумента (например добавится опыт в годах)?
Ну, тогда можно ведь в конструктор добавить $this->experience = $experience;, а в аргументах поставить по умолчанию $experience = false, чтобы уже имеющииеся работники у нас создавались нормально? Горожу что-то непонятное, конечно.
>> getTheValues
>Лучше printValues
Хм, да, действительно.
>> foreach ($departments as $key => $value) {
>Названия плохие. Надо так: foreach ($departments as $department)
Точно, спасибо, это я машинально записал, а потом не подчистил.
Спасибо за такой подробный разбор! Постараюсь разобраться - задача интересная.
Ну вот сделал с нормальным foreach: https://3v4l.org/mHNMJ
Признаться, что-то и не сразу вышло вообще - структура почему-то неочевидной оказалась.
Поясните что это за бред. Столкнулся с аналогичной хуйней, пришлось добавить фавикон в корень сайта.
Laravel 5.4
Я так понимаю траблы с доступом к папке?
/?sort=name&page=6
А на странице регистрации он уже так выглядит
/?sort=name&amp;page=6¬ify=registered
ЧЯДНТ?
Погуглил, оказалось действительно права доступа. Накатил chmod 755 на папку и всё норм.
При сохранении файла делаю
$file->move($path, $file->getClientOriginalName());
Как мне вместо getClientOriginalName дать собственное имя файлу?
Бля пиздец, да почитай ты уже документацию. Эта хуйня одинаковая во всех фреймворках.
Не верно. В уроке есть ответ.
$xBal нужно перед условием объявить и обнулить.
php намекает
PHP Notice: Undefined variable: xBal in /home/vKdGL9/prog.php on line 20
PHP Notice: Undefined variable: xBal in /home/vKdGL9/prog.php on line 21
Почитал твой код и нихуя не понял
Сам я ньюфаг-вот моё решение https://ideone.com/dZDFn3
PHP Fatal error: Uncaught Error: Call to undefined function mb_internal_encoding() in /home/tkDcLc/prog.php:4
Stack trace:
#0 {main}
thrown in /home/tkDcLc/prog.php on line 4
В гайде написано, что как раз там это все должно работать. Может я что-то не так делаю?
Проблема со строками на Идеоне уже давно, перекатывайся на https://3v4l.org
Базарю, поцене 38 рублей, намного удобнее и лучше Идеоне. Это что-то вроде контроля версий - в браузере при каждом запуске скрипта будет сохраняться его копия, код не потеряешь, можно в истории просмотров вернуться к нужному варианту и т.п.
> разделение на контроллеры в случае с о слимом?
Есть же пример в документации, раздел "Allow Slim to instantiate the controller": https://www.slimframework.com/docs/objects/router.html
> а что делать в случае крупных приложений?
В крупных приложениях Slim не используется, это же микрофреймворк.
>>962355
Зачем сохранять урл в сессию?
>Зачем сохранять урл в сессию?
Что бы после регистрации пользователь на ту же страницу попадал откуда и попал не регистрацию.
А, понел. Но все равно какая-то хуйня выходит, надо же опять же определять вот это:
$app->get('/', \HomeController::class . ':home');
$app->get('/contact', \HomeController::class . ':contact');
Ты ларавель изучаешь или просто код с экрана переписываешь? Открой документацию по move() и прочти.
Где будут спрашивать, там и буду отвечать. Если что-то случится - перекатываемся на доброчан.
Мой код: http://ideone.com/fork/mHPI0v
Ты каждый раз перезаписываешь переменную $name, видимо задумка была в её дописывании.
Опять в бухгалтерии бабки радио включали? Завязывай с госконторами.
php на уровне ООП
JS на уровне AJAX
>>962684
"Саморазвиваться с фреймворками" можно и в свободное время, а кушать хочется всегда.
Мне нужна работа за миску еды хотя бы что бы не сдохнуть с голоду. Я бы не против yii освоить, но без работы мне сейчас не вариант
Всё очень утрированно но суть ты понял
Ну, хули, сам ответил на свой вопрос, учи битриксы и вордпрессы.
Как у тебя с мозгами? Ты тупой, как и я? Если да, то можем обменяться контактами и вместе подыхать с голоду, я к лету как раз освобожусь.
xampp удобнее в винде
Быстрее всего открыть вакансии по своему городу и расписать требования, количество работ и зарплаты в excel таблицу. Сразу и понятно станет, что учить.
Задача по циклам, остановился на составлении цикла. Код: "<?php
error_reporting(-1);
$bankAmount = 10000
$bankPercent = 0.1
for ($years = 1; $years <= 100; $years ++) {
}"
Дальше я не знаю как и что.
Внутри цикла надо написать примерно такую команду:
увеличить сумму в банке с учетом процентов;
вывести на экран год и текущую сумму;
Это для начала. Потом надо будет добавить еще проверку, если сумма достигла миллиона, то напечатать, сколько лет прошло, и выйти из цикла.
Я к примеру пошел на работу опенкарт ковырять. В свободное время изучил второй язык js (не на уровне манипуляции с дом -поработал с нодой, в частности с sails, с Cordova ). Сделал с десяток тасков на этом. Потом плотно занялся MySQL так вы процессе работы с нагруженными e-commerce нужно много оптимизировать. Сейчас в свободное время взялся за slim, потом планирую в laravel/symphony. А мог бы дальше у мамки на шее сидеть и учить фреймворки.
А я тоже на работу быстро выкатился, подучил там mysql, пару фреймворков, js и юнит тесты, бабла на год безработной жизни подкопил, щас думаю работу кидануть и на фрилансы попробовать вкатиться. На работе вообще все быстрее учится, дома как-то медленно слишком шло.
Поясни нубу за ноду, нахуй она нужна если у тебя в стеке уже есть серверсайд технология?
Фриланс, Хз, я по удаленке пробовал работать, лично я не могу, сложнее из дома сосредоточиться
Ты пиздишь как дышишь. Никакой нормальный человек не будет вкатываться на фрилансы с ирл работы.
Ты и сейчас сидишь на шее у мамки, просто выучил пару модных слов с уроков на ютубе, которые ты не смог осилить. Прекращай уже заниматься хуйней, иди на завод, ты нужен стране.
Почему? На работе сидеть заебывает, душный офис, куча народу в комнате 5х5 метров, все галдят и невозможно сосредоточиться, линейки с докладами каждое утро по часу и злобный начальник, у которого все должно быть сделано вчера. На фрилансе сидишь дома в уюте и пишешь код как король.
Ага, с магазинов.
Вроде в тело функции рабочий код с первой задачи пришил, к Клубнике банку 7777 р. добавил, но мучают сомнения. В ОПовском учебнике на выводе видно что у Клубники банка на "конце" 08. Хуй знает.
https://3v4l.org/LB3b5
У меня в третьем случае вышло
>Кредит от банка StrawberryBank, обойдётся в 53560, выплаты составят - 11 месяцев
Я функции добавил новую вводную переменную "единоверменная выплата", двух других банков она была равна 0, у третьего 7777, собственно в формуле подсчёта эта переменная участвует.
А попробуй ввести данные из задачи про айфон? Корректно выведет? У меня просто вроде сходится, но вывод разный у нас.
Скорее всего у тебя что-то не так. При данных 1000р., 3%, комиссия 500р. вывод неверный.
Бля, соррян, не увидел. Тогда хуй знает почему на функциях ответы не совпадают. Говнокод не комментировал, стыдно кидать.
Так, ответы не совпадают только у strawberryBank, теперь хоть буду знать где фиксить.
Мне сам язык нравится, после Флэнагана полюбил js.
В Родительском классе задано одно поле:
text; в котором задаётся текст вопроса.
Всё, а поле которое мы должны проверять где? Куда? В Классах-предках есть поля:
$options; // варианты ответа на вопрос
$correntOption; // правильный вариант на вопрос
$answer; // ответ
$deviation; // допустмая погрешность
Среди них есть с чем сравнивать - правильные ответы и два других. Но с чем сравнивать? Пользователь ввёл ответы - где эта переменная? Как писать функцию function checkAnswer($answer) если НЕ С ЧЕМ СРАВНИВАТЬ? Ответов пользователя НЕТ.
Условий для решения задач нет, а самому додумывать, а потом ебаться с тем, что выполнить поставленную задачу невозможно с уровнем знаний - нет спасибо.
>Господа, поясните за кеширование динамических страниц при хайлоаде?
Ночью запускается скрипт (кроном) и он создаёт много-много файлов с расширением .php
Они потом прогоняются через интерпретатор. IRL от высоких нагрузок это не спасает, гугли MySQL, таблицы в памяти, плоские таблицы с одним ключом.
Блядь хуйню написал и рад, в общем для меня там не заданы условия в ЯВНОМ виде, вот что я хотел донести. Буду рад пояснениям.
Объект Question хранит только информацию о вопросе. Ответ в нем естественно не хранится, а хранится в отдельной переменной или массиве (так как ответов много).
Там же есть пример в уроке: функция function checkAnswers($questions, $answers)
Она получает на вход отдельно массив объектов-вопросов и отдельно массив ответов. В цикле обходим вопросы и берем соответствующий вопросу ответ из другого массива.
Добавляю бутстрап: bower_components/bootstrap/dist/css/bootstrap.css
Создаю бандл, там есть такое: src/Blogger/BlogBundle/Resources/views/Default/index.html.twig. Сюда я пытаюсь вкорячить хтмл-код, также дописываю
<link rel="stylesheet" href="{{ asset('bower_components/bootstrap/dist/css/bootstrap.css') }}">
И нихуя не работает. Просто обычная страница без css.
У тебя bower_components в публичной папке? Обычно после установки через bower нужные файлы копируют собственными скриптами.
А хз. Я по трем разным инструкциям делал. Вообще наверно можно было все руками скопировать, bower все-равно де ничего не сконфигурировал.
У тебя публичная директория web, а файлы бутстрапа совсем в другом месте. Руками копировать не всегда хорошо, так как при установке твоего приложения на другую машину, сисадмину нужно будет делать то же самое, а без подробной инструкции очень сложно догадаться что именно нужно скопировать, куда и откуда. Легче и проще один раз написать скрипт который это все делает, а потом если ты к примеру решишь поменять структуру файлов в публичной папке, ты сможешь сделать это в скрипте, при этом тебе не придется писать новуб инструкцию при установке.
Ладно, вот я скопировал папку бутстрапа в веб, и все равно нихуя. Может еще чего надо написать?
>ладно, скипну.
Я те блять щас скипну, пииииидр!!1
Это самое важное в учебнике, всё, что было до этого - это подготовка к ООП. Все фреймворки на нём, всё вменяемое программирование - на нём.
А ты - "скипну".
А на давай быстро вопросы задавай!
Что ты не можешь конкретно понять?
Для начала ты можешь открыть инструменты разработчика в браузере и посмотреть откуда он пытается загрузить стили. Эта информация поможет тебе определить источник проблемы. И в следующий раз пользуйся гуглом, решение тво ей проблемы можно найти за минуту.
Так кушать хочется, и за интернеты платить надо. Не все могут на шее у мамки сидеть или бабкину квартиру сдавать.
На жабе работы-то нет.
Честно, по всем гайдам пытался, и в composer.json вписывал зависимости, и в config.yml всякие asertic, никак.
А стили пытается грузить откуда я и указал, но Failed to load resource.
С ума сошёл! Там ты обсеришься из-за сложноты, инфа соточка!
Сначала же простое надо понять, о чем ты вообще..
Да изи, работаю на джаве с шарпом параллельно с пхп. Ничего против пхп не имею сейчас, но поначалу тоже не очень было.
>Зачем эти сложные ::
С этим все очень просто, лол. Два двоеточия и стрелка используется от того, что точка уже используется для конкатенации, лол.
Почему в питончике нельзя было сделать $ и ::? Как сложно.
>>963073
Для начала посмотри в исходном коде страницы, какие теги вставляются в HTML-код. Посмотри на вкладке network в отладчике, куда идут запросы. И посмотри, нет ли чего в логах.
С assetic нужно разбираться и читать доки.
>>963064
даже на западном фрилансе?
>>963063
Так эта намного проще. Собери куски кода для проверки ответов из урока, и подправь там то, что требуется в задании. Там большая часть кода уже написана автором урока. Надо только чуть подправить.
Надо разбираться в том, что происходит, а не делать что-то наугад. Если ты используешь assetic - разберись как он работает, и что происходит в твоем случае.
>>963049
А что ты будешь писать в докер-файле? Внезапно, те же bash-команды. Только завернутые в проприетарную программу.
>>963024
Смотри, что выводится в HTML-коде, что пишется в логи Симфони и лог ошибок PHP.
>>963002
Да. Можно использовать, чтобы передать в функцию имя класса с защитой от опечаток (если передавать строку, можно опечататься).
>>962949
Возьми предыдущую версию этой программы, которую ты делал раньше, и доработай.
>>962946
Ну и бред ты пишешь. Зачем людей путаешь?
>>962878
В файлы невыгодно так как создается лишняя нагрузка на диск, а его пропускная способность не резиновая. Часто кешируют в память, например в мемкеш или редис. Ну и тут не все так однозначно, в большинстве случаев, кроме самых простых, страницы кешировать целиком просто невозможно, так как они для всех разные или постоянно меняются.
Надо не слепо следовать рекомендациям неграмотных людей, а разобраться: что мы экономим, что мы теряем, что выигрываем, что на что меняем.
Есть презентация с объяснениями разных подводных камней: http://lib.custis.ru/images/6/6d/WebAppCache.pdf (не знаю, где искать запись выступления, можешь по названию погуглить)
Если ты не понимаешь, что описано в презентации, то рановато тебе кешированием заниматься, задавай уточняющие вопросы.
Если хочешь, можем еще какую-нибудь практическую задачу решить - например прикрутить кеширование к блогу на вордпрессе который без этого весьма тормозной.
Надо разбираться в том, что происходит, а не делать что-то наугад. Если ты используешь assetic - разберись как он работает, и что происходит в твоем случае.
>>963049
А что ты будешь писать в докер-файле? Внезапно, те же bash-команды. Только завернутые в проприетарную программу.
>>963024
Смотри, что выводится в HTML-коде, что пишется в логи Симфони и лог ошибок PHP.
>>963002
Да. Можно использовать, чтобы передать в функцию имя класса с защитой от опечаток (если передавать строку, можно опечататься).
>>962949
Возьми предыдущую версию этой программы, которую ты делал раньше, и доработай.
>>962946
Ну и бред ты пишешь. Зачем людей путаешь?
>>962878
В файлы невыгодно так как создается лишняя нагрузка на диск, а его пропускная способность не резиновая. Часто кешируют в память, например в мемкеш или редис. Ну и тут не все так однозначно, в большинстве случаев, кроме самых простых, страницы кешировать целиком просто невозможно, так как они для всех разные или постоянно меняются.
Надо не слепо следовать рекомендациям неграмотных людей, а разобраться: что мы экономим, что мы теряем, что выигрываем, что на что меняем.
Есть презентация с объяснениями разных подводных камней: http://lib.custis.ru/images/6/6d/WebAppCache.pdf (не знаю, где искать запись выступления, можешь по названию погуглить)
Если ты не понимаешь, что описано в презентации, то рановато тебе кешированием заниматься, задавай уточняющие вопросы.
Если хочешь, можем еще какую-нибудь практическую задачу решить - например прикрутить кеширование к блогу на вордпрессе который без этого весьма тормозной.
В твоем случае про текстовый файлы - 100% бред так как база данных сама хранит данные в файлы. Какой смысл пытаться дублировать то, что она делает, при этом делать это хуже? База данных например умеет кешировать результаты запросов в памяти, умеет кешировать прочитанные с диска данные в памяти, ты предлагаешь все это выбросить и использовать более медленный способ?
Я не про перегрузку. Ты меня не понял. Приведу пример. parse_ini_file("/path/to") - возвращает массив со всеми ключами-значениями. Но если мы добавим во второй необязательный параметр true - будут еще секции.
Добавление необязательных параметров, которые слишком сильно меняют поведение метода это bad practice. В ядре пыхи подобные функции есть, но это не повод на них равняться, в пыхе много чего есть - наследие времен, когда php был юн и наивен.
Создавай метод с необязательными параметрами если:
1 - поведение метода остается очевидным и предсказуемым
2 - дополнительные параметры либо лишь уточняют поведение метода, либо меняют лишь способ достижения того же результата, либо каким-либо косметическим образом влияют на возвращаемое значения
3 - это необходимо для сохранения обратной совместимости при рефакторинге или изменении метода, если остальной код, который эту функцию вызывает отрефакторить не получается по каким-либо уважительным причинам
4 - когда этот необязательный параметр просто присваивает параметру значение по-умолчанию из множества возможных для этого параметра значений
Если метод при наличии необязательного параметра ведет себя совсем по-другому, возвращает другой тип результата, включает слишком массивный кусок кода, который обычно не задействован или совершает еще какие-либо странные действия, то значит лучше разделить такой метод на несколько других.
В случае parse_ini_file необязательные параметры лишь декорируют результат и привносят в него дополнительные сведение, но контекстное поведение функции никак не меняется - это по прежнему парсинг ini файла.
Думаю, в твоем случае поведение метода уже завязано на имени getValue, т.е. получить значение. Если при вызове getValue ты получаешь целую секцию, то это уже слишком большое изменение результата. Я ожидал конкретно значение из секции, а получил всю секцию. Лучше создай метод getSection.
> Смотри, что выводится в HTML-коде, что пишется в логи Симфони и лог ошибок PHP.
Ну бля. Я вижу, что он не может подгрузить css, и все.
https://pastebin.com/3xkPYVQP
И еще один совет чисто по стилистике от меня. Если вызов функции без указания необязательного параметра, подразумевает, что этот параметр должен быть просто проигнорирован, то не присваивай ему false, а лучше присвой null. Т.к. "возможность" присвоить аргументу false, означает, что ему также можно присвоить и true, что будет странным, если наличие значение у аргумента при вызове не подразумевает bool значение.
public function getImage()
{
return ($this->image) ? '/uploads/' . $this->image : '/no-image.png';
}
это ? аргумент : аргумент - или я хз, что-то такое было даже у ОПа в учебнике, помогите найти
Актуальна для РНР5, он-то остался на том уровне.
Это ещё долго будет актуально, хотя в 7 изменения были, конечно, но в процессе разберёшься.
Ну допёр, вспомнил суть:
выражение ? действие1 : действие2;
Если выражение истинно, то действие1, если не истинно - действие2.
>>962220
Вот это объяснил. Сохрани к себе на GitHub, пожалуйста, в пасты, супер полезная информация. Приступаю к работе.
>>962227
>А если программа-клиент?
Именно! Потихоньку пишу такую на (клиент: js + nwjs) <=> (сервер: rest api на php + mysql).
Конечно, ломать меня никто не будет, но тема зацепила, и из всех вариантов SRP тут подходит замечательно: бесплатно и можно реализовать своими силами (и черт возьми, как же интересна оказалась простая математика).
Алсо, иногда вижу в тредах про программирование "нахуй матан в пхп лол ты че нуб?". Абсолютный пиздеж, очень нужна в любом языке. Жалею, что в школе и в универе на матишу забивал болт, это блин чудо-наука.
А что скажете за такое? Стоит связываться?
Судя по описанию, стандартная шарага, где учат на примитивном уровне как на видеокурсах с ютуба. Про трудоустройство ясно пиздеж, или в шараги какие устраивают с никакими перспективами (хотя после курсов с ютуба и так пойдет). Сертификаты пригодятся конечно, но вангую за них с тебя отдельно баблосы обдерут, т.е. ты эти сертификаты и без них так же получить можешь, записавшись и сдав экзамен помимо их шараги.
Нужно делать отдельную функцию. Неудобно, когда функция может возвращать разные типы данных. Получить параметр конфига - одна функция, получить весь конфиг - другая.
В PHP есть ошибки проектирования и не стоит их повторять.
>>963279
Ты используешь assetic или нет?
Если нет то читай мануал
- http://symfony.com/doc/current/reference/twig_reference.html#asset
- http://symfony.com/doc/current/templating.html#linking-to-assets
И проверяй, все ли сделано как надо. Правильно ли указан путь к файлу, относительно нужной ли папки?
Если ты используешь assetic, то там 2 варианта:
- либо по этому пути должен располагаться файл/ссылка на файл (ну например если ты запустил скрипт и он скопировал нужные файлы - это для продакшена)
- либо этот путь должен обрабатываться контроллером, который сгенерирует и отдаст нужное содержимое. Это обычно используется в среде разработки (чтобы не надо было руками запускать скрипты обновления файлов)
Открывай мануал по assetic.
http://symfony.com/doc/current/assetic/asset_management.html
Сделал все, что там написано? Бандл добавил? Конфиг прописал?
Если не используешь assetic то стоит для начала научиться правильно функцию asset использовать.
assetic кстати как раз умеет отдавать или копировать файлы в нужные папки, если его настроить.
И надо читать документацию, а не повторять то, что делают в видеоуроках, особенно если там используется другая версия Симфони. Нужно понимать, что значит каждая строчка кода в твоем приложении, а не слепо их копировать откуда-то.
Нужно делать отдельную функцию. Неудобно, когда функция может возвращать разные типы данных. Получить параметр конфига - одна функция, получить весь конфиг - другая.
В PHP есть ошибки проектирования и не стоит их повторять.
>>963279
Ты используешь assetic или нет?
Если нет то читай мануал
- http://symfony.com/doc/current/reference/twig_reference.html#asset
- http://symfony.com/doc/current/templating.html#linking-to-assets
И проверяй, все ли сделано как надо. Правильно ли указан путь к файлу, относительно нужной ли папки?
Если ты используешь assetic, то там 2 варианта:
- либо по этому пути должен располагаться файл/ссылка на файл (ну например если ты запустил скрипт и он скопировал нужные файлы - это для продакшена)
- либо этот путь должен обрабатываться контроллером, который сгенерирует и отдаст нужное содержимое. Это обычно используется в среде разработки (чтобы не надо было руками запускать скрипты обновления файлов)
Открывай мануал по assetic.
http://symfony.com/doc/current/assetic/asset_management.html
Сделал все, что там написано? Бандл добавил? Конфиг прописал?
Если не используешь assetic то стоит для начала научиться правильно функцию asset использовать.
assetic кстати как раз умеет отдавать или копировать файлы в нужные папки, если его настроить.
И надо читать документацию, а не повторять то, что делают в видеоуроках, особенно если там используется другая версия Симфони. Нужно понимать, что значит каждая строчка кода в твоем приложении, а не слепо их копировать откуда-то.
Что-то еще больше вопросов стало. Есть серверное, а есть клиентское кэширование (http)?
В общем, как мне кэшировать страничку динамическую, если пользователь ввел данные на эту страницу и они обновились в бд и при перезагрузке ему нужно вывести эту же страницу только с новыми данными (а они берутся из старого кэша, а не из бд)? Как обновлять кэш при POST запросе? Для этого нужно использовать редис, nginx или memcashed?
Почитал англоязычный ресурс, там написано, что кэш удаляется при пост запросе, т.е. при удаленном кэше данные подргужаются из бд, а потом опять кэшируются? Я запутался. Нет ли где-нибудь ссылки на гитхаб с реализацией подобного кэширования дин. страницы? В докладе что-то про сокеты говорится, но разрабы с моей работы говорили, что создавать на каждое соединение по сокету при хайлоаде - не эффективно.
Так же я нахуярил методов в суперклассе, но вызывать мне их совсем не хочется, потому что, блядь, массив. Можно заюзать форич в теле программы, что бы по одному дёргать объекты из массива засовывать его в функции, отличное блядь, решение, но как оказалось я проебал ещё пол часа, что бы понять, что каждый раз вызывая метод - я стираю все переменные внутри, и мой блядь, счетчик зарплат обнулялся.
Объясните, как и с какой целью в этой программе использовать методы.
Чем тебе методы не функции?
У тебя Employees и Department. По логике очень схожие сущности. Может ты хотел сделать Employee (один наемный рабочий), у которого свои свойства и методы, соответственно у Department будет свойство employees в котором будет массив экземпляров класса Employee.
Если у Employee будет метод ::getSalary(); то к примеру в Department может быть метод ::getTotalSalary() который бы обходил в цикле всех своих сотрудников и у каждого вызывал бы getSalary() и доплюсовывал в какой нибудь $total который бы потом этот метод возвращал
И ещё вопрос, почему Employees наследуется от Department, по логике Department более узкое понятие, специфическое понятие, а Employees более широкое, если абстрагироваться от кода внутри них на скрине, то по логике Department должен наследоваться от Employees (К примеру: Политический митинг extends Группа людей)
Зачем их вообще друг от друга наследовать? По логике это 2 вообще разные сущности с разными свойствами и функциями.
Люди работают в департаменте, департамент более широкое понятие. В Департаменте создан массив куда будут помещаться объекты "сотрудников."
>Если у Employee будет метод ::getSalary(); то к примеру в Department может быть метод ::getTotalSalary() который бы обходил в цикле всех своих сотрудников и у каждого вызывал бы getSalary() и доплюсовывал в какой нибудь $total который бы потом этот метод возвращал
Зачем вообще создавать два метода? Почему не одну функцию? Предлагаешь на любое действие -- создавать пару методов?
>getPage
>totalGetPage
>getCofe
>totalGetCofe
>Зачем вообще создавать два метода? Почему не одну функцию?
Потому что Employee это общее понятие, у тебя может быть "Архитектор" или "Уборщик", разные условия оплаты, значит у них метод подсчета зарплаты может отличаться.
>Предлагаешь на любое действие -- создавать пару методов?
Может оп лучше объяснит, каждый метод должен описывать какое-то целостное действие.
> у тебя может быть "Архитектор" или "Уборщик", разные условия оплаты, значит у них метод подсчета зарплаты может отличаться.
В условиях задачи написано, что з/п может различаться только из-за ранга и статуса "начальник", что учтено в методе.
Т.е вот эта конструкция $totalSalary=Employees::CalculateTheSalary($employees);
Является нормой?
Метод CalculateTheSalary считает зарплату каждого и возвращает $totalSalary.
Вот тот switch не нужен, это должно быть внутри метода Employee - он должен вернуть уже посчитанный для конкретного employee конечную цифру зарплаты, Департамент вообще не должен знать о том, как считать зарплаты своим сотрудникам.
Не понял в чём проблема свича? Либо он, либо тонна условий режущих глаза. Я так например блядь созданием сотрудников сделал, говнокод ебучий.
А ты блядь подумай, какой нужен абстрактный класс, чтобы не было этих тонн условий, свитча и проблем с введением новых должностей.
Проблема свитча тут в том, что ты делаешь комментарии для того, чтобы не перестать понимать свою хуйню, вместо того, чтобы завести какой-нибудь массив или словарь, в котором компактно будет описано, сколько и чего нужно создать. Это как минимум.
мимопроходил
Вместо свича при подсчете - сделай в методе getSalary() у Employee подсчет конечной цифры зарплаты, которая бы больше никак не изменялась, она должна отражать зарплату работника всецело, департамент не должен ничего с ней делать, департамент вообще ничего не должен знать о её пересчете или подсчете. в итоге у тебя останется простенький цикл вида пикрелейтед
Вот хоть убей, я не вижу способа в getSalary подсчитать зарплату без свича или условий. Поделись секретом, чего я не вижу.
Напоминаю работники в массиве $employees, у работника есть свойсва rank и baseSalary. Открой мне глаза.
В нем делай как угодно, со свичами, с ифами, там ему место, а не в департаменте.
...
Я думал ты пытаешься заставить меня убрать свич, что у тебя есть гениальное решение без условий.
...
В департаменте вообще ничего не считается, пока. Ты же видел скрин, я и зарплату по сотрудникам и тотал по зарплате посчитал в одном методе, метод этот принадлежит Empolyees, никакого отношения к депортаменту он не имеет. Ты хочешь разнести эти действия по разным методам...
Employees в принципе существовать не должен, департамент состоять должен из массива в котором единицей является "1 работник", а не из массива "группа работников"
>а не из массива "группа работников"
а не из масссива где единицей является "группа работников"
selffix
NE OCHEN
>Может оп лучше объяснит, каждый метод должен описывать какое-то целостное действие.
Он ещё говорил мне, что это нужно для удобства. Видишь класс Работник - вот тут все действия для работы с ним: нанять, уволить, посчитать зарплату, исходя из ранга и профессии - и т.п.
То есть у объекта Работник должны быть все методы работы с ним.
>>963562
>В условиях задачи написано, что з/п может различаться только из-за ранга и статуса "начальник", что учтено в методе.
Код должен быть гибким. Например, может понадобиться внести подсчёт выкуренных сигарет, выпитой воды, туалетной бумаги и т.п. бреда, который там и так был про кофе и страницы. Вот методы у суперкласса Работник должны позволять легко и компактно это всё вносить.
Мимо выше решал первую часть Вектора до антикризисных мер
Говнокод тут в том плане, что ты мог сделать создание работников - методом класса Работник, у которого в аргументах стояло бы: профессия, количество работников, которых нужно создать, ранг, боссы или нет. И в этом методе уже был бы цикл for, который создавал экземпляры класса, при этом по профессии ещё наделял их кофе и страницами (для этого профессии должны быть классами, унаследованными от Работника).
Вот ещё тебе плюс в пользу использования методов.
SLOZHNA
Считает верно, но объясни вот это условие:
>if ($creditBalance < 4000)
Что оно означает, почему никак не привязано к имеющимся значениям?
Было выше такое решение у анона, это неверное решение в том плане, что поддержке не поддаётся: какие 4000 тысячи, что это за условие - не понять.
ну смотри. изначально это должно было быть 5к, но тут еще добавляется 1к платы за месяц.
Да, но в данном случае и обозримом будущем параметр "профессия" не играет роли, так зачем плодить классы для деления работников на эти самые профессии?
Ну не обязательно создавать классы под профессии, действительно, однако метод для создания работника в классе Работник тогда просто должен содержать то, что ты наговнокодил, чтобы было чётко и понятно, чтобы всё делал этот метод, а не циклы громоздкие при создании.
Ты сам не понимаешь, о чём говоришь.
Куда прибавляется тысяча, если у тебя if ($creditBalance < 4000)? Это тут без этой тысячи, но с процентами? С какой такой стати? Что это за условие вообще?
Также условие для работы цикла for непонятное и не универсальное - если меньше 20 месяцев. С какой такой стати? А если сумма кредита будет 80 тысяч, то там больше 20 месяцев будет выплачиваться - всё сломается.
Поэтому там лучше условие вот такое: если сумма кредита не ровна нулю.
Вот уже понятнее, просто я сразу не дошёл до того, зачем нужны методы(и сейчас смутно представляю дальнейшие действия).
я вчера только статью про ООП прочитал.
>>963675
Этого поддержу, не могу въехать откуда эти 4 тысячи вылезли. А за условие в цикле не ругай, так ОП накодил.
задать в b 50 и в a 99.
$container = $app->getContainer();
$container['twig'] = function(){
$loader = new \Twig_Loader_Filesystem('../app/Templates/');
$twig = new Twig_Environment($loader);
return $twig;
};
И все работает, проблема в том, что с таким подходом не работает автодополнение кода для объектов в контейнере. Его можно как-то подрубить туда?
Да.
По неймспейсам есть хороший мануал: http://php.net/manual/en/language.namespaces.php
>>963714
if ($x > 50 && $x < 99) { ...
>>963742
Обычно делают так:
/ @var Twig_Environment $twig */
$twig = $container['twig'];
>>963068
Признайся, что у тебя просто низкая квалификация и ты пришёл сюда поныть. Среди одногруппников 4 человека пишут код за деньги, двое из них как раз на C#.
>/ @var Twig_Environment $twig */
Идея понятна, только я не понял где мне это писать. Прямо в этом методе?
>$twig = $container['twig'];
public function index(\Slim\Http\Request $request, \Slim\Http\Response $response, $args)
{
$template = $this->container->get('twig')->load('index.html.php');
echo $template->render();
return $response;
}
PHP не виноват, что ты просто дно. Если после нескольких лет кодинга на джаве и шарпе ты не можешь себе доширак обеспечить, то мкарьера офис-менеджера ждет тебя.
Я кончил
Оказалось, что PHP на моем компьютере не поддерживает целые числа больше 2147483647. Поэтому при вычислении $v = pow(2, $x) % $N получаю 0 или число 2 ^ n , что есть абсурд, ибо как я понял, оно должно получаться довольно длинным. Эпик фэйл. Придется использовать библиотеки, позволяющие работать с большими числами?
http://php.net/manual/ru/ref.bc.php
Мануал не пробовал открывать? Там целый специальный раздел с функциями для больших чисел.
http://php.net/manual/ru/refs.math.php
Там еще несколько расширений php доступно, если совсем матаном упоролся.
- DOM который построил Джек, 5: проверено тут http://arhivach.org/thread/245785/#956739
- https://github.com/never3ver/fileshare - проверено 19 марта: http://arhivach.org/thread/245785/#956732
Далее, на доброчане в /s/ в PHP треде ( dobrochan.org/s/res/23225.xhtml ) я проверил некоторые другие задачи, почитайте ответы к ним:
>>958664 задача с регулярками и телефонным номером, от 22 марта
- студенты https://github.com/sylenien/students-exercise/tree/master
- блог https://github.com/honeydev/s-blog/
- p-sch 19/03/17 >>956914 - вопрос по обработке исключений
- https://github.com/grigoryMovchan/auth/
- https://bitbucket.org/learning_acc/discounts/
- https://github.com/kubk/students
- https://github.com/greenTea242/MinesweeperMVC
Зайдите, посмотрите.
Ну и как всегда, если кого-то из предыдущего треда пропустил, напомните о себе.
>>963742
А ты первый раз что ли с криптографией работаешь? Встроенные в PHP типы данных не годятся:
- int - только до 2 млрд (больше на 64-битных системах, но все равно недостаточно)
- float - не гарантирует точность больше 8-16 знаков после запятой
Потому нужно использовать специальные расширения для точной работы с большими числами:
- http://php.net/manual/ru/book.bc.php
- http://php.net/manual/ru/book.gmp.php
>>963781
@var позволяет указать тип переменной и пишется на предыдущей строке, до переменной. Но недостаток тут в том, что тип надо будет указывать каждый раз, как ты берешь что-то из контейнера. Решения проблемы - описать именно сервисы в самом контейнере:
1) сделать свой класс поверх контейнера (либо унаследовать, либо использовать делегирование), где на каждый сервис будет метод вида
public function getTwig() { return $this->container['twig']; }
Перед методом мы пишем phpdoc @return SomeClass и теперь IDE будет распознавать тип значения при вызове $x = $container->getSomething();
Это максимально совместимо с разными IDE, но требует создания лишнего класса.
2) Использовать плагин для IDE, который умеет читать конфиги конкретного DI контейнера. Применимо к фреймворкам вроде Симфони, где сервисы описываются в конфигах.
Для Pimple есть дампер + плагин для PhpStorm: http://stackoverflow.com/questions/6395737/how-do-i-make-my-php-ide-understand-dependency-injection-containers/6418373#6418373
3) Pimple позволяет получать сервисы, как будто бы они хранятся в полях класса:
$pimple->twig
мы можем унаследовать от Pimple пустой класс и описать типы сервисов в нем с помощью аннотации @property: http://stackoverflow.com/questions/6395737/how-do-i-make-my-php-ide-understand-dependency-injection-containers/6418373#6418373
4) Можно создать специальный файл с описанием сервисов и их типов только для PhpStorm: https://confluence.jetbrains.com/display/PhpStorm/PhpStorm+Advanced+Metadata
В общем, это все описано тут (англ): http://stackoverflow.com/questions/6395737/how-do-i-make-my-php-ide-understand-dependency-injection-containers
Аннотации вида @var или @return или @property - это стандарт phpDoc, советую с ним ознакомиться.
В твоем примере кода подсказку @var можно поставить только на переменную $template.
>>963714
Можно объединять несколько условий с помощью && (И) или || (ИЛИ) или !(НЕ). Не забывай ставить скобки в сложных случаях:
if ($x > 100 && $x < 200 && ($a > 1 || $b > 1 || !($x < 150)))
>>963742
А ты первый раз что ли с криптографией работаешь? Встроенные в PHP типы данных не годятся:
- int - только до 2 млрд (больше на 64-битных системах, но все равно недостаточно)
- float - не гарантирует точность больше 8-16 знаков после запятой
Потому нужно использовать специальные расширения для точной работы с большими числами:
- http://php.net/manual/ru/book.bc.php
- http://php.net/manual/ru/book.gmp.php
>>963781
@var позволяет указать тип переменной и пишется на предыдущей строке, до переменной. Но недостаток тут в том, что тип надо будет указывать каждый раз, как ты берешь что-то из контейнера. Решения проблемы - описать именно сервисы в самом контейнере:
1) сделать свой класс поверх контейнера (либо унаследовать, либо использовать делегирование), где на каждый сервис будет метод вида
public function getTwig() { return $this->container['twig']; }
Перед методом мы пишем phpdoc @return SomeClass и теперь IDE будет распознавать тип значения при вызове $x = $container->getSomething();
Это максимально совместимо с разными IDE, но требует создания лишнего класса.
2) Использовать плагин для IDE, который умеет читать конфиги конкретного DI контейнера. Применимо к фреймворкам вроде Симфони, где сервисы описываются в конфигах.
Для Pimple есть дампер + плагин для PhpStorm: http://stackoverflow.com/questions/6395737/how-do-i-make-my-php-ide-understand-dependency-injection-containers/6418373#6418373
3) Pimple позволяет получать сервисы, как будто бы они хранятся в полях класса:
$pimple->twig
мы можем унаследовать от Pimple пустой класс и описать типы сервисов в нем с помощью аннотации @property: http://stackoverflow.com/questions/6395737/how-do-i-make-my-php-ide-understand-dependency-injection-containers/6418373#6418373
4) Можно создать специальный файл с описанием сервисов и их типов только для PhpStorm: https://confluence.jetbrains.com/display/PhpStorm/PhpStorm+Advanced+Metadata
В общем, это все описано тут (англ): http://stackoverflow.com/questions/6395737/how-do-i-make-my-php-ide-understand-dependency-injection-containers
Аннотации вида @var или @return или @property - это стандарт phpDoc, советую с ним ознакомиться.
В твоем примере кода подсказку @var можно поставить только на переменную $template.
>>963714
Можно объединять несколько условий с помощью && (И) или || (ИЛИ) или !(НЕ). Не забывай ставить скобки в сложных случаях:
if ($x > 100 && $x < 200 && ($a > 1 || $b > 1 || !($x < 150)))
Методы - это действия, которые можно делать с одним конкретным объектом. Они могут считать и возвращать какую-то информацию об объекте или что-то в нем менять. Ну для объекта Работник могут быть такие методы:
- получить текущую зарплату
- повысить ранг
- сделать боссом
Для Департамента - посчитать суммарную зарплату, посчитать число сотрудников, уволить всех, поменять босса, найти сотрудников определенного типа и тд
То есть подумай, какие действия ты хочешь делать с объектом и какие методы понадобятся.
Одна из идей ООП в том, что объект содержит как информацию о какой-то сущности (поля), так и действия, которые с ней можно сделать (методы).
> А за условие в цикле не ругай, так ОП накодил.
Можно поменять, если не нравится.
>>963673
Разные классы нужны, если одно и то же действие для разных профессий делается по-разному. Ну например, подсчет зарплаты идет по разным формулам для инженера и для менеджера (например у менеджера зарплата зависит от опыта, а у инженера от ранга). Вообще, варианта тут два:
- сделать профессию свойством класса Работник. Это работает, если у всех профессий все считается одинаково. Минус - для добавления новой профессии надо править класс
- сделать каждый класс отдельной профессией. можно менять методы расчета для разных профессий, минус - нельзя так просто поменять человеку профессию (так как надо будет создавать новый объект и везде во всей программе заменять старый на новый, что часто невозможно).
Считать зарплату можно тоже по-разному, можно сделать метод у Работника, можно попробовать сделать сторонний объект-калькулятор зарплаты (выгода от второго варианта - можно разом поменять базовую ставку всем, так как она хранится в калькуляторе).
>>963668
Ты не учел проценты, там еще проценты есть, не только комиссия. И что если мы поменяем сумму комиссии или месячную выплату - твое число 4000 тоже само поменяется?
>>963658
Тогда метод логично сделать статическим. Или вообще отдельной функцией. Ибо неправильно создавать одного Работника, только чтобы он создал еще нескольких.
Методы - это действия, которые можно делать с одним конкретным объектом. Они могут считать и возвращать какую-то информацию об объекте или что-то в нем менять. Ну для объекта Работник могут быть такие методы:
- получить текущую зарплату
- повысить ранг
- сделать боссом
Для Департамента - посчитать суммарную зарплату, посчитать число сотрудников, уволить всех, поменять босса, найти сотрудников определенного типа и тд
То есть подумай, какие действия ты хочешь делать с объектом и какие методы понадобятся.
Одна из идей ООП в том, что объект содержит как информацию о какой-то сущности (поля), так и действия, которые с ней можно сделать (методы).
> А за условие в цикле не ругай, так ОП накодил.
Можно поменять, если не нравится.
>>963673
Разные классы нужны, если одно и то же действие для разных профессий делается по-разному. Ну например, подсчет зарплаты идет по разным формулам для инженера и для менеджера (например у менеджера зарплата зависит от опыта, а у инженера от ранга). Вообще, варианта тут два:
- сделать профессию свойством класса Работник. Это работает, если у всех профессий все считается одинаково. Минус - для добавления новой профессии надо править класс
- сделать каждый класс отдельной профессией. можно менять методы расчета для разных профессий, минус - нельзя так просто поменять человеку профессию (так как надо будет создавать новый объект и везде во всей программе заменять старый на новый, что часто невозможно).
Считать зарплату можно тоже по-разному, можно сделать метод у Работника, можно попробовать сделать сторонний объект-калькулятор зарплаты (выгода от второго варианта - можно разом поменять базовую ставку всем, так как она хранится в калькуляторе).
>>963668
Ты не учел проценты, там еще проценты есть, не только комиссия. И что если мы поменяем сумму комиссии или месячную выплату - твое число 4000 тоже само поменяется?
>>963658
Тогда метод логично сделать статическим. Или вообще отдельной функцией. Ибо неправильно создавать одного Работника, только чтобы он создал еще нескольких.
Слишком сложно. Лучше так:
- прибавляем проценты и комиссию к остатку долга (!не вычитаем ничего пока!)
- если остаток маленький, выплачиваем сколько осталось и уходим
- иначе платим 5000
«Платим» здесь значит уменьшаем долг и увеличиваем общую сумму выплаченного.
>>963653
> То есть у объекта Работник должны быть все методы работы с ним.
В этом и идея ООП, что вместе собраны данные (поля) и методы для выполнения действий с ними. Ну условно говоря, представь себе например класс Лифт. "текущий этаж", "открыты ли двери" - это состояние , а "поехать на N-й этаж", "открыть двери" - это методы, меняющие состояние лифта.
Было бы неправильно сделать например класс Лифт только со свойствами, а действия выше в виде отдельных функций.
>>963590
Да, с группами будет неудобно если тебе надо повысить зарплату одному работнику из группы - код переразбиения групп сложный будет. Проще с отдельными объектами, пусть даже так уйдет чуть больше памяти, но у нас там не миллион работников, чтобы о ней беспокоиться.
>>963568
Код на скриншоте однозначно не годится, так как условия с цифрами излишне запутанные. Создать работников можно по-другому, например:
$employees = createEmployees(тип, кол-во, ранг);
$employees = array_merge($employees, createEmployees(тип, кол-во, ранг));
...
Можно сделать описание в массиве вида
[
[кол-во, профессия, ранг],
[кол-во, профессия, ранг],
...
]
А можно сделать массив вида ['3ме1', '2ин3'] и функцию, которая его разберет и создаст нужные объекты.
>>963567
Это да, но пока их там 3, а не 15, можно не заморачиваться.
>>963535
Ты бы код дал ссылкой, а не скриншотом, как его читать?
По коду:
"A наследуется от B" значит, что A является разновидностью B (по английски получается короче: A is B). Например, Банк - это Организация, с дополнительными особенностями (наличие банковской лицензии) потому класс Банк можно наследовать от класса Организация, добавив поле с номером лицензии и методы вроде "внести вклад".
Также, при наследовании мы должны соблюдать совместимость. Мы всегда можем передать объект класса B в код, который рассчитан на объект класса A, и этот код должен работать корректно (принцип замещения Барбары Лисков). В примере выше, если у нас есть функция, которая считает сумму налога на Организацию, в эту функцию можно передать Банк и она должна работать правильно. Так как Банк это разновидность Организации.
В твоем случае "Работники" - это не разновидность Департамента. Наследование применено неверно.
Важно понять этот принцип, а не наследовать все от всего.
Классы называются в единственном числе, не Employees, а EmployeeGroup. Но я бы советовал так не делать, а делать 1 объект = 1 сотрудник, иначе трудно будет например повысить ранг только одному человеку в группе - надо будет переразбивать группу, сложно.
Имена методов пишутся с маленькой буквы, начинаются с глагола: сделайЧтоТо(). Артикль the не используется.
Если у тебя у ГруппыРаботников есть метод вроде посчитатьСуммарнуюЗарплату(), то ему не надо ничего передавать - ведь в объекте и так есть информация об этих работниках. Обычно метод предназначен для выполнения каких-то действий с объектом, с его полями.
> не понял главного - как здесь использовать методы, у меня из-за них одни проблемы, почему не понаписать просто функций?
В этом и идея ООП, что в объекте вместе собраны данные (поля) и методы для выполнения действий с ними. Ну условно говоря, представь себе например класс Лифт. "текущий этаж", "открыты ли двери" - это состояние , а "поехать на N-й этаж", "посчитать высоту", "открыть двери" - это методы, работающие с состоянием лифта.
Было бы неправильно сделать например класс Лифт только со свойствами, а действия выше в виде отдельных функций.
В этой задаче тебе надо правильно определить, какие у тебя будут объекты, какие с ними можно делать действия.
> Я поместил объекты(сотрудников) в массив, но методы не вызываются так как функции, им нужен объект
Да, потому что метод - это часть объекта. Ты же не можешь прочитать поле объекта, не имея самого объекта.
> Откройте мне глаза, зачем, нужны, методы?
Чтобы сразу было видно, какой метод к какому объекту относится. В случае с функциями, это не понять, особенно если программа большая и у тебя тысячи функций, они просто свалены в кучу. А в ООП все методы аккуратно разложены по разным классам. Каждый класс имеет свою зону отвественности и решает свою задачу.
Также, методы позволяют нам использовать инкапсуляцию. Это когда мы делаем поля приватными и доступ к ним можно получить только через методы. Таким образом мы можем к примеру запретить ставить сотруднику ранг больше 3, а если бы у нас было публичное поле, то мы такое ограничение поставить не могли бы.
----
Суть инкапсуляции в том, что класс скрывает (инкапслирует) в себе логику работы с данными и сами данные, а наружу выставляет методы. Пользователю этих методов не важно, как класс устроен внутри, как он хранит данные, ему достаточно вызвать нужный метод чтобы получить результат.
Это упрощает понимание кода: тебе не надо читать и разбирать код класса, достаточно прочитать название метода (и может быть комментарий к нему). Также, это упрощает изменение кода: если какое-то свойство имеет уровень private то доступ к нему возможен только из того же класса и тебе не надо бегать по всему коду и смотреть что там с этим свойством делается, тебе достаточно просмотреть один файл с этим классом.
Инкапсуляция это хорошо. Так как весь код, который занимается одной задачей, оказывается заключен внутри одного класса. Противоположный случай это когда код (или знание о его внутреннем устройстве) вылезает из класса и размазывается по всей программе.
Если проводить аналогии, то можно представить кофе-машину. Ты нажимаешь кнопку (=вызываешь публичный метод) и получаешь кофе (=результат вызова этого метода), при этом ты не видишь что происходит внутри нее и тебе не надо в этом разбираться.
----
> но в моём случае нет объектов к которым я мог это применить, у меня, блядь, массив с объектами.
Это значит, что ты не смог пока придумать решение задачи, соответствующее идеям ООП, и разбить код на отдельные классы, а пытаешься по старой привычке писать все вперемешку.
> что каждый раз вызывая метод - я стираю все переменные внутри, и мой блядь, счетчик зарплат обнулялся.
Это и с функциями так, локальные переменные создаются при входе в функцию и уничтожаются при выходе из нее, ты разве не знал? Так и надо, они предназначены для хранения каких-то временных данных, которые нужны только внутри функции. Условно говоря, ты что-то на листоке посчитал, запомнил результат, а листочек выбросил.
И посмотри, ниже я дал ссылки на статьи с описанием видов отношений между классами.
Слишком сложно. Лучше так:
- прибавляем проценты и комиссию к остатку долга (!не вычитаем ничего пока!)
- если остаток маленький, выплачиваем сколько осталось и уходим
- иначе платим 5000
«Платим» здесь значит уменьшаем долг и увеличиваем общую сумму выплаченного.
>>963653
> То есть у объекта Работник должны быть все методы работы с ним.
В этом и идея ООП, что вместе собраны данные (поля) и методы для выполнения действий с ними. Ну условно говоря, представь себе например класс Лифт. "текущий этаж", "открыты ли двери" - это состояние , а "поехать на N-й этаж", "открыть двери" - это методы, меняющие состояние лифта.
Было бы неправильно сделать например класс Лифт только со свойствами, а действия выше в виде отдельных функций.
>>963590
Да, с группами будет неудобно если тебе надо повысить зарплату одному работнику из группы - код переразбиения групп сложный будет. Проще с отдельными объектами, пусть даже так уйдет чуть больше памяти, но у нас там не миллион работников, чтобы о ней беспокоиться.
>>963568
Код на скриншоте однозначно не годится, так как условия с цифрами излишне запутанные. Создать работников можно по-другому, например:
$employees = createEmployees(тип, кол-во, ранг);
$employees = array_merge($employees, createEmployees(тип, кол-во, ранг));
...
Можно сделать описание в массиве вида
[
[кол-во, профессия, ранг],
[кол-во, профессия, ранг],
...
]
А можно сделать массив вида ['3ме1', '2ин3'] и функцию, которая его разберет и создаст нужные объекты.
>>963567
Это да, но пока их там 3, а не 15, можно не заморачиваться.
>>963535
Ты бы код дал ссылкой, а не скриншотом, как его читать?
По коду:
"A наследуется от B" значит, что A является разновидностью B (по английски получается короче: A is B). Например, Банк - это Организация, с дополнительными особенностями (наличие банковской лицензии) потому класс Банк можно наследовать от класса Организация, добавив поле с номером лицензии и методы вроде "внести вклад".
Также, при наследовании мы должны соблюдать совместимость. Мы всегда можем передать объект класса B в код, который рассчитан на объект класса A, и этот код должен работать корректно (принцип замещения Барбары Лисков). В примере выше, если у нас есть функция, которая считает сумму налога на Организацию, в эту функцию можно передать Банк и она должна работать правильно. Так как Банк это разновидность Организации.
В твоем случае "Работники" - это не разновидность Департамента. Наследование применено неверно.
Важно понять этот принцип, а не наследовать все от всего.
Классы называются в единственном числе, не Employees, а EmployeeGroup. Но я бы советовал так не делать, а делать 1 объект = 1 сотрудник, иначе трудно будет например повысить ранг только одному человеку в группе - надо будет переразбивать группу, сложно.
Имена методов пишутся с маленькой буквы, начинаются с глагола: сделайЧтоТо(). Артикль the не используется.
Если у тебя у ГруппыРаботников есть метод вроде посчитатьСуммарнуюЗарплату(), то ему не надо ничего передавать - ведь в объекте и так есть информация об этих работниках. Обычно метод предназначен для выполнения каких-то действий с объектом, с его полями.
> не понял главного - как здесь использовать методы, у меня из-за них одни проблемы, почему не понаписать просто функций?
В этом и идея ООП, что в объекте вместе собраны данные (поля) и методы для выполнения действий с ними. Ну условно говоря, представь себе например класс Лифт. "текущий этаж", "открыты ли двери" - это состояние , а "поехать на N-й этаж", "посчитать высоту", "открыть двери" - это методы, работающие с состоянием лифта.
Было бы неправильно сделать например класс Лифт только со свойствами, а действия выше в виде отдельных функций.
В этой задаче тебе надо правильно определить, какие у тебя будут объекты, какие с ними можно делать действия.
> Я поместил объекты(сотрудников) в массив, но методы не вызываются так как функции, им нужен объект
Да, потому что метод - это часть объекта. Ты же не можешь прочитать поле объекта, не имея самого объекта.
> Откройте мне глаза, зачем, нужны, методы?
Чтобы сразу было видно, какой метод к какому объекту относится. В случае с функциями, это не понять, особенно если программа большая и у тебя тысячи функций, они просто свалены в кучу. А в ООП все методы аккуратно разложены по разным классам. Каждый класс имеет свою зону отвественности и решает свою задачу.
Также, методы позволяют нам использовать инкапсуляцию. Это когда мы делаем поля приватными и доступ к ним можно получить только через методы. Таким образом мы можем к примеру запретить ставить сотруднику ранг больше 3, а если бы у нас было публичное поле, то мы такое ограничение поставить не могли бы.
----
Суть инкапсуляции в том, что класс скрывает (инкапслирует) в себе логику работы с данными и сами данные, а наружу выставляет методы. Пользователю этих методов не важно, как класс устроен внутри, как он хранит данные, ему достаточно вызвать нужный метод чтобы получить результат.
Это упрощает понимание кода: тебе не надо читать и разбирать код класса, достаточно прочитать название метода (и может быть комментарий к нему). Также, это упрощает изменение кода: если какое-то свойство имеет уровень private то доступ к нему возможен только из того же класса и тебе не надо бегать по всему коду и смотреть что там с этим свойством делается, тебе достаточно просмотреть один файл с этим классом.
Инкапсуляция это хорошо. Так как весь код, который занимается одной задачей, оказывается заключен внутри одного класса. Противоположный случай это когда код (или знание о его внутреннем устройстве) вылезает из класса и размазывается по всей программе.
Если проводить аналогии, то можно представить кофе-машину. Ты нажимаешь кнопку (=вызываешь публичный метод) и получаешь кофе (=результат вызова этого метода), при этом ты не видишь что происходит внутри нее и тебе не надо в этом разбираться.
----
> но в моём случае нет объектов к которым я мог это применить, у меня, блядь, массив с объектами.
Это значит, что ты не смог пока придумать решение задачи, соответствующее идеям ООП, и разбить код на отдельные классы, а пытаешься по старой привычке писать все вперемешку.
> что каждый раз вызывая метод - я стираю все переменные внутри, и мой блядь, счетчик зарплат обнулялся.
Это и с функциями так, локальные переменные создаются при входе в функцию и уничтожаются при выходе из нее, ты разве не знал? Так и надо, они предназначены для хранения каких-то временных данных, которые нужны только внутри функции. Условно говоря, ты что-то на листоке посчитал, запомнил результат, а листочек выбросил.
И посмотри, ниже я дал ссылки на статьи с описанием видов отношений между классами.
Неверно, прочитай мои примеры выше. Департамент это не группа работников, Департамент нанимает Работников, тут между классами отношение делегирования: https://ru.wikipedia.org/wiki/Агрегирование_(программирование)
Насчет людей/митингов, я бы тоже не стал применять наследование, так как Митинг - это событие, а люди - участники события.
Вот нашел статьи, про отношения между классами - можешь почитать, там много всяких видов отношений разобрано:
- http://www.intuit.ru/studies/courses/1007/229/lecture/5956?page=3
- https://habrahabr.ru/post/150041/
- https://metanit.com/sharp/patterns/1.2.php
>>963551
Так может быть удобнее, одна функция считает зарплату одного конкретного работника, другая - сумму по департаменту. Зачем все писать в одну огромную функцию?
И эти 2 метода он предлагает сделать в разных классах.
>>963562
По коду: не ставь пробелы вокруг стрелки, ставь их вокруг математических операций. для switch всегда стоит написать блок default на случай если ты по ошибке поставишь неправильный ранг, чтобы сразу это заметить.
Копипасту в switch стоит убрать, лучше там задавать только коэффициент.
>>963563
Нет, не норма. Если у тебя есть объект, представляющий группу работников, то для расчета зарплаты в метод не надо ничего передавать - эта информация уже есть в объекте.
Ты пытаешься писать код не в ООП-стиле, а как обычный процедурный код из отдельных функций.
А ты решал предыдущие задачи на ООП, про тесты и вопросы и тд?
Неверно, прочитай мои примеры выше. Департамент это не группа работников, Департамент нанимает Работников, тут между классами отношение делегирования: https://ru.wikipedia.org/wiki/Агрегирование_(программирование)
Насчет людей/митингов, я бы тоже не стал применять наследование, так как Митинг - это событие, а люди - участники события.
Вот нашел статьи, про отношения между классами - можешь почитать, там много всяких видов отношений разобрано:
- http://www.intuit.ru/studies/courses/1007/229/lecture/5956?page=3
- https://habrahabr.ru/post/150041/
- https://metanit.com/sharp/patterns/1.2.php
>>963551
Так может быть удобнее, одна функция считает зарплату одного конкретного работника, другая - сумму по департаменту. Зачем все писать в одну огромную функцию?
И эти 2 метода он предлагает сделать в разных классах.
>>963562
По коду: не ставь пробелы вокруг стрелки, ставь их вокруг математических операций. для switch всегда стоит написать блок default на случай если ты по ошибке поставишь неправильный ранг, чтобы сразу это заметить.
Копипасту в switch стоит убрать, лучше там задавать только коэффициент.
>>963563
Нет, не норма. Если у тебя есть объект, представляющий группу работников, то для расчета зарплаты в метод не надо ничего передавать - эта информация уже есть в объекте.
Ты пытаешься писать код не в ООП-стиле, а как обычный процедурный код из отдельных функций.
А ты решал предыдущие задачи на ООП, про тесты и вопросы и тд?
Также, если хочешь лучше разобраться в ООП, предлагаю (только после решения Вектора) глянуть эту задачку посложнее : http://www.cyberforum.ru/php-oop/thread1459985.html
(решения при желании гуглятся, так что не гугли).
И еще эту статью советую тоже: https://habrahabr.ru/post/153225/
>>963442
> Есть серверное, а есть клиентское кэширование (http)?
Да. У браузера есть кеш, когда ты переходишь с одной страницы сайта на другую, браузер может не скачивать повторно CSS-файл, а взять из кеша. Или взять из кеша и спросить сервер, не изменился ли он за это время? Управляется это кеширование HTTP заголовками, которые отдает сервер.
Аналогично, если ты второй раз заходишь в тред на сайте, в котором уже был, браузер может взять страницу из кеша, если сервер это разрешил.
- https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching?hl=ru
- http://html5.by/blog/cache/
- https://ruhighload.com/post/Кэширование+статики+и+cache-control
- https://webo.in/articles/habrahabr/104-client-side-caching-basics/
Разумеется, кеш важно настроить так, чтобы при изменении файла на сервере браузер не пытался бы использовать устаревшую версию из кеша.
Такое кеширование хорошо подходит для статических файлов, но не всегда работает ддя динамических страниц, так как они генерируются каждый раз заново.
И разумеется это кеширование не работает если пользователь впервые зашел на сайт или давно (несколько часов/дней) на нем не был и файлы в кеше оказались вытеснены файлами других сайтов.
Серверный кеш - это другое, это когда приложение сохраняет данные в кеш, чтобы в слудующий раз сэкономить время на их получение, или когда нагрузка на сайт очень высокая (вряд ли это твой случай) и хочется разгрузить базу данных. Надо помнить, что кеш это скорее костыль, которым не от хорошей жизни пользуются, если можно без него обойтись, то хорошо.
На сервере кеширование делать можно на разных уровнях: можно кешировать какие-то промежуточные данные, можно куски HTML разметки, можно целую страницу. Чем больше ты кешируешь, тем сложнее отследить, когда надо сбросить/обновить кеш.
Для начала тебе надо понимать, что, где ты будешь кешировать, как отслеживать изменения исходных данных. От этого зависит, как он будет реализован.
Стандартного решения, которое подходит всем, нет. В каждом проекте надо делать по-своему. Кеш это не программа, которую можно установить и все само заработает. Надо править код приложения скорее всего.
> В общем, как мне кэшировать страничку динамическую, если пользователь ввел данные на эту страницу и они обновились в бд и при перезагрузке ему нужно вывести эту же страницу только с новыми данными (а они берутся из старого кэша, а не из бд)?
Первое, о чем тебе стоит подумать - это можно ли обойтись без кеша (тем более что судя по твоим вопросам, ты вообще пока плохо понимаешь, как он работает и какие есть подводные камни). Ведь данные на странице могут измениться, ну представь, что выводится список последних комментариев, и где-то на другой странице добавлен комментарий, надо обновить этот список. Или представь, что в углу страницы выводится город пользователя - тогда целиком страницу кешировать нельзя, так как для разных пользователей город разный.
> Как обновлять кэш при POST запросе?
Очистить либо обновить содержимое ячейки кеша. Как именно зависит от того, какой ты кеш используешь.
> Для этого нужно использовать редис, nginx или memcashed?
Ты все смешал вместе. Редис - это хранилище, нгинкс - это веб-сервер. Хотя их можно использовать вместе.
> Почитал англоязычный ресурс, там написано, что кэш удаляется при пост запросе,
Бред. Это наверно какой-то частный случай, то есть на каком-то одном сайте сделано так, что при POST запросе удаляется какой-то элемент кеша. Это не рецепт, который подходит всем.
> В докладе что-то про сокеты говорится, но разрабы с моей работы говорили, что создавать на каждое соединение по сокету при хайлоаде - не эффективно.
Если ты не понимаешь о чем речь в докладе, то надо сначала с ним разобраться, прежде чем браться за кеширование.
>>963335
Тернарный оператор
Также, если хочешь лучше разобраться в ООП, предлагаю (только после решения Вектора) глянуть эту задачку посложнее : http://www.cyberforum.ru/php-oop/thread1459985.html
(решения при желании гуглятся, так что не гугли).
И еще эту статью советую тоже: https://habrahabr.ru/post/153225/
>>963442
> Есть серверное, а есть клиентское кэширование (http)?
Да. У браузера есть кеш, когда ты переходишь с одной страницы сайта на другую, браузер может не скачивать повторно CSS-файл, а взять из кеша. Или взять из кеша и спросить сервер, не изменился ли он за это время? Управляется это кеширование HTTP заголовками, которые отдает сервер.
Аналогично, если ты второй раз заходишь в тред на сайте, в котором уже был, браузер может взять страницу из кеша, если сервер это разрешил.
- https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching?hl=ru
- http://html5.by/blog/cache/
- https://ruhighload.com/post/Кэширование+статики+и+cache-control
- https://webo.in/articles/habrahabr/104-client-side-caching-basics/
Разумеется, кеш важно настроить так, чтобы при изменении файла на сервере браузер не пытался бы использовать устаревшую версию из кеша.
Такое кеширование хорошо подходит для статических файлов, но не всегда работает ддя динамических страниц, так как они генерируются каждый раз заново.
И разумеется это кеширование не работает если пользователь впервые зашел на сайт или давно (несколько часов/дней) на нем не был и файлы в кеше оказались вытеснены файлами других сайтов.
Серверный кеш - это другое, это когда приложение сохраняет данные в кеш, чтобы в слудующий раз сэкономить время на их получение, или когда нагрузка на сайт очень высокая (вряд ли это твой случай) и хочется разгрузить базу данных. Надо помнить, что кеш это скорее костыль, которым не от хорошей жизни пользуются, если можно без него обойтись, то хорошо.
На сервере кеширование делать можно на разных уровнях: можно кешировать какие-то промежуточные данные, можно куски HTML разметки, можно целую страницу. Чем больше ты кешируешь, тем сложнее отследить, когда надо сбросить/обновить кеш.
Для начала тебе надо понимать, что, где ты будешь кешировать, как отслеживать изменения исходных данных. От этого зависит, как он будет реализован.
Стандартного решения, которое подходит всем, нет. В каждом проекте надо делать по-своему. Кеш это не программа, которую можно установить и все само заработает. Надо править код приложения скорее всего.
> В общем, как мне кэшировать страничку динамическую, если пользователь ввел данные на эту страницу и они обновились в бд и при перезагрузке ему нужно вывести эту же страницу только с новыми данными (а они берутся из старого кэша, а не из бд)?
Первое, о чем тебе стоит подумать - это можно ли обойтись без кеша (тем более что судя по твоим вопросам, ты вообще пока плохо понимаешь, как он работает и какие есть подводные камни). Ведь данные на странице могут измениться, ну представь, что выводится список последних комментариев, и где-то на другой странице добавлен комментарий, надо обновить этот список. Или представь, что в углу страницы выводится город пользователя - тогда целиком страницу кешировать нельзя, так как для разных пользователей город разный.
> Как обновлять кэш при POST запросе?
Очистить либо обновить содержимое ячейки кеша. Как именно зависит от того, какой ты кеш используешь.
> Для этого нужно использовать редис, nginx или memcashed?
Ты все смешал вместе. Редис - это хранилище, нгинкс - это веб-сервер. Хотя их можно использовать вместе.
> Почитал англоязычный ресурс, там написано, что кэш удаляется при пост запросе,
Бред. Это наверно какой-то частный случай, то есть на каком-то одном сайте сделано так, что при POST запросе удаляется какой-то элемент кеша. Это не рецепт, который подходит всем.
> В докладе что-то про сокеты говорится, но разрабы с моей работы говорили, что создавать на каждое соединение по сокету при хайлоаде - не эффективно.
Если ты не понимаешь о чем речь в докладе, то надо сначала с ним разобраться, прежде чем браться за кеширование.
>>963335
Тернарный оператор
В README хорошо бы кратко еще написать, как развернуть проект (залить дамп в БД, прописать пароли в конфиге, запустить композер и тд)
Папки vendor в репозитории не должно быть, убери ее, закоммить, добавь ее в гитигнор, закоммить снова, верни на место. Тот, кто скачает твой код, сделает composer install и нужные версии зависимостей, прописанные в composer.lock, установятся. Нет никакого смысла копировать сторонние библиотеки в твой репозиторий (и еще в тысячу других), надо стремиться чтобы там был только твой код.
Лог тоже в гитигнор.
https://github.com/Si0n/fileshare-project/blob/master/config/config-dist.php
тут стоит добавить комментарий, что это образец конфига, и что с ним делать.
> "dir" => "/var/www/fileshare.home/files"
Это неудобно, лучше сделать автоматическое определение текущей папки.
> 'driver' => 'mysql',
Хорошо бы в конфиге писать только те настройки, что пользователь может поменять. Ведь если мы тут пропишем другой тип БД, все перестанет работать, так как твои запросы написаны под mysql?
https://github.com/Si0n/fileshare-project/blob/master/system/bootstrap.php#L8
> require_once '../controller/file.controller.php';
> require_once '../controller/home.controller.php';
настрой автозагрузку по PSR-4 через композер, у меня есть урок на гитхабе https://github.com/codedokode/pasta/blob/master/php/autoload.md
https://github.com/Si0n/fileshare-project/blob/master/system/dir.php
Имя и папку с файлом надо привести в соответствие с PSR-4
И зачем там final? Есть какие-то веские причины почему тут запрещено наследование?
https://github.com/Si0n/fileshare-project/blob/master/system/dependencies.php#L26
> $container['App\Controller\File'] = function ($c) use ($app) {
По умолчанию контейнер при повторном обращении не создает новый экземпляр класса, а возвращает старый. Для контроллера это нелогично, так как удобнее, когда один контроллер обрабатывает один запрос и выкидывается, а не используется для обработки нескольких запросов. Лучше сделать, чтобы каждый раз создавался новый.
> (str_ireplace('index.php', '', $container['request']->getUri()->getBasePath())
Это коряво. А что, если папка называется index.php? Удалить имя файла из пути удобнее через dirname().
Насчет логгера - хорошо бы для продакшена логгировать поменьше, чтобы не копились мегабайты ненужных логов. А логгировать на продакшене только важные вещи.
https://github.com/Si0n/fileshare-project/blob/master/system/controller.php#L10
> var $app;
Что это за устаревший синтаксис из PHP4? Ты по учебнику какого года учился?
https://github.com/Si0n/fileshare-project/blob/master/system/controller.php#L19
> public function __get($var) {
Я не советую тут использовать магию, так как при опечатке в имени свойства ошибка не будет замечена. Также непонятно почему это публичный метод. В задачи контроллера входит предоставлять другим классам сервисы? Я думал, это задача контейнера.
> public function setModel($model) {
Непонимание MVC. Между контроллерами и моделями нет соответствия один-к-одному. Плюс твой метод подразумевает, что одному контроллеру можно давать разные модели, и он в любом случае будет корректно работать. Не думаю , что у тебя это так.
> abstract public function index($request, $response, $args);
Название неудачное, лучше handleRequest(). И тайп-хинты проставить.
> use App\Local\File as LocalFile;
Этого лучше избегать, синонимы запутывают чтение кода, человек не робот, чтобы в уме их преобразовывать в имена классов.
https://github.com/Si0n/fileshare-project/blob/master/controller/file.controller.php
Имя файла не соответствует PSR-4.
https://github.com/Si0n/fileshare-project/blob/master/public/index.php#L2
> ini_set('display_errors', 1);
Это логичнее в php.ini задавать, или ты и на продакшене собрался показывать всем ошибки?
> require '../vendor/autoload.php';
> require '../config/config.php';
Это логично перенести в бутстрап.
> $capsule = new Illuminate\Database\Capsule\Manager;
И это тоже.
Вот тебе кстати дополнительная задачка для лучшего понимния архитектуры: сделай скрипты, которые позволяют из командной строки загружать или удалять файлы в файлообменник. Например так:
$ php cli/upload.php /tmp/file.txt
http://example.com/file/123456
Можно добавить опции, например
$ php cli/upload.php --comment="Комментарий к файлу" /tmp/file.txt
Для разбора опций есть функция getopt.
https://github.com/Si0n/fileshare-project/blob/master/public/css/style.css#L77
> input[type=file] {
Это неправильный стиль, он на всем сайте скроет поля выбора файла, а надо только в одном конкретном месте.
https://github.com/Si0n/fileshare-project/blob/master/sql/install.sql#L3
А где таблица юзеров?
> `filename` VARCHAR(155) NOT NULL,
> `path` VARCHAR(255) NOT NULL,
Зачем путь к файлу в 2 частях хранить?
> `status` TINYINT(1)
тут бы ENUM подошел лучше
https://github.com/Si0n/fileshare-project/blob/master/system/controller.php#L11
> protected $table;
Очень странное поле, и непонятно зачем оно тут.
> protected $html;
То же самое.
https://github.com/Si0n/fileshare-project/blob/master/system/router.php#L4
> $this->{'App\Controller\Home'}-
Как-то странно смотрится. Тут лучше либо синтаксис массива использовать, либо дать сервису другое имя.
> $uploaded_files = $this->{'App\Controller\File'}->upload($request);
Это неправильное использование контроллера. Контроллер это не сервис, чтобы его так можно было вызывать. Контроллер обычно получает на вход запрос и выдет на выходе HTTP ответ, например HTML страницу.
> $app->get('/files/{file_id}', function ($request, $response, $args) use ($app) {
> //Need to check file owner
> $this->{'App\Controller\File'}->files($request, $args);
тут почему-то не используется $response
Также, обрати внимание, Слим позволяет указывать в качестве обработчика сервис-контроллер: https://www.slimframework.com/docs/objects/router.html#container-resolution и тебе не надо писать анонимные функции.
> "document" => ["title" => "Home page",
> "styles" => ["/css/bootstrap.min.css", "/css/style.css"]]
Зачем эти многоэтажные массивы? Лучше либо отдельные переменные, либо объект с полями и методами. Ну и передавать одни и те же стили для каждой страницы не очень удобно, может стоит как-то их по умолчанию задать?
Кстати, добавлять скрипты к странице (а также переопределять title) можно через наследование шаблонов в твиге, если оставить в head зону для их добавления.
> "upload" => "/upload"
Неудачное название, трудно понять, что это? URL для формы? Тогда лучше его там же и прописать либо получать какой-нибудь функцией.
https://github.com/Si0n/fileshare-project/blob/master/controller/file.controller.php
Код отсюда надо будет вынести в сервис загрузки файлов, иначе ты не сможешь сделать задачу про cli скрипты. перечитай на всякий случай мой урок по MVC: https://github.com/codedokode/pasta/blob/master/arch/mvc.md
Обрати внимание:
> Весь функционал приложения содержится в модели. Контроллер и вью предоставляют лишь возможность пользователю взаимодействовать с моделью и отображать данные из нее. К примеру, если мы делаем сайт объявлений, с такими функциями, как "добавить объявление", "удалить объявление", "найти объявления по критериям", то для каждого действия где-то в модели должна быть функция, которую можно вызвать. Если выкинуть все контроллеры и вью, то мы все равно можем добавлять объявления, вызывая методы модели.
https://github.com/Si0n/fileshare-project/blob/master/model/file.model.php
> public function setFile(FileController $file) {
Здесь что-то очень неправильное. Контроллер это не модель, чтобы хранить информацию о файле и иметь методы вроде getDescription(). У контроллера могут быть только методы вроде handleRequest(). А методы вроде getDescription() должны быть как раз у модели. Перечитай урок по MVC.
https://github.com/Si0n/fileshare-project/blob/master/controller/file.controller.php#L33
> $file_model = new FileModel();
> foreach ($files as $file) {
> $local_file = $this->uploadFile($file);
тут непонимание, как работает ORM. Модель представляет информацию об одном файле, одну модель нелогично использовать для загрузки нескольких разных файлов.
Почитай про active record https://github.com/codedokode/pasta/blob/master/db/patterns-oop.md
Ну и вообще, с Eloquent тебе надо лучше разобраться, что-то пока ощущение что ты его не очень знаешь.
https://github.com/Si0n/fileshare-project/blob/master/view/layout.twig#L6
> maximum-scale=1.0, minimum-scale=1.0">
Зачем так делать? Ты издеваешься над пользователями что ли?
Вместо include body.twig удобнее использовать наследование шаблонов, когда страница наследуется от лейаута.
В README хорошо бы кратко еще написать, как развернуть проект (залить дамп в БД, прописать пароли в конфиге, запустить композер и тд)
Папки vendor в репозитории не должно быть, убери ее, закоммить, добавь ее в гитигнор, закоммить снова, верни на место. Тот, кто скачает твой код, сделает composer install и нужные версии зависимостей, прописанные в composer.lock, установятся. Нет никакого смысла копировать сторонние библиотеки в твой репозиторий (и еще в тысячу других), надо стремиться чтобы там был только твой код.
Лог тоже в гитигнор.
https://github.com/Si0n/fileshare-project/blob/master/config/config-dist.php
тут стоит добавить комментарий, что это образец конфига, и что с ним делать.
> "dir" => "/var/www/fileshare.home/files"
Это неудобно, лучше сделать автоматическое определение текущей папки.
> 'driver' => 'mysql',
Хорошо бы в конфиге писать только те настройки, что пользователь может поменять. Ведь если мы тут пропишем другой тип БД, все перестанет работать, так как твои запросы написаны под mysql?
https://github.com/Si0n/fileshare-project/blob/master/system/bootstrap.php#L8
> require_once '../controller/file.controller.php';
> require_once '../controller/home.controller.php';
настрой автозагрузку по PSR-4 через композер, у меня есть урок на гитхабе https://github.com/codedokode/pasta/blob/master/php/autoload.md
https://github.com/Si0n/fileshare-project/blob/master/system/dir.php
Имя и папку с файлом надо привести в соответствие с PSR-4
И зачем там final? Есть какие-то веские причины почему тут запрещено наследование?
https://github.com/Si0n/fileshare-project/blob/master/system/dependencies.php#L26
> $container['App\Controller\File'] = function ($c) use ($app) {
По умолчанию контейнер при повторном обращении не создает новый экземпляр класса, а возвращает старый. Для контроллера это нелогично, так как удобнее, когда один контроллер обрабатывает один запрос и выкидывается, а не используется для обработки нескольких запросов. Лучше сделать, чтобы каждый раз создавался новый.
> (str_ireplace('index.php', '', $container['request']->getUri()->getBasePath())
Это коряво. А что, если папка называется index.php? Удалить имя файла из пути удобнее через dirname().
Насчет логгера - хорошо бы для продакшена логгировать поменьше, чтобы не копились мегабайты ненужных логов. А логгировать на продакшене только важные вещи.
https://github.com/Si0n/fileshare-project/blob/master/system/controller.php#L10
> var $app;
Что это за устаревший синтаксис из PHP4? Ты по учебнику какого года учился?
https://github.com/Si0n/fileshare-project/blob/master/system/controller.php#L19
> public function __get($var) {
Я не советую тут использовать магию, так как при опечатке в имени свойства ошибка не будет замечена. Также непонятно почему это публичный метод. В задачи контроллера входит предоставлять другим классам сервисы? Я думал, это задача контейнера.
> public function setModel($model) {
Непонимание MVC. Между контроллерами и моделями нет соответствия один-к-одному. Плюс твой метод подразумевает, что одному контроллеру можно давать разные модели, и он в любом случае будет корректно работать. Не думаю , что у тебя это так.
> abstract public function index($request, $response, $args);
Название неудачное, лучше handleRequest(). И тайп-хинты проставить.
> use App\Local\File as LocalFile;
Этого лучше избегать, синонимы запутывают чтение кода, человек не робот, чтобы в уме их преобразовывать в имена классов.
https://github.com/Si0n/fileshare-project/blob/master/controller/file.controller.php
Имя файла не соответствует PSR-4.
https://github.com/Si0n/fileshare-project/blob/master/public/index.php#L2
> ini_set('display_errors', 1);
Это логичнее в php.ini задавать, или ты и на продакшене собрался показывать всем ошибки?
> require '../vendor/autoload.php';
> require '../config/config.php';
Это логично перенести в бутстрап.
> $capsule = new Illuminate\Database\Capsule\Manager;
И это тоже.
Вот тебе кстати дополнительная задачка для лучшего понимния архитектуры: сделай скрипты, которые позволяют из командной строки загружать или удалять файлы в файлообменник. Например так:
$ php cli/upload.php /tmp/file.txt
http://example.com/file/123456
Можно добавить опции, например
$ php cli/upload.php --comment="Комментарий к файлу" /tmp/file.txt
Для разбора опций есть функция getopt.
https://github.com/Si0n/fileshare-project/blob/master/public/css/style.css#L77
> input[type=file] {
Это неправильный стиль, он на всем сайте скроет поля выбора файла, а надо только в одном конкретном месте.
https://github.com/Si0n/fileshare-project/blob/master/sql/install.sql#L3
А где таблица юзеров?
> `filename` VARCHAR(155) NOT NULL,
> `path` VARCHAR(255) NOT NULL,
Зачем путь к файлу в 2 частях хранить?
> `status` TINYINT(1)
тут бы ENUM подошел лучше
https://github.com/Si0n/fileshare-project/blob/master/system/controller.php#L11
> protected $table;
Очень странное поле, и непонятно зачем оно тут.
> protected $html;
То же самое.
https://github.com/Si0n/fileshare-project/blob/master/system/router.php#L4
> $this->{'App\Controller\Home'}-
Как-то странно смотрится. Тут лучше либо синтаксис массива использовать, либо дать сервису другое имя.
> $uploaded_files = $this->{'App\Controller\File'}->upload($request);
Это неправильное использование контроллера. Контроллер это не сервис, чтобы его так можно было вызывать. Контроллер обычно получает на вход запрос и выдет на выходе HTTP ответ, например HTML страницу.
> $app->get('/files/{file_id}', function ($request, $response, $args) use ($app) {
> //Need to check file owner
> $this->{'App\Controller\File'}->files($request, $args);
тут почему-то не используется $response
Также, обрати внимание, Слим позволяет указывать в качестве обработчика сервис-контроллер: https://www.slimframework.com/docs/objects/router.html#container-resolution и тебе не надо писать анонимные функции.
> "document" => ["title" => "Home page",
> "styles" => ["/css/bootstrap.min.css", "/css/style.css"]]
Зачем эти многоэтажные массивы? Лучше либо отдельные переменные, либо объект с полями и методами. Ну и передавать одни и те же стили для каждой страницы не очень удобно, может стоит как-то их по умолчанию задать?
Кстати, добавлять скрипты к странице (а также переопределять title) можно через наследование шаблонов в твиге, если оставить в head зону для их добавления.
> "upload" => "/upload"
Неудачное название, трудно понять, что это? URL для формы? Тогда лучше его там же и прописать либо получать какой-нибудь функцией.
https://github.com/Si0n/fileshare-project/blob/master/controller/file.controller.php
Код отсюда надо будет вынести в сервис загрузки файлов, иначе ты не сможешь сделать задачу про cli скрипты. перечитай на всякий случай мой урок по MVC: https://github.com/codedokode/pasta/blob/master/arch/mvc.md
Обрати внимание:
> Весь функционал приложения содержится в модели. Контроллер и вью предоставляют лишь возможность пользователю взаимодействовать с моделью и отображать данные из нее. К примеру, если мы делаем сайт объявлений, с такими функциями, как "добавить объявление", "удалить объявление", "найти объявления по критериям", то для каждого действия где-то в модели должна быть функция, которую можно вызвать. Если выкинуть все контроллеры и вью, то мы все равно можем добавлять объявления, вызывая методы модели.
https://github.com/Si0n/fileshare-project/blob/master/model/file.model.php
> public function setFile(FileController $file) {
Здесь что-то очень неправильное. Контроллер это не модель, чтобы хранить информацию о файле и иметь методы вроде getDescription(). У контроллера могут быть только методы вроде handleRequest(). А методы вроде getDescription() должны быть как раз у модели. Перечитай урок по MVC.
https://github.com/Si0n/fileshare-project/blob/master/controller/file.controller.php#L33
> $file_model = new FileModel();
> foreach ($files as $file) {
> $local_file = $this->uploadFile($file);
тут непонимание, как работает ORM. Модель представляет информацию об одном файле, одну модель нелогично использовать для загрузки нескольких разных файлов.
Почитай про active record https://github.com/codedokode/pasta/blob/master/db/patterns-oop.md
Ну и вообще, с Eloquent тебе надо лучше разобраться, что-то пока ощущение что ты его не очень знаешь.
https://github.com/Si0n/fileshare-project/blob/master/view/layout.twig#L6
> maximum-scale=1.0, minimum-scale=1.0">
Зачем так делать? Ты издеваешься над пользователями что ли?
Вместо include body.twig удобнее использовать наследование шаблонов, когда страница наследуется от лейаута.
> Я не могу представить, как должно выглядеть следующее: Компания создаёт Департамент, который создаёт Работников. Как, например, в этом случае потом отдельно создавать работников и включать их в компанию? Не могу осмыслить...
компания = создать Компанию;
департамент = создать Департамент;
компания->добавитьДепартамент(депармамент);
сотрудник = создать Сотрудника();
депарматент->добавитьСотрудника(сотрудник);
И так далее.
> То есть я вообще неверно понимал, что Компания должна создавать Департаменты, Департамент должен создавать Работника... Получается, этим всем могут заниматься простые функции, а методы в этих классах работают только с подсчётом всего по компании или департаменту?
Департамент может создавать Сотрудников, но это делает наш код менее гибким, так как может быть мы хотим создать его как-то по своему, как-то его настроить. А в твоем случае получается вообще без компании нельзя создать отдельно сотрудника. То есть это лишние ограничения, и не очень понятно, ради чего.
И там еще есть один момент. В твоем варианте, чтобы добавить новую профессию, надо править существующий код. В моем - просто добавить новый класс, не трогая старый код. Гибче. А у тебя нало программу в нескольких местах править (свитч как минимум). А представь, когда она огромная, и надо еще эти места все найти.
Ну и бывают случаи, когда код править нельзя - если это например сторонняя библиотека с классами.
Такое имело бы смысл, если бы сотрудник не мог существовать без Компании. Но в теории, он может - он может уволиться из одной компании и перейти в другую например. Или поменять депарматент.
Такое можно было бы применить например для Департамента - если он не может существовать вне Компании, то можно сделать в компании метод создатьДепартамент(название), но опять же я тут особой выгоды не вижу, мне кажется удобнее, когда мы создаем Департамент любым способом и добавляем в Компанию.
> Ну, тогда можно ведь в конструктор добавить $this->experience = $experience;, а в аргументах поставить по умолчанию $experience = false, чтобы уже имеющииеся работники у нас создавались нормально? Горожу что-то непонятное, конечно.
Ну так это надо в нескольких местах править. А в моем варианте - только в классе с профессией. Идея ООП в том, что то, что относится только к одной профессии, желательно поместить в ее класс, чтобы у каждого класса была своя зона ответственности. А ты пытаешься особенности профессии размазать по всей программе, вместо того, чтобы собрать в одном классе.
Вот у тебя например зарплата Инженера хранится не в его классе, а в Департаменте. Тут конечно есть своя логика (компания ведь назначает зарплату), но может быть удобнее было бы это хранить именно в классе Инженера.
> class Manager extends Employee {
> public $rank = 1;
> public $boss = false;
Это писать не надо, при наследовании все свойства наследуются из родительского класса.
>>962275
Вырезаешь (mb_substr) первую букву из строки, делаешь заглавной, вырезаешь остаток строки со второй буквы, приклеиваешь к первой букве.
>>960493
> нельзя делать апдейт поверх данных,
Если речь о добавлении, переименовании таблиц и колонок, то можно. Если изменение типа колонки - то надо чтобы при конвертации ничего не потерялось. Но вообще БД по максимуму пытается сохранить данные. Более подробно можно почитать в мануале на англ: https://dev.mysql.com/doc/refman/5.7/en/alter-table.html
Или там постгрес? Самостоятельно тогда найти мануал постгрес по ALTER TABLE, он есть и на англ, и в хорошем переводе.
> Я ещё предполагал, что есть некоторая договоренность между программистами делать для каждой таблицы колонку с id.
На практие они почти везде нужны, так как например для удаления или обновления надо указать, какую именно запись мы хотим обновить. Но первичный ключ можно делать и составным.
> Я не могу представить, как должно выглядеть следующее: Компания создаёт Департамент, который создаёт Работников. Как, например, в этом случае потом отдельно создавать работников и включать их в компанию? Не могу осмыслить...
компания = создать Компанию;
департамент = создать Департамент;
компания->добавитьДепартамент(депармамент);
сотрудник = создать Сотрудника();
депарматент->добавитьСотрудника(сотрудник);
И так далее.
> То есть я вообще неверно понимал, что Компания должна создавать Департаменты, Департамент должен создавать Работника... Получается, этим всем могут заниматься простые функции, а методы в этих классах работают только с подсчётом всего по компании или департаменту?
Департамент может создавать Сотрудников, но это делает наш код менее гибким, так как может быть мы хотим создать его как-то по своему, как-то его настроить. А в твоем случае получается вообще без компании нельзя создать отдельно сотрудника. То есть это лишние ограничения, и не очень понятно, ради чего.
И там еще есть один момент. В твоем варианте, чтобы добавить новую профессию, надо править существующий код. В моем - просто добавить новый класс, не трогая старый код. Гибче. А у тебя нало программу в нескольких местах править (свитч как минимум). А представь, когда она огромная, и надо еще эти места все найти.
Ну и бывают случаи, когда код править нельзя - если это например сторонняя библиотека с классами.
Такое имело бы смысл, если бы сотрудник не мог существовать без Компании. Но в теории, он может - он может уволиться из одной компании и перейти в другую например. Или поменять депарматент.
Такое можно было бы применить например для Департамента - если он не может существовать вне Компании, то можно сделать в компании метод создатьДепартамент(название), но опять же я тут особой выгоды не вижу, мне кажется удобнее, когда мы создаем Департамент любым способом и добавляем в Компанию.
> Ну, тогда можно ведь в конструктор добавить $this->experience = $experience;, а в аргументах поставить по умолчанию $experience = false, чтобы уже имеющииеся работники у нас создавались нормально? Горожу что-то непонятное, конечно.
Ну так это надо в нескольких местах править. А в моем варианте - только в классе с профессией. Идея ООП в том, что то, что относится только к одной профессии, желательно поместить в ее класс, чтобы у каждого класса была своя зона ответственности. А ты пытаешься особенности профессии размазать по всей программе, вместо того, чтобы собрать в одном классе.
Вот у тебя например зарплата Инженера хранится не в его классе, а в Департаменте. Тут конечно есть своя логика (компания ведь назначает зарплату), но может быть удобнее было бы это хранить именно в классе Инженера.
> class Manager extends Employee {
> public $rank = 1;
> public $boss = false;
Это писать не надо, при наследовании все свойства наследуются из родительского класса.
>>962275
Вырезаешь (mb_substr) первую букву из строки, делаешь заглавной, вырезаешь остаток строки со второй буквы, приклеиваешь к первой букве.
>>960493
> нельзя делать апдейт поверх данных,
Если речь о добавлении, переименовании таблиц и колонок, то можно. Если изменение типа колонки - то надо чтобы при конвертации ничего не потерялось. Но вообще БД по максимуму пытается сохранить данные. Более подробно можно почитать в мануале на англ: https://dev.mysql.com/doc/refman/5.7/en/alter-table.html
Или там постгрес? Самостоятельно тогда найти мануал постгрес по ALTER TABLE, он есть и на англ, и в хорошем переводе.
> Я ещё предполагал, что есть некоторая договоренность между программистами делать для каждой таблицы колонку с id.
На практие они почти везде нужны, так как например для удаления или обновления надо указать, какую именно запись мы хотим обновить. Но первичный ключ можно делать и составным.
> for ($credit=40000; $credit>0; $credit=($credit$persent+$service)-$payment)
Слишком много кода в шапке цикла, тяжело читать, надо перенести формулу в тело.
> if ($credit+$service<5000)
Не учтен процент
> $credit=($credit+($credit0.03+1000));
Формула повторяется второй раз.
>>960603
Тут формула повторяется 3 раза, попробуй избавиться от повторов.
>>960747
>>960862
Вообще у меня есть урок по теме https://gist.github.com/codedokode/772a4ccc03e41d6b7cba
>>960928
А погуглить? "js carousel"
>>961000
> Почему бы просто не сделать это всё свойством класса?
> Смотришь на класс и свойства - видишь кофе, зарплату, страницы, а так надо смотреть в метод addEmployee, чтобы это всё узнать или поменять?
Так там есть условно говоря 2 зарплаты:
- базовая ставка для данной профессии
- реальная зарплата с учетом ранга и статуса босса
Первое может быть свойством. Второе - не стоит делать свойством, так как оно вычисляется из базовой ставки, ранга, статуса босса и при изменении любого из них должно автоматически пересчитываться. Это сложно, проще сделать метод, который считает реальную зарплату каждый раз заново.
>>961014
Ну вот в итоге так и сделано, как я и хотел. Только в switch надо добавить default на случай, если мы ошиблись и поставили неправильный ранг, чтобы прервать программу.
> Я помню, ты всегда говорил, что всё то, что может вычисляться, не надо хранить, но если мы представим, что нам надо создать миллионы экземпляров работников, то это будет большей нагрузкой, чем просто хранить свойства в их классах, разве нет?
Не факт. Ведь нам все равно эту зарплату миллион раз считать придется, только в другом месте кода. И для хранения свойств ведь больше памяти пондобится. Это надо мерять и проверять. И у нас нет миллиона работников в задаче.
Но главное тут не производительность, а то, что нам надо будет автоматически при изменении ранга как-то пересчитвать и зарплату, если она хранится в свойстве. замучаешься это писать.
> for ($credit=40000; $credit>0; $credit=($credit$persent+$service)-$payment)
Слишком много кода в шапке цикла, тяжело читать, надо перенести формулу в тело.
> if ($credit+$service<5000)
Не учтен процент
> $credit=($credit+($credit0.03+1000));
Формула повторяется второй раз.
>>960603
Тут формула повторяется 3 раза, попробуй избавиться от повторов.
>>960747
>>960862
Вообще у меня есть урок по теме https://gist.github.com/codedokode/772a4ccc03e41d6b7cba
>>960928
А погуглить? "js carousel"
>>961000
> Почему бы просто не сделать это всё свойством класса?
> Смотришь на класс и свойства - видишь кофе, зарплату, страницы, а так надо смотреть в метод addEmployee, чтобы это всё узнать или поменять?
Так там есть условно говоря 2 зарплаты:
- базовая ставка для данной профессии
- реальная зарплата с учетом ранга и статуса босса
Первое может быть свойством. Второе - не стоит делать свойством, так как оно вычисляется из базовой ставки, ранга, статуса босса и при изменении любого из них должно автоматически пересчитываться. Это сложно, проще сделать метод, который считает реальную зарплату каждый раз заново.
>>961014
Ну вот в итоге так и сделано, как я и хотел. Только в switch надо добавить default на случай, если мы ошиблись и поставили неправильный ранг, чтобы прервать программу.
> Я помню, ты всегда говорил, что всё то, что может вычисляться, не надо хранить, но если мы представим, что нам надо создать миллионы экземпляров работников, то это будет большей нагрузкой, чем просто хранить свойства в их классах, разве нет?
Не факт. Ведь нам все равно эту зарплату миллион раз считать придется, только в другом месте кода. И для хранения свойств ведь больше памяти пондобится. Это надо мерять и проверять. И у нас нет миллиона работников в задаче.
Но главное тут не производительность, а то, что нам надо будет автоматически при изменении ранга как-то пересчитвать и зарплату, если она хранится в свойстве. замучаешься это писать.
> $regexp = '/ + /u';
Тут можно обойтись без дублирования пробелов, например так: {2,}
> //проверяем, чтобы первый символ был не пробелом{
Тут может trim() проще использовать?
> $other = mb_substr($text, $second);
> $first = mb_strtoupper($first);
> $text = $first . $other;
Это можно записать в одну строку без лишних переменных.
Так в общем верно, но закомментированиые куски кода стоит убрать.
>>961149
Доктрина использует прокси-классы для ленивой загрузки. Ну допустим у тебя в классе Тест есть поле Автор. По идее, когда ты загружаешь из БД один Тест, доктрина должна загрузить и создать объект Автора. Если у Автора есть другие связи, она и их должна заполнить. Так мы скоро придем к тому, что надо половину базы данных в память загрузить.
А не загрузить - нельзя, так как иначе непонятно, как получить автора теста.
Потому Доктрина использует прокси-классы. Прокси-класс наследуется от сущности (чтобы проходить все тайп-хинты) и генерируется автоматически. Для каждого метода в исходном классе генерируется метод-обертка. Эти классы кладутся по моему во временную папку, которая задается в конфиге Доктрины.
Вместо реального Автора доктрина вставляет объект-прокси. У этого объектавсе поля пустые, кроме id, и при вызове любого метода, кроме getId() (например getName()), сначала запускается загрузка данных из базы, эти данные загружаются в поля объекта, и только после этого вызывается исходный метод. И таким образом, получается "ленивая" загрузка, прозрачно для твоего кода.
Это объясняет ограничения, которые доктрина накладывает на классы - например, запрет использовать публичные поля, так как обращение к ним невозможно перехватить в классе-наследнике.
Можешь попробовать сам написать пример прокси-класса, чтобы лучше понять.
Аналогично прокси-классы делаются и для коллекций.
Я еще напомню, что Доктрина это Data Mapper - она пытается создавать видимость, что все твои классы находятся в памяти и скрывает факт, что на самом деле данные загружаются и объект создаются по мере надобности. И что она не требует твои классы знать о ней и о базе данных - ты можешь вообще убрать БД, создавать объекты руками и твой код с ними будет так же работать, как с загруженными из БД.
Для полей еще надо прописывать nullable=true/false. Если есть значения по умолчани, их надо прописать тоже.
https://github.com/TheSidSpears/TestHub/blob/master/web/config.php
Вот кстати это стоит ли оставлять?
Насчет роутов - я бы советовал использовать конфиг, а не аннотации, так как в конфиге они ве собраны в одном месте, удобнее.
>>961306
> Если я использую Pimple и PSR-4 могу я загрузить этот класс через них?
Да, если ты ставил доктрину через композер, то скорее всего ее автозагрузчик уже подключен где-то в vendor/autoload.php, а код в статье для тех, кто хочет подключить его вручную.
Сама по себе программа управления миграциями сделана как набор команд с использованием Symfony Console, потому надо настроить компонент Symfony Console Application (который скорее всего устанавливается вместе с доктриной).
То есть ты создаешь файл, например cli/migration.php, и в нем подключаешь свой бутстрап, настраиваешь Symfony Console Application, добавляешь в него классы-команды доктрины, настраиваешь доступ доктрине к БД. И когда все настроено, запускаешь этот Symfony Console Application, он анализирует командную строку и парамтеры и вызывает нужную команду.
В общем, я советую глянуть на описание Symfony Console, это библиотечка для создания консольных команд: http://symfony.com/doc/current/components/console.html
Там есть такой код:
> $application = new Application();
> // ... register commands
> $application->run();
Вот его и надо поместить в твой файл.
Не перепутай компонент Symfony Console (который не зависит от фреймворка Симфони) и бандл FrameworkBundle, который является частью Симфони.
Также еще есть вариант просто использовать готовый phar файл, но думаю, написать и настроить файл самому будет интереснее.
> $container['Migrations'] = function () {
> return new Migrations();
Это не нужно делать, я думаю.
Также, вполне возможно что эти команды миграции уже подключены в скрипт доктрины bin/doctrine и можно просто вызывать его, возможно, что нет. Можно проверить, запустив bin/doctrine и выведя список доступных команд.
> -configuration это опция чего? Через doctrine:migrations -configuration ошибка о несуществующей команде.
Это опция, указываемая, при вызове какой-либо из команд миграции. Если ты изучишь Symfony Console, то увидишь что там есть опции для вывода списка доступных команд, а также вывод списка опций для любой команды.
> Class 'DOMDocument' not found
наверно расширение dom не установлено для PHP.
> $regexp = '/ + /u';
Тут можно обойтись без дублирования пробелов, например так: {2,}
> //проверяем, чтобы первый символ был не пробелом{
Тут может trim() проще использовать?
> $other = mb_substr($text, $second);
> $first = mb_strtoupper($first);
> $text = $first . $other;
Это можно записать в одну строку без лишних переменных.
Так в общем верно, но закомментированиые куски кода стоит убрать.
>>961149
Доктрина использует прокси-классы для ленивой загрузки. Ну допустим у тебя в классе Тест есть поле Автор. По идее, когда ты загружаешь из БД один Тест, доктрина должна загрузить и создать объект Автора. Если у Автора есть другие связи, она и их должна заполнить. Так мы скоро придем к тому, что надо половину базы данных в память загрузить.
А не загрузить - нельзя, так как иначе непонятно, как получить автора теста.
Потому Доктрина использует прокси-классы. Прокси-класс наследуется от сущности (чтобы проходить все тайп-хинты) и генерируется автоматически. Для каждого метода в исходном классе генерируется метод-обертка. Эти классы кладутся по моему во временную папку, которая задается в конфиге Доктрины.
Вместо реального Автора доктрина вставляет объект-прокси. У этого объектавсе поля пустые, кроме id, и при вызове любого метода, кроме getId() (например getName()), сначала запускается загрузка данных из базы, эти данные загружаются в поля объекта, и только после этого вызывается исходный метод. И таким образом, получается "ленивая" загрузка, прозрачно для твоего кода.
Это объясняет ограничения, которые доктрина накладывает на классы - например, запрет использовать публичные поля, так как обращение к ним невозможно перехватить в классе-наследнике.
Можешь попробовать сам написать пример прокси-класса, чтобы лучше понять.
Аналогично прокси-классы делаются и для коллекций.
Я еще напомню, что Доктрина это Data Mapper - она пытается создавать видимость, что все твои классы находятся в памяти и скрывает факт, что на самом деле данные загружаются и объект создаются по мере надобности. И что она не требует твои классы знать о ней и о базе данных - ты можешь вообще убрать БД, создавать объекты руками и твой код с ними будет так же работать, как с загруженными из БД.
Для полей еще надо прописывать nullable=true/false. Если есть значения по умолчани, их надо прописать тоже.
https://github.com/TheSidSpears/TestHub/blob/master/web/config.php
Вот кстати это стоит ли оставлять?
Насчет роутов - я бы советовал использовать конфиг, а не аннотации, так как в конфиге они ве собраны в одном месте, удобнее.
>>961306
> Если я использую Pimple и PSR-4 могу я загрузить этот класс через них?
Да, если ты ставил доктрину через композер, то скорее всего ее автозагрузчик уже подключен где-то в vendor/autoload.php, а код в статье для тех, кто хочет подключить его вручную.
Сама по себе программа управления миграциями сделана как набор команд с использованием Symfony Console, потому надо настроить компонент Symfony Console Application (который скорее всего устанавливается вместе с доктриной).
То есть ты создаешь файл, например cli/migration.php, и в нем подключаешь свой бутстрап, настраиваешь Symfony Console Application, добавляешь в него классы-команды доктрины, настраиваешь доступ доктрине к БД. И когда все настроено, запускаешь этот Symfony Console Application, он анализирует командную строку и парамтеры и вызывает нужную команду.
В общем, я советую глянуть на описание Symfony Console, это библиотечка для создания консольных команд: http://symfony.com/doc/current/components/console.html
Там есть такой код:
> $application = new Application();
> // ... register commands
> $application->run();
Вот его и надо поместить в твой файл.
Не перепутай компонент Symfony Console (который не зависит от фреймворка Симфони) и бандл FrameworkBundle, который является частью Симфони.
Также еще есть вариант просто использовать готовый phar файл, но думаю, написать и настроить файл самому будет интереснее.
> $container['Migrations'] = function () {
> return new Migrations();
Это не нужно делать, я думаю.
Также, вполне возможно что эти команды миграции уже подключены в скрипт доктрины bin/doctrine и можно просто вызывать его, возможно, что нет. Можно проверить, запустив bin/doctrine и выведя список доступных команд.
> -configuration это опция чего? Через doctrine:migrations -configuration ошибка о несуществующей команде.
Это опция, указываемая, при вызове какой-либо из команд миграции. Если ты изучишь Symfony Console, то увидишь что там есть опции для вывода списка доступных команд, а также вывод списка опций для любой команды.
> Class 'DOMDocument' not found
наверно расширение dom не установлено для PHP.
Все правильно
>>961478
Сделай stat /opt/lampp/... и посмотри владельцев и права доступа. Затем сделай id и посмотри свой id пользователя. Учти что веб-сервер как правило работает от отдельного пользователя вроде www-data.
>>961553
> Долго ломал голову и исписал не один лист в длинющих таблицах из декартовых произведений.
Зато теперь наверно гораздо лучше умеешь делать джойны. Теперь решение более-менее оптимальное.
По поводу задачи про лайки - это строго говоря случай наследования таблиц, и тут есть 3 паттерна, которые легко гуглятся:
Concrete Table Inheritable
Class Table Inheritance
Single Table Inheritance
Вот из них и стоит выбирать.
Идея с entity_type/entity_id - на мой взгляд плохая, так как не позволяет ставить внешние ключи. Хотя тоже в каких-то случаях имеет право на жизнь.
> с использованием таблицы 'всё_что_можно_лайкнуть'
Промежуточная таблица выглядит как лишнее звено. Например, где гарантия что пользователь и фото не будут ссылаться на один и тот же likeable id? Наверно, тогда проще было сделать likeable_id первичным ключом в таблицах пользователей, фоток и тд.
Ты пытаешься унаследовать от общего предка таблицы пользователей, фото (у которых ничего общего), но есть другой вариант - наследовать таблицы лайков, сделав разные виды лайков. И к ним применить по очереди 3 паттерна выше.
> все лайкабельные сущности в одну таблицу:
Ну вот это как раз получилось применение паттерна Single TI к таблицам лайков.
> - Для каждой новой сущности нужно добавлять новый столбец в таблице likes, нужно не забыть добавить уникальный ключ.
Это как раз не проблема, проблема в том что можно по ошибке один лайк отнести к 2 сущностям. В БД вроде Postgres от этого можно защититься, добавив на таблицу ограничение CHECK:
ALTE TABLE ADD CONSTRAINT only_one_reference CHECK (like_to_user IS NOT NULL) + (like_to_photo IS NOT NULL) + ... = 1
- https://postgrespro.ru/docs/postgrespro/9.5/sql-createtable
- https://en.wikipedia.org/wiki/Check_constraint
Попробуй еще посмотреть другие паттерны наследования, может там есть смысл.
>>961558
>>961591
Внешние ключи не поставить, плохо.
>>961633
А это уже применение паттерна Concrete TI
>>962112
Их удаляют кроном раз в полчаса по дате модификации обычно. Можешь конечно попробовать не сохранять пустые сессии, в PHP можно сделать свой обработчик сессий, но может лучше использовать нормальное хранилище вроде БД?
Все правильно
>>961478
Сделай stat /opt/lampp/... и посмотри владельцев и права доступа. Затем сделай id и посмотри свой id пользователя. Учти что веб-сервер как правило работает от отдельного пользователя вроде www-data.
>>961553
> Долго ломал голову и исписал не один лист в длинющих таблицах из декартовых произведений.
Зато теперь наверно гораздо лучше умеешь делать джойны. Теперь решение более-менее оптимальное.
По поводу задачи про лайки - это строго говоря случай наследования таблиц, и тут есть 3 паттерна, которые легко гуглятся:
Concrete Table Inheritable
Class Table Inheritance
Single Table Inheritance
Вот из них и стоит выбирать.
Идея с entity_type/entity_id - на мой взгляд плохая, так как не позволяет ставить внешние ключи. Хотя тоже в каких-то случаях имеет право на жизнь.
> с использованием таблицы 'всё_что_можно_лайкнуть'
Промежуточная таблица выглядит как лишнее звено. Например, где гарантия что пользователь и фото не будут ссылаться на один и тот же likeable id? Наверно, тогда проще было сделать likeable_id первичным ключом в таблицах пользователей, фоток и тд.
Ты пытаешься унаследовать от общего предка таблицы пользователей, фото (у которых ничего общего), но есть другой вариант - наследовать таблицы лайков, сделав разные виды лайков. И к ним применить по очереди 3 паттерна выше.
> все лайкабельные сущности в одну таблицу:
Ну вот это как раз получилось применение паттерна Single TI к таблицам лайков.
> - Для каждой новой сущности нужно добавлять новый столбец в таблице likes, нужно не забыть добавить уникальный ключ.
Это как раз не проблема, проблема в том что можно по ошибке один лайк отнести к 2 сущностям. В БД вроде Postgres от этого можно защититься, добавив на таблицу ограничение CHECK:
ALTE TABLE ADD CONSTRAINT only_one_reference CHECK (like_to_user IS NOT NULL) + (like_to_photo IS NOT NULL) + ... = 1
- https://postgrespro.ru/docs/postgrespro/9.5/sql-createtable
- https://en.wikipedia.org/wiki/Check_constraint
Попробуй еще посмотреть другие паттерны наследования, может там есть смысл.
>>961558
>>961591
Внешние ключи не поставить, плохо.
>>961633
А это уже применение паттерна Concrete TI
>>962112
Их удаляют кроном раз в полчаса по дате модификации обычно. Можешь конечно попробовать не сохранять пустые сессии, в PHP можно сделать свой обработчик сессий, но может лучше использовать нормальное хранилище вроде БД?
>А где таблица юзеров?
Я только начал, мне просто было нужно знать по архитектуре, чтобы меньше исправлять на последних этапах
Slim Framework.
Спасибо, понял насчет контейнера. Наверное остановлюсь на первом, так выглядит проще всего. Не пойму только одного, я вот загуглил PSR-11 - так вот, раз он ест и в фреймворках реализован, почему разработчики IDE не сделают эти фишки автоматическими? Ну что бы они понимали интерфейс и без лишней мороки дополняли код.
PSR-11 не предлагает способа для описания самих сервисов, он только определяет интерфейс для контейнера (с 2 методами get и ha).
Ну так а почему бы не дополнить его по принципу как я описал? Алсо, собираюсь тогда уже сделать обертку для контейнера с методами типа getTwig(), как его следует назвать? ContainerWrapper сойдет?
>А ты решал предыдущие задачи на ООП, про тесты и вопросы и тд?
Одну решил, во второй там с уловиями проблемы, пришлось скипнуть меня уже отругали, сразу взялся на вектор, в итоге убил 8 часов, но задачу не решил.
Спасибо ОП. На выходных добью вектор.
Доработал цикл, с учётом твоих замечаний, и сделал задачку по подсчету кредита в нескольких банках. ОП или просто шарящий анон, посмотрите решение и дайте советов мудрых. Спасибо.
http://ideone.com/4iXPBW
Все даже новички решают первую задачу про тесты, затем вторую, а ты как этот...
Какое у тебя будет понимание после этого?
$creditSum=39999; //сумма кредита
$payment=5000; //ежемесячная выплата
$mon=0; // кол-во месяцев (по умолчанию - 0)
$homoCreditDownPayment=0; //первый взнос в HomоCredit
$softBankDownPayment=0; //первый взнос в SoftBank
$strawberryBankDownPayment=7777; //первый взнос в StrawberryBank
$homoCreditPersent=1.04; //процент в HomоCredit
$softBankPersent=1.03; //процент в SoftBank
$strawberryBankPersent=1.02; //процент в StrawBerry bank
$homoCreditService=500; // плата за сервис в HomoCredit
$softBankService=1000; // плата за сервис в SoftBank
$strawberryBankService=0; // плата за сервис в StrawberryBank
//Пиздец. Я - индус.
$homoCreditTotal=countCredit($creditSum, $homoCreditPersent, $homoCreditService, $payment, $homoCreditDownPayment, $mon, $bankName="HomoCredit");
$softBankTotal=countCredit($creditSum, $softBankPersent, $softBankService, $payment, $softBankDownPayment, $mon, $bankName="SoftBank");
$strawBankTotal=countCredit($creditSum, $strawberryBankPersent, $strawberryBankService, $payment, $strawberryBankDownPayment, $mon, $bankName="StrawbrerryBank");
I LOLED
Короче, суть скобок у функций, в которые передаются аргументы, в том, чтобы вот так не инициализировать разные переменные - достаточно прямо в скобках у функции на месте заявленных при создании самой функции элементов указать значения.
НЕ
>$homoCreditTotal=countCredit($creditSum, $homoCreditPersent, $homoCreditService, $payment, $homoCreditDownPayment, $mon, $bankName="HomoCredit");
А
>$homoCreditTotal=countCredit($creditSum, 1.03, 500, $payment, 0, $mon, $bankName="HomoCredit");
Тогда инициализировать ничего не придётся, городить лишнего.
А так всё верно у тебя считает.
>$bankName="HomoCredit"
*просто "HomoCredit"
Те, которые повторяются, можно ставить переменными, а индивидуальные значения лучше прямо значениями и вставлять.
Блядь, а я ведь сначала так и делал, как ты говоришь, но потом меня что-то понесло. Спасибо, анон.
Ты учишь плохому, а именно магическим константам: https://ru.wikipedia.org/wiki/Магическое_число_(программирование)
Нет ничего "лишнего" в инициализации переменных.
>>964331
Ещё прочитай своё второе условие: "если x меньше 50 и x больше 60". Ты можешь сказать, что это за число, которое меньше 50 и больше 60?
>>964148
> Ну так а почему бы не дополнить его по принципу как я описал?
Ты предлагаешь добавить в PSR-11 интерфейс метод getTwig? PSR-11 нужен для того, чтобы привести разные DI-контейнеры (например Pimple, PHP-DI) к единому интерфейсу: get(), has(). Чтобы не было такого, что где-то getService, а где-то register(). Это позволяет проекту, использующему PSR-11 контейнер, не зависеть от какой-то конкретной реализации. Автодополнение в IDE здесь вообще не при делах.
Нда, понял, спасибо.
>>964337
Стоп, я исправил второе условие, но не исправлял б на д и код все равно выполнялся. Это как ?
{{ Form::select('category', $categories_list) }}
на html форму?
$categories_list = Category::pluck('category_name', 'id');
Накидал сам, но не знаю будет ли правильно
<select name="category">
@foreach
<option value="{{$categories_list->'id'"{{ $categories_list->'category_name'"</option>
@endforeach
>тут бы ENUM подошел лучше
Не люблю использовать ENUM, он не гибкий, тем более если у меня изначально уже не планируется статус 0 и 1, а сразу идет как минимум 3 статуса - нет гарантии, что в процессе не появится 4 или 5 статусов сверху. То-есть я исходил из логики - если я не могу наперед просчитать все подводные камни - то зачем сразу себе ограничения создавать на будущее.
http://komlenic.com/244/8-reasons-why-mysqls-enum-data-type-is-evil/
https://habrahabr.ru/post/76356/
> Весь функционал приложения содержится в модели. Контроллер и вью предоставляют лишь возможность пользователю взаимодействовать с моделью и отображать данные из нее.
Почему? По логике весь функционал должен выполняться в контроллере, а модель должна отвечать только за работу с базой данных.
> maximum-scale=1.0, minimum-scale=1.0">
> Зачем так делать? Ты издеваешься над пользователями что ли?
Я воспользовался стандартным кодом HTML-страницы из phpstorm emmet'a по !!+tab
>Это неудобно, лучше сделать автоматическое определение текущей папки.
Почему не удобно? Практически во всех CMS используются предопределенные константы текущего местоположения проекта.
> автоматическое определение текущей папки.
Я указал путь не на папку проекта, а на корневой каталог для файлов загруженных пользователями.
>Есть какие-то веские причины почему тут запрещено наследование?
Что может унаследоваться от класса который работает со структурой директорий? Не хочу чтобы плодились унаследованные классы, DIR вполне может выполнять любую работу с папками.
>Между контроллерами и моделями нет соответствия один-к-одному. Плюс твой метод подразумевает
Во многих CMS можно в один контроллер подключить сколько угодно моделей, в опенкарте как правило контроллеру соответствует модель
>Непонимание MVC
Скорее извращенное понимание после долгой работы с CMS'ками сомнительного качества. Я поэтому и снова тут, надоело ковыряться в CMS'ках.
Спасибо ОП, что посмотрел. Надеюсь за выходные успею всё поправил и допилить функционал
На HTML-CSS не обращай внимания, только на twig, если не трудно, так как не работал ранее с шаблонизаторами
>тут бы ENUM подошел лучше
Не люблю использовать ENUM, он не гибкий, тем более если у меня изначально уже не планируется статус 0 и 1, а сразу идет как минимум 3 статуса - нет гарантии, что в процессе не появится 4 или 5 статусов сверху. То-есть я исходил из логики - если я не могу наперед просчитать все подводные камни - то зачем сразу себе ограничения создавать на будущее.
http://komlenic.com/244/8-reasons-why-mysqls-enum-data-type-is-evil/
https://habrahabr.ru/post/76356/
> Весь функционал приложения содержится в модели. Контроллер и вью предоставляют лишь возможность пользователю взаимодействовать с моделью и отображать данные из нее.
Почему? По логике весь функционал должен выполняться в контроллере, а модель должна отвечать только за работу с базой данных.
> maximum-scale=1.0, minimum-scale=1.0">
> Зачем так делать? Ты издеваешься над пользователями что ли?
Я воспользовался стандартным кодом HTML-страницы из phpstorm emmet'a по !!+tab
>Это неудобно, лучше сделать автоматическое определение текущей папки.
Почему не удобно? Практически во всех CMS используются предопределенные константы текущего местоположения проекта.
> автоматическое определение текущей папки.
Я указал путь не на папку проекта, а на корневой каталог для файлов загруженных пользователями.
>Есть какие-то веские причины почему тут запрещено наследование?
Что может унаследоваться от класса который работает со структурой директорий? Не хочу чтобы плодились унаследованные классы, DIR вполне может выполнять любую работу с папками.
>Между контроллерами и моделями нет соответствия один-к-одному. Плюс твой метод подразумевает
Во многих CMS можно в один контроллер подключить сколько угодно моделей, в опенкарте как правило контроллеру соответствует модель
>Непонимание MVC
Скорее извращенное понимание после долгой работы с CMS'ками сомнительного качества. Я поэтому и снова тут, надоело ковыряться в CMS'ках.
Спасибо ОП, что посмотрел. Надеюсь за выходные успею всё поправил и допилить функционал
На HTML-CSS не обращай внимания, только на twig, если не трудно, так как не работал ранее с шаблонизаторами
Вот такое получилось на PHP:
https://ideone.com/A2Dwu0
Не всегда выводит одинаковые ключи. Пока не могу понять, почему.
Алсо, комп очень долго думает над этим всем, нагревается и жужжит, мне его жалко.
Ебанутый двач, почему сажа-то?
Речь о той, что из цикла "Head First", нувыпоняли
Дан массив с числами, например: $numbers = [1, 3, 4, 2, 7, 12];
Напишите функцию isNumberAfter($numbers, $first, $second), которая возвращает true, если в массиве есть число $second правее числа $first, и false в противном случае.
Например:
isNumberAfter($numbers, 1, 7) // true
isNumberAfter($numbers, 3, 1) // false
isNumberAfter($numbers, 1, 100) // false
isNumberAfter($numbers, 1, 1) // false
По-моему всё в порядке. Там же не написано "$second должен идти cразу за $first", там написано "правее".
https://3v4l.org/2S3rK
это называется offset/step
>Ты предлагаешь добавить в PSR-11 интерфейс метод getTwig?
Я выразился хуево. Скорее имел ввиду, почему разработчики IDE не запилят такую хуйню, мол если класс с интерфейсом PSR-11 возвращает из массива объект то делать автодополнение.
Чтобы делать автодополнение, надо как-то узнать имена сервисов и соответствующие им классы. В разных контейнерах это делается по разному,в Pimple вообще это так просто не определить, так как это явно не описано нигде. Там ведь функция, она может вернуть что угодно, пока не запустишь - не поймешь.
Кстати, почитал про PHP-DI и его интеграцию со Slim'ом: https://github.com/PHP-DI/Slim-Bridge#service-injection
То есть можно внедрять сервисы сразу в экшн, в IDE будет работать автодополнение, можешь попробовать. Недостаток такого подхода - нужно для каждого экшена указывать все зависимости.
Ещё в PHP-DI есть автоматическое связывание зависимостей по тайп-хинтам (подробнее - у ОПа в пасте про DI: https://github.com/codedokode/pasta/blob/master/arch/di.md )
>Экшен - это действие, сервис - объек который делает что-то.
Если исходить из этой логики, то сервис это оператор экшинов
Правильное решение, но ты наверно не очень и начинающий.
>>964693
Да, такое и в ZF2 я видел раньше, тут есть подвох: теории у тебя может быть несколько сервисов одного класса, но с разными настройками. Распознается ли это?
И еще интереснее ситуация, ты сделал внедрение через тайп-хинты, а завтра кто-то добавил второй сервис твига.
>>964737
action это controller
service это часть модели
Ты можешь посмотреть например мой урок по MVC для начала https://github.com/codedokode/pasta/blob/master/arch/mvc.md
Может test_id?
Возможно, там очень много данных выводится. Сделай свою функцию для дампа сущностей, которая например пишет класс и основные свойства вроде id, name, ну или поищи, может в симфони есть готовый дампер. Там было что-то такое.
Скорее наоборот. Например actionIndex - метод который собирает данные и передает их во вьху. А сервисы - это разные классы которые делают операции над данными, ну там типа валидации, пагинации и т.п. Ну я это так понимаю по крайней мере.
В середине Getting Started (!) написано не использовать var_dump для сущностей: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/tutorials/getting-started.html
> Lazy load proxies always contain an instance of Doctrine’s EntityManager and all its dependencies. Therefore a var_dump() will possibly dump a very large recursive structure which is impossible to render and read.
И далее авторы предлагают использовать специальный Dump из доктрины.
https://pastebin.com/y4tDiMZQ
Пробовал, <exec executable="php bin/console doctrine:database:create"/>
тоже не работает. Просто виснет и никакого вывода в консоль.
Руками все естественно работает.
Давай готовое, я уже повтыкал в документацию. А что, ты сейчас напишешь больше двух строчек?
А зачем передавать то что-то? Ты как-то странно делаешь. Я сделал обычный контейнер, который сам передается в контроллер.
UPD:А на пике твоем творится какой-то пиздец .
https://www.slimframework.com/docs/objects/router.html#container-resolution
Вот в мануале описывается то, что я хочу сделать. Только не понятно как зароутить контроллер в контейнере.
А можешь в конструктор передать сразу контейнер, а у же в самом классе вызывать экземпляры контейнера, вместо того, чтобы все эти экземпляры по отдельности тащить.
Ну, блять, все правильно DI и контейнеры это разные вещи, которые друг о друге не знают.
Ты сначала доки почитай.
Ты явно не туда свернул. Я аналогично исползую DI:
$container = new ContainerWrapper($config);
$container['twig'] = function() {
$loader = new \Twig_Loader_Filesystem('../app/Templates/');
$twig = new Twig_Environment($loader);
return $twig;
};
$app = new \Slim\App($container);
$app->get('/', \Controllers\IndexController::class . ':index');
Только там у меня еще обертка для контейнера, ну что бы phpdoc использовать.
Помогите разобраться почему не работает скрипт с кириллицей.
mb_internal_encoding("utf-8"); в начале прописал и функции нужные для кириллицы использовал. С английским текстом работает как нужно.
http://ideone.com/fork/g8wDBZ
Спроси в ларавель треде.
http://phpclub.rf.gd/pr/res/945059.html#955506
>Задача про addMethod и super
>>> Что-то у меня не получилось понять подвоха этой задачи: https://jsfiddle.net/zmLjh7ur/
>>> Более того, я не смог понять как работает функция super(): https://jsfiddle.net/b073aLb5/1/
>> В чем моя ошибка? Здесь же должна быть такая же ситуация, super должен искать метод в прототипе.
>Подвох в том, что функции super() в JS нету, и в задаче требуется ее сделать.
Но она же описана в документации: https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Operators/super
Допустим нету т.к. она действительно не работает, тогда нужно написать свою функцию mySuper(). Как ей привязать this в контексте объекта в котором она была вызвана не передавая ей никаких знаний об этом объекте?
С остальными подвохами нужно разобраться после этого...
>Задача про гамбургер
>> if (size == Hamburger.SIZE_SMALL || size == Hamburger.SIZE_LARGE) {
>> } else if (size === undefined) {
>> } else if (size != Hamburger.SIZE_SMALL || size != Hamburger.SIZE_LARGE) {
>В третьем случае лучше просто написать else. Также, можно убрать второй случай.
>Также, может быть стоит хранить где-то список допустимых значений отдельно, чтобы было легко его править.
Добавил список допустимых значений и исправил условие: https://jsfiddle.net/y28h2o2b/6/
>> определил this.menu
>Странно, я в коде не вижу this.menu = {}; Наверно это было в другой версии кода.
Да, я нечаянно скинул не ту. Это было в 4 версии. Сейчас всё на месте.
>В остальном выглядит верно.
>Электросеть
https://jsfiddle.net/6591a2sL/6/
>> А почему ЛЭП не может спросить сколько энергии нужно?
>Она может, но получается как минимум 2 проблемы:
>- ЛЭП надо будет дать ссылку на Сеть, в то время как c другими элементами у нас односторонняя связь: у Сети есть ссылка на Элемент, а у Элемента на Сеть - нет. Такая односторонняя связь удобнее, ее проще поддерживать и лучше видно кто кем управляет
>- будет запутанная цепочка вызовов: Сеть опрашивает Элементы, сколько они генерируют, а ЛЭП в свою очередь опрашивает Сеть, какой получился баланс (а ей для этого надо опять опрашивать Элементы). Запутанное отношение, и тут легко даже сделать бесконечную рекурсию.
>Потому удобнее сделать расчет, сколько мы закупаем/продаем энергии, в Сети, а ЛЭП эти цифры не давать, зачем они ей.
Если что, я не согласен с вашим замечанием - потому что мне не нужно было давать ссылку на Сеть, только передать уже посчитанный баланс. Можно было считать Сеть за контроллер, а ЛЭП за модель которая содержит вспомогательные методы расчета. А теперь в эти методы нужно передавать ссылку на ЛЭП. Мне из-за этого кажется что я понял и сделал всё ещё более худшим образом.
>>> PowerLine.prototype.countPower = function(power) {
>>> var thispower = this.power;
>>>
>>> for (var i = 0; i < thispower; thispower--) {
>>> if (power == 0) {
>>> break;
>>> }
>>>
>>> power += power / -Math.abs(power);
>>>что-то я не могу толком понять, что тут происходит. Зачем мы power делим саму на себя? Получится ведь либо 1, либо -1. Тут явно ошибка.
>>Наверно я сбил столку неправильно назвав функцию - эта функция считает сколько энергии останется после передачи\получения её через конкретную ЛЭП.
>>power мы делим саму на себя чтобы узнать прибавлять или отнимать энергию каждый раз, чтобы достичь баланса, т.е. узнать обратный знак своего значения. То есть, мы каждый раз либо прибавляем или отнимаем по одному, до тех пор пока значение не станет нулём.
>Вместо вычитания в цикле надо использовать деление или умножение и функции min()/max().
Как определение максимального или минимального значения поможет определить сколько энергии останется после передачи её через ЛЭП? И определение максимального\минимального значения чего нужно сделать?
>> price += powerlines.countPrice(balance);
>> balance = powerlines.countPower(balance);
>Здесь идея правильная, но код не очень логчный. Мы сначала спрашиваем сколько стоит передача энергии, а только потом - сколько можно передать. Логичнее сделать наоборот, узнать, сколько можно передать, а потом - сколько это стоит.
А здесь считается не сколько можно передать а сколько останется энергии после передачи через конкретную ЛЭП. То есть сначала мы считаем цену за то количество которое мы может передать а затем высчитываем оставшиеся количество энергии.
>Ну и функции стоило назвать логичнее. Не countPower(), а например getTransferredPower()
Переименовал функцию для наглядности
> хотя мне кажется что сделать тут min(balance, line.getThroughput()) было бы нагляднее.
А я не сразу догадался что это делает. Можно было и так сделать, но у меня уже сделано по своему. Можно я не буду эту менять? Придётся заново переосмысливать мою программу.
http://phpclub.rf.gd/pr/res/945059.html#955507
>Определение типа переменной
https://jsfiddle.net/5q3r473h/4/
Ещё был совет сделать хэш за место свича, но для Array-like пришлось бы делать сложное условие внутри этого хэша. Чем плох свич, если его функционал подходит для этой задачи?
>Напиши функцию неглубокого копирования объектов и массивов
https://jsfiddle.net/uyey3at1/5/
>>>Тут в коде, я вижу, есть поддержка копирования объектов Date и обычных объектов, а что с массивами? Для них ведь надо изначально создавать пустой массив и копировать элементы.
>> А других встроенных объектов это замечание касается?
>Да, если надо копировать встроенные объекты, то для каждого придется писать свою логику. Один способ для Regexp, другой для Function, и так далее.
Встроенных объектов довольно много. Мне действительно следует прям для каждого-каждого объекта писать логику? Включая примитивные значения, которые на самом деле тоже объекты?
>Встроенные объекты могут иметь скрытые свойства и просто циклом их копировать нельзя.
А как узнать про эти свойства? У меня не получилось ничего найти про них.
>Глубокое копирование
https://jsfiddle.net/b0a7tk75/2/
http://phpclub.rf.gd/pr/res/945059.html#955506
>Задача про addMethod и super
>>> Что-то у меня не получилось понять подвоха этой задачи: https://jsfiddle.net/zmLjh7ur/
>>> Более того, я не смог понять как работает функция super(): https://jsfiddle.net/b073aLb5/1/
>> В чем моя ошибка? Здесь же должна быть такая же ситуация, super должен искать метод в прототипе.
>Подвох в том, что функции super() в JS нету, и в задаче требуется ее сделать.
Но она же описана в документации: https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Operators/super
Допустим нету т.к. она действительно не работает, тогда нужно написать свою функцию mySuper(). Как ей привязать this в контексте объекта в котором она была вызвана не передавая ей никаких знаний об этом объекте?
С остальными подвохами нужно разобраться после этого...
>Задача про гамбургер
>> if (size == Hamburger.SIZE_SMALL || size == Hamburger.SIZE_LARGE) {
>> } else if (size === undefined) {
>> } else if (size != Hamburger.SIZE_SMALL || size != Hamburger.SIZE_LARGE) {
>В третьем случае лучше просто написать else. Также, можно убрать второй случай.
>Также, может быть стоит хранить где-то список допустимых значений отдельно, чтобы было легко его править.
Добавил список допустимых значений и исправил условие: https://jsfiddle.net/y28h2o2b/6/
>> определил this.menu
>Странно, я в коде не вижу this.menu = {}; Наверно это было в другой версии кода.
Да, я нечаянно скинул не ту. Это было в 4 версии. Сейчас всё на месте.
>В остальном выглядит верно.
>Электросеть
https://jsfiddle.net/6591a2sL/6/
>> А почему ЛЭП не может спросить сколько энергии нужно?
>Она может, но получается как минимум 2 проблемы:
>- ЛЭП надо будет дать ссылку на Сеть, в то время как c другими элементами у нас односторонняя связь: у Сети есть ссылка на Элемент, а у Элемента на Сеть - нет. Такая односторонняя связь удобнее, ее проще поддерживать и лучше видно кто кем управляет
>- будет запутанная цепочка вызовов: Сеть опрашивает Элементы, сколько они генерируют, а ЛЭП в свою очередь опрашивает Сеть, какой получился баланс (а ей для этого надо опять опрашивать Элементы). Запутанное отношение, и тут легко даже сделать бесконечную рекурсию.
>Потому удобнее сделать расчет, сколько мы закупаем/продаем энергии, в Сети, а ЛЭП эти цифры не давать, зачем они ей.
Если что, я не согласен с вашим замечанием - потому что мне не нужно было давать ссылку на Сеть, только передать уже посчитанный баланс. Можно было считать Сеть за контроллер, а ЛЭП за модель которая содержит вспомогательные методы расчета. А теперь в эти методы нужно передавать ссылку на ЛЭП. Мне из-за этого кажется что я понял и сделал всё ещё более худшим образом.
>>> PowerLine.prototype.countPower = function(power) {
>>> var thispower = this.power;
>>>
>>> for (var i = 0; i < thispower; thispower--) {
>>> if (power == 0) {
>>> break;
>>> }
>>>
>>> power += power / -Math.abs(power);
>>>что-то я не могу толком понять, что тут происходит. Зачем мы power делим саму на себя? Получится ведь либо 1, либо -1. Тут явно ошибка.
>>Наверно я сбил столку неправильно назвав функцию - эта функция считает сколько энергии останется после передачи\получения её через конкретную ЛЭП.
>>power мы делим саму на себя чтобы узнать прибавлять или отнимать энергию каждый раз, чтобы достичь баланса, т.е. узнать обратный знак своего значения. То есть, мы каждый раз либо прибавляем или отнимаем по одному, до тех пор пока значение не станет нулём.
>Вместо вычитания в цикле надо использовать деление или умножение и функции min()/max().
Как определение максимального или минимального значения поможет определить сколько энергии останется после передачи её через ЛЭП? И определение максимального\минимального значения чего нужно сделать?
>> price += powerlines.countPrice(balance);
>> balance = powerlines.countPower(balance);
>Здесь идея правильная, но код не очень логчный. Мы сначала спрашиваем сколько стоит передача энергии, а только потом - сколько можно передать. Логичнее сделать наоборот, узнать, сколько можно передать, а потом - сколько это стоит.
А здесь считается не сколько можно передать а сколько останется энергии после передачи через конкретную ЛЭП. То есть сначала мы считаем цену за то количество которое мы может передать а затем высчитываем оставшиеся количество энергии.
>Ну и функции стоило назвать логичнее. Не countPower(), а например getTransferredPower()
Переименовал функцию для наглядности
> хотя мне кажется что сделать тут min(balance, line.getThroughput()) было бы нагляднее.
А я не сразу догадался что это делает. Можно было и так сделать, но у меня уже сделано по своему. Можно я не буду эту менять? Придётся заново переосмысливать мою программу.
http://phpclub.rf.gd/pr/res/945059.html#955507
>Определение типа переменной
https://jsfiddle.net/5q3r473h/4/
Ещё был совет сделать хэш за место свича, но для Array-like пришлось бы делать сложное условие внутри этого хэша. Чем плох свич, если его функционал подходит для этой задачи?
>Напиши функцию неглубокого копирования объектов и массивов
https://jsfiddle.net/uyey3at1/5/
>>>Тут в коде, я вижу, есть поддержка копирования объектов Date и обычных объектов, а что с массивами? Для них ведь надо изначально создавать пустой массив и копировать элементы.
>> А других встроенных объектов это замечание касается?
>Да, если надо копировать встроенные объекты, то для каждого придется писать свою логику. Один способ для Regexp, другой для Function, и так далее.
Встроенных объектов довольно много. Мне действительно следует прям для каждого-каждого объекта писать логику? Включая примитивные значения, которые на самом деле тоже объекты?
>Встроенные объекты могут иметь скрытые свойства и просто циклом их копировать нельзя.
А как узнать про эти свойства? У меня не получилось ничего найти про них.
>Глубокое копирование
https://jsfiddle.net/b0a7tk75/2/
>> Class 'DOMDocument' not found
>наверно расширение dom не установлено для PHP.
У меня возникала та же самая ошибка после установки этого расширения. Оказалось нужно ещё php-xml было.
Так переменная сначала только ровна нулю.
При первой итерации она становится равна $p, при второй она становится равна $v + $p - и так далее до конца.
Завязывай с такими пидорскими названиями у переменных - непонятно же ни черта.
Пиши так, чтобы можно было посмотреть на любое условие и сразу понять, что означают переменные.
А то я твои А и Б труба шатал!!1
http://php.net/manual/ru/function.mb-substr.php
http://php.net/manual/ru/function.mb-convert-case.php
Посоветуйте форм-билдер самый распространенный, не хочу велосипед изобретать с форм-рендерингом можно ли взять форм-билдер с yii2 ?
https://3v4l.org/Brc10
Но нихуя не вышло. Наследовать Работников от Департамента в корне не верно.
Не посчитано:
>Число страниц документов и отчетов, которые производят все департаменты в сумме.
>Средний расход тугриков на одну страницу
Ну и с выводом не стал ебаться.
Браток, у тебя неверный подход. На правах новичка, ковыряющегося с этим несколько недель и сделавшего "Вектор" до антикризисных мер, говорю.
Что это такое - класс Департамент и класс ГруппаРаботников? Это вообще ни к чему.
Какие у нас есть сущности, какие у них есть атрибуты и методы, давай выделим?
1. Работник, у которого есть профессия, есть ранг, на основе которых выявляются потребление кофе и выработка страниц, а также - является или нет боссом, что также влияет на зарплату.
2. Департамент, у которого есть определённое количество работников, нужно иметь возможность считать общую зарплату по департаменту, потребление кофе, выработку страниц.
3. Компания, в которой находятся все департаменты. (С этим я и сам пока не совладал, азаза.)
Чтобы просто всё посчитать хотя бы и не по ООП, нам надо иметь как минимум класс Работник. Дальше ты получишь всех работников по департаментам и можешь всё получить.
Попробуй хотя бы так, дальше лучше поймёшь.
Будь моя воля - я бы вообще всё в одной функции посчитал, но мне уже удалили по рукам и сказали под каждое действие пилить свой метод, что вылилось в тонну кривых методов. В условиях был толстый намёк, что должно быть два класса, - Департамент и Работники, после сказали работников заменить на ГруппаРаботников, что и было сделано. Собственно с этим и работал. Про сущности я так и не понял нихуя. Про наследования стало немного доходить, но тут Группуработников нельзя унаследовать от Департамента.
Ты не шаришь. Не работники, а работник. От этого работника можно наследовать как хочешь, скакой угодно зряплатой и вообще любой должностью. А работники будут собираться у тебя уже в департаменте.
>после сказали работников заменить на ГруппаРаботников
Какой педераст это сказал? Да вырвут ему его гнусный язык!
Наверное, ты не так понял, потому что кому надо советовать ерунду.
>Про сущности я так и не понял нихуя.
Сущность - это краеугольный камень системы. У нас это Работник.
У работника есть свойства - профессия, потребление кофе, выработка страниц, ранг, босс-нет, зарплата. Некоторые свойства вычисляются из других (по профессии - кофе и страницы, по рангу и боссу - зарплата).
У работника должны быть методы - подсчёт зарплаты исходя из ранга и босс-нет, подсчёт кофе исходя из босс-нет, подсчёт страниц исходя из босс-нет.
Ну а дальше создавай экземпляры и считай в цикле.
Делай!
Но ты же ничего не объяснил. Ты посмотри на мой код, там почти тоже самое, что ты щас сказал, только называется класс по другому, имеет те же свойства, те же методы.
Херась, не объяснил!
С какого перепугу тогда у тебя класс Работник называется ГруппаРаботников?
Я же не говорю тебе, что у тебя код неправильный целиком, я говорю тебе, что подход у тебя неверный. Ты же ни хера не понял сути, если назвал класс ГруппаРаботников. Какая группа, если у тебя там отдельные работники создаются?
У тебя многое есть, просто нужно понять суть.
Судя по всему, ты часть кода скопировал из чьего-то решения, поэтому сути и не догнал.
>Департамент и Работники, после сказали работников заменить на ГруппаРаботников, что и было сделано
>>963590
Да ты охуел, тебе сказали, чтобы Employees поменял на Employee. Ты английского не знаешь? Мне кажется в этом проблема, может задумка была и правильно, но название неправильное и вводит посторонних в заблуждение
Зайчем мы полтреда ебемся с мудаком, который даже самых жырных намеков не понимает?
Вы зациклены на названии. Проблема не в нём.
Вот Оп пояснял, что нужно переименовать.
>Классы называются в единственном числе, не Employees, а EmployeeGroup. Но я бы советовал так не делать, а делать 1 объект = 1 сотрудник, иначе трудно будет например повысить ранг только одному человеку в группе - надо будет переразбивать группу, сложно.
>>964062
Когда было Employees, это скорее упущение, чем грубая, фатальная ошибка из-за которой мой код пошёл по пизде.
Английский тут совершенно не при чём. В общем я жду официального комментария от ОПа, а то некоторые тут уже мудаком обзывают, а просто задаю вопросы, может они тупые и нелепые, но я в первую очередь пишу ОПу, потому что ему не похуй.
на самом деле похуй.
Так он комментил намного выше:
>Да, с группами будет неудобно если тебе надо повысить зарплату одному работнику из группы - код переразбиения групп сложный будет. Проще с отдельными объектами, пусть даже так уйдет чуть больше памяти, но у нас там не миллион работников, чтобы о ней беспокоиться.
>Классы называются в единственном числе, не Employees, а EmployeeGroup
Ох лол, так он ведь просто пример привёл, ну что же ты так всё буквально понимаешь...
Я так тебе и объяснял: не нужен класс ГруппаРаботников, нужен класс Работник.
От этого у тебя и идёт общее непонимание - ты никак не въедешь в тот момент, что оперировать надо отдельными экземплярами-работниками, собирать их в департамент, там всё считать.
От этого весь сумбур у тебя.
>Вы зациклены на названии. Проблема не в нём.
Проблема в том, что ты никак не въедешь, что не может быть класса Департаменты, не может быть класса Работники.
Ты это понимаешь?
Класс - это сущность, она единична. У неё есть свойства и методы.
А у тебя - ГруппаРаботников, у которых сумбур в свойствах и методах, всё свалено в кучу, когда должно быть всё отделено и чётко.
В общем, если
> User: S = (B - kg^x) ^ (a + ux)
степень получается нечетным числом, то токены S получаются разные.
Если степень четная - всё работает.
Вынужден признать поражение.
Ой, я даун. Всё получилось! Спасибо, ОП и другой товарищ, который отвечал.
Приступаю к реализации на JS.
> Но она же описана в документации: https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Operators/super
> Specifications
> ECMAScript 2015 (6th Edition, ECMA-262)
Это только в ES6 стало доступно. Надо своими силами сделать аналог для до-ES6 браузеров.
> Как ей привязать this в контексте объекта в котором она была вызвана не передавая ей никаких знаний об этом объекте?
Дам подсказку: надо при добавлении метода в объект его обернуть в обертку, которая задаст нужные значения.
>>965168
Если что, проверить список расширений можно командой php -m или в phpinfo(). там будет видно, есть DOM или нет.
Всё работает! Было очень весело разбираться в этой теме, хочется теперь ещё чего-нибудь копнуть математическое.
Замечания:
1) серверная половина (PHP) работает заметно медленно (с использованием BC.Math).
2) JavaScript, похоже, не имеет встроенных функций для работы с большими числами, пришлось использовать стороннюю библиотеку (минус), да еще и для шифрования библиотеку (минус), зато обрабатывает почти моментально (плюс). Потыкать бы где сервер с Node.js
3) Python-версия с википедии тоже обрабатывает моментально (говорят, на питоне тоже пишут сайты, но мой хостер дает только PHP).
4) Очень помогли пасты ОП-а про ООП. Нихуя не работало, пока не расчленил код на микрообъекты с методами, только тогда нашел свою ошибку.
5) Что почитать про HTTPS?
> а как-то типа $this->container->методыКонтейнера?
Как раз при вызове $this->get() ты и вызываешь метод контейнера.
Slim привязывает this обработчика роута к контейнеру, поэтому когда ты вызываешь $this->get('service') на самом деле вызывается $container->get('service'). Так что попробуй $this->методКонтейнера, должно заработать. Про привязку контекста написано тут: http://php.net/manual/en/closure.bindto.php , вот пример попроще: https://ideone.com/mTHisT
>>964999
Правильно понимаешь, передача контейнера в качестве аргумента - это Service Locator. То, что ты хочешь, называется Controller as Service. Обычно в этом нет смысла, есть идеи почему?
>>964987
https://github.com/spudro228/my-site/blob/master/src/Core/PostsController.php#L20
Странный код. Контейнер как раз нужен, чтобы возвращать уже проинициализированные объекты и разруливать зависимости именно его задача.
Там древний код скорее всего, написанный по мотивам того, что видели в других CMS того времени. Так да, вот тут например echo встречается: https://github.com/opencart/opencart/blob/master/upload/system/framework.php
И кстати паттерн Registry, упомнянутый в моем уроке по DI, используется.
>>964270
> $mon++;
Это можно 1 раз написать вместо двух.
> $credit=$absoluteCredit-$payment
Это лучше унести из шапки в тело цикла так как переменная absoluteCredit создается ниже и выглядит нелогично, надо при чтении вверх/вних прыгать чтобы разобраться.
> $total+=$absoluteCredit;
> $total+=$payment;
Это бы тоже хорошо объединить в одну строку, например так:
если (кредит большой) {
выплата = ...;
} иначе {
выплата = ...;
}
> $homoCreditDownPayment=0; //первый взнос в HomоCredit
> $softBankDownPayment=0; //первый взнос в SoftBank
> $strawberryBankDownPayment=7777; //первый взнос в StrawberryBank
> $homoCreditPersent=1.04; //процент в HomоCredit
> $softBankPersent=1.03; //процент в SoftBank
> $strawberryBankPersent=1.02; //проц
Так можно писать, но проще было это просто числами при вызове функции указать - смысл этих чисел понятен из названий аргументов функции.
> $bankName="HomoCredit")
Вот так переменную создавать не надо, создание переменной это однодействие, вызов функции - другое, и не надо их в одну строку втискивать. Тут лучше вообще было без переменной обойтись.
> ?>
Не надо ставить этот маркер в конце файла
Ответ получается верный.
>>964331
Второе условие никогда не выполнится, так как там 2 противоречащих подусловия (x не может быть одновременно меньше 50 и больше 60).
>>964390
Это PHP при обращении к несуществующей переменной хоть и выводит ошибку, но не прекращает выполнение программы, а вместо значения переменной возвращает null. Неправильно, кстати, придумано.
>>964458
Я не знаю, надо документацию по их шаблонизатору читать.
Там древний код скорее всего, написанный по мотивам того, что видели в других CMS того времени. Так да, вот тут например echo встречается: https://github.com/opencart/opencart/blob/master/upload/system/framework.php
И кстати паттерн Registry, упомнянутый в моем уроке по DI, используется.
>>964270
> $mon++;
Это можно 1 раз написать вместо двух.
> $credit=$absoluteCredit-$payment
Это лучше унести из шапки в тело цикла так как переменная absoluteCredit создается ниже и выглядит нелогично, надо при чтении вверх/вних прыгать чтобы разобраться.
> $total+=$absoluteCredit;
> $total+=$payment;
Это бы тоже хорошо объединить в одну строку, например так:
если (кредит большой) {
выплата = ...;
} иначе {
выплата = ...;
}
> $homoCreditDownPayment=0; //первый взнос в HomоCredit
> $softBankDownPayment=0; //первый взнос в SoftBank
> $strawberryBankDownPayment=7777; //первый взнос в StrawberryBank
> $homoCreditPersent=1.04; //процент в HomоCredit
> $softBankPersent=1.03; //процент в SoftBank
> $strawberryBankPersent=1.02; //проц
Так можно писать, но проще было это просто числами при вызове функции указать - смысл этих чисел понятен из названий аргументов функции.
> $bankName="HomoCredit")
Вот так переменную создавать не надо, создание переменной это однодействие, вызов функции - другое, и не надо их в одну строку втискивать. Тут лучше вообще было без переменной обойтись.
> ?>
Не надо ставить этот маркер в конце файла
Ответ получается верный.
>>964331
Второе условие никогда не выполнится, так как там 2 противоречащих подусловия (x не может быть одновременно меньше 50 и больше 60).
>>964390
Это PHP при обращении к несуществующей переменной хоть и выводит ошибку, но не прекращает выполнение программы, а вместо значения переменной возвращает null. Неправильно, кстати, придумано.
>>964458
Я не знаю, надо документацию по их шаблонизатору читать.
> Не люблю использовать ENUM, он не гибкий,
Можно потом добавлять новые статусы через ALTER TABLE.
> То-есть я исходил из логики - если я не могу наперед просчитать все подводные камни - то зачем сразу себе ограничения создавать на будущее.
Чтобы защититься от записи неправильных значений. Ну и слова чуть читабельнее чем числа.
> ENUM is evil
Ну так твое решение ничуть не лучше, там предлагается ENUM не на число заменять, а сделать отдельную таблицу статусов и ставить внешний ключ на нее.
> Я воспользовался стандартным кодом HTML-страницы из phpstorm emmet'a по !!+tab
Значит это плохой код. Это запрещает изменение масштаба в мобильной версии. зачем? Они его откуда-то бездумно скопировали, а исходный код скорее всего написал тот, кому лень было отлаживать верстку и он просто запретил масштабирование. На хабре сделано так же, как неудобно.
>>Это неудобно, лучше сделать автоматическое определение текущей папки.
> Почему не удобно? Практически во всех CMS используются предопределенные константы текущего местоположения проекта.
Потому что это можно определять автоматически. Зачем заставлять пользователя что-то вводить? Позор разработчикам таких CMS.
> Я указал путь не на папку проекта, а на корневой каталог для файлов загруженных пользователями.
Тогда можно сделать по умолчанию определение автоматически, а при необходимости переопределение в конфиге. Но если ты меняешь папку, скорее всего поменяется и URL, под которым она видна, ты это учел?
>>Есть какие-то веские причины почему тут запрещено наследование?
> Что может унаследоваться от класса который работает со структурой директорий? Не хочу чтобы плодились унаследованные классы, DIR вполне может выполнять любую работу с папками.
В этом и суть наследования, что ты заранее не знаешь, как твой класс будет унаследован. Вдруг кто-то например захочет логгировать все действия с папками или какие-нибудь проверки добавить. Для добавления final должна быть веская причина, например, какой-то критичный код, изменение которого сломает программу. И его тогда лучше на метод ставить, а не на весь класс.
Обычно нигде final не ставят, потому когда ты его ставишь, появляется вопрос, а зачем, и каких-то веских причин запрещать наследование я пока не вижу.
Если что, еще есть принцип что классы должны быть открыты для расширения, но закрыты для модификации (open/closed principle).
>>Между контроллерами и моделями нет соответствия один-к-одному. Плюс твой метод подразумевает
> Во многих CMS можно в один контроллер подключить сколько угодно моделей, в опенкарте как правило контроллеру соответствует модель
Это не стоит копировать. Это какая-то ошибка в опенкарте. Или это не совсем модель, а какой-то помощник для контроллера.
Если ты читал мой урок по MVC: https://github.com/codedokode/pasta/blob/master/arch/mvc.md то там по моему это даже специально упоминается. Что контроллеры соответствуют разделам сайта. а модели - частям функционала приложения.
Еще совет: не спеши строить какие-то сложные структуры классов, если нет уверенности что это нужно. Лучше делать все проще. Вот статья по теме: https://habrahabr.ru/post/153225/
> Не люблю использовать ENUM, он не гибкий,
Можно потом добавлять новые статусы через ALTER TABLE.
> То-есть я исходил из логики - если я не могу наперед просчитать все подводные камни - то зачем сразу себе ограничения создавать на будущее.
Чтобы защититься от записи неправильных значений. Ну и слова чуть читабельнее чем числа.
> ENUM is evil
Ну так твое решение ничуть не лучше, там предлагается ENUM не на число заменять, а сделать отдельную таблицу статусов и ставить внешний ключ на нее.
> Я воспользовался стандартным кодом HTML-страницы из phpstorm emmet'a по !!+tab
Значит это плохой код. Это запрещает изменение масштаба в мобильной версии. зачем? Они его откуда-то бездумно скопировали, а исходный код скорее всего написал тот, кому лень было отлаживать верстку и он просто запретил масштабирование. На хабре сделано так же, как неудобно.
>>Это неудобно, лучше сделать автоматическое определение текущей папки.
> Почему не удобно? Практически во всех CMS используются предопределенные константы текущего местоположения проекта.
Потому что это можно определять автоматически. Зачем заставлять пользователя что-то вводить? Позор разработчикам таких CMS.
> Я указал путь не на папку проекта, а на корневой каталог для файлов загруженных пользователями.
Тогда можно сделать по умолчанию определение автоматически, а при необходимости переопределение в конфиге. Но если ты меняешь папку, скорее всего поменяется и URL, под которым она видна, ты это учел?
>>Есть какие-то веские причины почему тут запрещено наследование?
> Что может унаследоваться от класса который работает со структурой директорий? Не хочу чтобы плодились унаследованные классы, DIR вполне может выполнять любую работу с папками.
В этом и суть наследования, что ты заранее не знаешь, как твой класс будет унаследован. Вдруг кто-то например захочет логгировать все действия с папками или какие-нибудь проверки добавить. Для добавления final должна быть веская причина, например, какой-то критичный код, изменение которого сломает программу. И его тогда лучше на метод ставить, а не на весь класс.
Обычно нигде final не ставят, потому когда ты его ставишь, появляется вопрос, а зачем, и каких-то веских причин запрещать наследование я пока не вижу.
Если что, еще есть принцип что классы должны быть открыты для расширения, но закрыты для модификации (open/closed principle).
>>Между контроллерами и моделями нет соответствия один-к-одному. Плюс твой метод подразумевает
> Во многих CMS можно в один контроллер подключить сколько угодно моделей, в опенкарте как правило контроллеру соответствует модель
Это не стоит копировать. Это какая-то ошибка в опенкарте. Или это не совсем модель, а какой-то помощник для контроллера.
Если ты читал мой урок по MVC: https://github.com/codedokode/pasta/blob/master/arch/mvc.md то там по моему это даже специально упоминается. Что контроллеры соответствуют разделам сайта. а модели - частям функционала приложения.
Еще совет: не спеши строить какие-то сложные структуры классов, если нет уверенности что это нужно. Лучше делать все проще. Вот статья по теме: https://habrahabr.ru/post/153225/
> function bchexdec($hex) {
Она никак не проверяет наличие двоеточий. И может давать неверный результат. Надо ее доработать.
Также, я бы ее оптимизировал. Вот что можно улучшить:
- вырезать двоеточия
- убрать неэффективную рекурсию, заменить на цикл
- там на каждый шаг создается новая строка, неэффективно, лучше просто циклом идти по строке с конца к началу и брать N-й символ через substr.
- она берет по 1 символу за раз, но dechex работает минимум с 32-битными числами, это 8 16-чных, для надежности можно брать по 6 цифр за раз.
Ты разобрался, как она работает? Она просто берет по 1 цифре с конца, домножает число на 16 и прибавляет эту цифру.
И надо протестировать эту функцию, на каком-нибудь известном числе. Например:
01:00:00 = 0x10000 = 65536
01:00:00:00:00 = 4294967296
ff:ff:ff:ff = 4294967295
07:5B:CD:15 = 123456789
01:6A:7C:1C:E1:EE:C6:FA = 102030405060708090
(преобразовать можно калькулятором Windows или как описано тут https://www.cyberciti.biz/faq/linux-unix-convert-hex-to-decimal-number/ )
Также, может быть библиотека gmp будет эффективнее, так как она хранит числа не в виде строк, а в виде объектов и может там как-то эффективнее это сделано. Ну и для импорта чисел там есть gmp_import, тебе надо только твое число преобразовать в бинарную строку из байтов сначала.
> # соль
Имей в виду что mt_rand генерирует лишь 32-битное число и использует генератор (вихрь Мерсена), у которого генерируемые числа зависят от предыдущих (не криптографически надежный). Если ты генерируешь большое число несколькими вызовами mt_rand, там все равно будет только 32 или меньше бит случайности, остальные биты зависят от предыдущих. Более того, ты искуственно ограничиваешь диапазон, что уменьшает число возможных вариантов. У тебя вариантов числа a совсем немного получилось, на уровне 24 бит может быть.
Ну чтобы тебе было понятнее, представь что у тебя используется всего 3 бита энтропии: mt_rand(0, 7). Получается всего 8 вариантов, и их легко перебрать. Алгоритм же основан на том, что a и b трудно подобрать и для этого они должны быть в очень большом диапазоне (но больше простого числа q их делать смысла нет, так как при операциях по модулю результат не может быть больше этого модуля).
При этом несколько вызовов mt_rand подряд могут не помочь, так как в псевдослучайных генераторах только первое число (seed) случайное (берется из /dev/random или текущего времени, что хуже), а следующие числа генерируются из предыдущего. Например, rand() использует линейный генератор, прочитай статью: https://ru.wikipedia.org/wiki/Линейный_конгруэнтный_метод
Сколько бы ты не вызывал rand(), и какое бы длинное число не делал, больше 32 бит энтропии (4 млрд вариантов) ты не получишь. И у тебя получается 32-битный ключ, что смешно по нынешним меркам. NSA его за 3 секунды вскроет.
Чтобы получить большое случайное число, надо использовать специальные функции:
- на линуксе - прочитать N байт из /dev/random Скорость генерации чисел может быть ограничена. Если нужны числа в очень больших количествах, придется раскошелиться на аппаратный генератор.
- в PHP7 сделали функцию http://php.net/manual/ru/function.random-bytes.php
- другие методы можно найти в исходниках библиотеки https://github.com/paragonie/random_compat , я их не буду тут приводить.
> foreach($args as $argument) {
> $string .= $argument . ':';
implode лучше использовать.
> Алсо, комп очень долго думает над этим всем, нагревается и жужжит, мне его жалко
Асимметричная криптография требует тяжелых вычислений, потому обычно с ее помощью только вырабатывают общий ключ и далее шифруют данные симметричным шифрованием с этим ключом.
Кстати, sha256 дает более длинный хеш, чем md5, с md5 мы получаем только 128 бит (то есть пароль какой бы сложный не был, останется только 128 бит от него). sha256 можно попробовать сгенерировать функцией http://php.net/manual/ru/function.hash.php
Еще алгоритм gost генерирует 256-битные хеши, если ты предпочитаешь отечественные разработки.
Попробуй еще gmp, может быстрее будет. Ну и можешь еще посчитать время, какая строка сколько времени требует.
> function bchexdec($hex) {
Она никак не проверяет наличие двоеточий. И может давать неверный результат. Надо ее доработать.
Также, я бы ее оптимизировал. Вот что можно улучшить:
- вырезать двоеточия
- убрать неэффективную рекурсию, заменить на цикл
- там на каждый шаг создается новая строка, неэффективно, лучше просто циклом идти по строке с конца к началу и брать N-й символ через substr.
- она берет по 1 символу за раз, но dechex работает минимум с 32-битными числами, это 8 16-чных, для надежности можно брать по 6 цифр за раз.
Ты разобрался, как она работает? Она просто берет по 1 цифре с конца, домножает число на 16 и прибавляет эту цифру.
И надо протестировать эту функцию, на каком-нибудь известном числе. Например:
01:00:00 = 0x10000 = 65536
01:00:00:00:00 = 4294967296
ff:ff:ff:ff = 4294967295
07:5B:CD:15 = 123456789
01:6A:7C:1C:E1:EE:C6:FA = 102030405060708090
(преобразовать можно калькулятором Windows или как описано тут https://www.cyberciti.biz/faq/linux-unix-convert-hex-to-decimal-number/ )
Также, может быть библиотека gmp будет эффективнее, так как она хранит числа не в виде строк, а в виде объектов и может там как-то эффективнее это сделано. Ну и для импорта чисел там есть gmp_import, тебе надо только твое число преобразовать в бинарную строку из байтов сначала.
> # соль
Имей в виду что mt_rand генерирует лишь 32-битное число и использует генератор (вихрь Мерсена), у которого генерируемые числа зависят от предыдущих (не криптографически надежный). Если ты генерируешь большое число несколькими вызовами mt_rand, там все равно будет только 32 или меньше бит случайности, остальные биты зависят от предыдущих. Более того, ты искуственно ограничиваешь диапазон, что уменьшает число возможных вариантов. У тебя вариантов числа a совсем немного получилось, на уровне 24 бит может быть.
Ну чтобы тебе было понятнее, представь что у тебя используется всего 3 бита энтропии: mt_rand(0, 7). Получается всего 8 вариантов, и их легко перебрать. Алгоритм же основан на том, что a и b трудно подобрать и для этого они должны быть в очень большом диапазоне (но больше простого числа q их делать смысла нет, так как при операциях по модулю результат не может быть больше этого модуля).
При этом несколько вызовов mt_rand подряд могут не помочь, так как в псевдослучайных генераторах только первое число (seed) случайное (берется из /dev/random или текущего времени, что хуже), а следующие числа генерируются из предыдущего. Например, rand() использует линейный генератор, прочитай статью: https://ru.wikipedia.org/wiki/Линейный_конгруэнтный_метод
Сколько бы ты не вызывал rand(), и какое бы длинное число не делал, больше 32 бит энтропии (4 млрд вариантов) ты не получишь. И у тебя получается 32-битный ключ, что смешно по нынешним меркам. NSA его за 3 секунды вскроет.
Чтобы получить большое случайное число, надо использовать специальные функции:
- на линуксе - прочитать N байт из /dev/random Скорость генерации чисел может быть ограничена. Если нужны числа в очень больших количествах, придется раскошелиться на аппаратный генератор.
- в PHP7 сделали функцию http://php.net/manual/ru/function.random-bytes.php
- другие методы можно найти в исходниках библиотеки https://github.com/paragonie/random_compat , я их не буду тут приводить.
> foreach($args as $argument) {
> $string .= $argument . ':';
implode лучше использовать.
> Алсо, комп очень долго думает над этим всем, нагревается и жужжит, мне его жалко
Асимметричная криптография требует тяжелых вычислений, потому обычно с ее помощью только вырабатывают общий ключ и далее шифруют данные симметричным шифрованием с этим ключом.
Кстати, sha256 дает более длинный хеш, чем md5, с md5 мы получаем только 128 бит (то есть пароль какой бы сложный не был, останется только 128 бит от него). sha256 можно попробовать сгенерировать функцией http://php.net/manual/ru/function.hash.php
Еще алгоритм gost генерирует 256-битные хеши, если ты предпочитаешь отечественные разработки.
Попробуй еще gmp, может быстрее будет. Ну и можешь еще посчитать время, какая строка сколько времени требует.
Я не знаю точно о какой речь, какую-то из этой серии видел и код там был не очень, плюс там требуется знать HTML чтобы ее читать.
>>964928
В лог который у тебя там указан, что-то пишется? У phing наверно есть отладочный режим, где он пишет подробно выполняемые команды, попробуй его включить:
https://www.phing.info/docs/stable/hlhtml/index.html#sec.commandlineargs
> -verbose Verbose, give some more output
> -debug Output debug information
Судя по тому, что виснет, аргументы не передаются, то есть выполняется просто команда php и он ждет данных на стадартный вход.
чтобы указывать аргументы отдельно, надо использовать не command="" а executable="".
>>964977
Ты используешь синтаксис при определении роута, который говорит Слиму самому создать объект класса. Надо использовать синтаксис, указывающий что класс надо взять из контейнера.
Также при определении контроллера как сервиса надо указать что он каждый раз должен создаваться заново.
Чтобы понять, как Слим отличает имя класса от имени сервиса в контейнере, лучше всего глянуть код Слима:
- идем сюда https://github.com/slimphp/Slim/blob/3.x/Slim/App.php#L134
- затем https://github.com/slimphp/Slim/blob/3.x/Slim/App.php#L224
- здесь идет вызов роутера: https://github.com/slimphp/Slim/blob/3.x/Slim/Router.php#L156
- он передает handler в конструктор роута: https://github.com/slimphp/Slim/blob/3.x/Slim/Route.php#L88
- тогда смотрим код run() https://github.com/slimphp/Slim/blob/3.x/Slim/App.php#L290
- затем https://github.com/slimphp/Slim/blob/3.x/Slim/App.php#L354
- затем https://github.com/slimphp/Slim/blob/3.x/Slim/App.php#L446
- здесь мы видим что за вызов контроллера отвечает роут:
> return $route->run($request, $response);
и идем назад в Route:
- раз https://github.com/slimphp/Slim/blob/3.x/Slim/Route.php#L310
- два https://github.com/slimphp/Slim/blob/3.x/Slim/Route.php#L331
И тут наконец мы находим нужное:
- $this->callable = $this->resolveCallable($this->callable);
Эта функция берет на вход то, что мы передали в $app->get() и преобразует его в функцию .которую можно вызвать. Изучаем код этой функции.
- раз https://github.com/slimphp/Slim/blob/3.x/Slim/Routable.php
- два https://github.com/slimphp/Slim/blob/3.x/Slim/CallableResolverAwareTrait.php#L36
Тут видно что отвечает за преобразование сервис callableResolver. Идем в него:
- раз https://github.com/slimphp/Slim/blob/3.x/Slim/CallableResolver.php#L49
- два https://github.com/slimphp/Slim/blob/3.x/Slim/CallableResolver.php#L83
разбирайся.
Вот кстати аноны, которые не хотят решать задачи по ООП из моего учебника, просто интересно, как вы код Слима собрались читать не понимая ни ООП ни DI?
Я не знаю точно о какой речь, какую-то из этой серии видел и код там был не очень, плюс там требуется знать HTML чтобы ее читать.
>>964928
В лог который у тебя там указан, что-то пишется? У phing наверно есть отладочный режим, где он пишет подробно выполняемые команды, попробуй его включить:
https://www.phing.info/docs/stable/hlhtml/index.html#sec.commandlineargs
> -verbose Verbose, give some more output
> -debug Output debug information
Судя по тому, что виснет, аргументы не передаются, то есть выполняется просто команда php и он ждет данных на стадартный вход.
чтобы указывать аргументы отдельно, надо использовать не command="" а executable="".
>>964977
Ты используешь синтаксис при определении роута, который говорит Слиму самому создать объект класса. Надо использовать синтаксис, указывающий что класс надо взять из контейнера.
Также при определении контроллера как сервиса надо указать что он каждый раз должен создаваться заново.
Чтобы понять, как Слим отличает имя класса от имени сервиса в контейнере, лучше всего глянуть код Слима:
- идем сюда https://github.com/slimphp/Slim/blob/3.x/Slim/App.php#L134
- затем https://github.com/slimphp/Slim/blob/3.x/Slim/App.php#L224
- здесь идет вызов роутера: https://github.com/slimphp/Slim/blob/3.x/Slim/Router.php#L156
- он передает handler в конструктор роута: https://github.com/slimphp/Slim/blob/3.x/Slim/Route.php#L88
- тогда смотрим код run() https://github.com/slimphp/Slim/blob/3.x/Slim/App.php#L290
- затем https://github.com/slimphp/Slim/blob/3.x/Slim/App.php#L354
- затем https://github.com/slimphp/Slim/blob/3.x/Slim/App.php#L446
- здесь мы видим что за вызов контроллера отвечает роут:
> return $route->run($request, $response);
и идем назад в Route:
- раз https://github.com/slimphp/Slim/blob/3.x/Slim/Route.php#L310
- два https://github.com/slimphp/Slim/blob/3.x/Slim/Route.php#L331
И тут наконец мы находим нужное:
- $this->callable = $this->resolveCallable($this->callable);
Эта функция берет на вход то, что мы передали в $app->get() и преобразует его в функцию .которую можно вызвать. Изучаем код этой функции.
- раз https://github.com/slimphp/Slim/blob/3.x/Slim/Routable.php
- два https://github.com/slimphp/Slim/blob/3.x/Slim/CallableResolverAwareTrait.php#L36
Тут видно что отвечает за преобразование сервис callableResolver. Идем в него:
- раз https://github.com/slimphp/Slim/blob/3.x/Slim/CallableResolver.php#L49
- два https://github.com/slimphp/Slim/blob/3.x/Slim/CallableResolver.php#L83
разбирайся.
Вот кстати аноны, которые не хотят решать задачи по ООП из моего учебника, просто интересно, как вы код Слима собрались читать не понимая ни ООП ни DI?
Есть вариант controller-as-a-service, почему бы анону его не попробовать?
>>965008
Думаю, что ты путаешь. В DI как раз применяется принцип IoC в том смысле, что не класс ищет зависимости, а их в него инжектируют. Мне само понятие IoC не нравится так как при желании под него можно подвести что угодно.
>>965013
Анон хочет DI в контроллере.
>>965018
Там еще есть вариант когда контроллер это сервис в контейнере.
>>965020
У тебя для контроллера внедряется контейнер и получается ServiceLocator. так часто делают, это нормально, но анон хочет чтобы контроллер был сервисом с DI.
>>965021
Для работы со строками надо использовать mb_substr а не substr и тд. На ideone они могут не работать, используй 3v4l.org Урок https://github.com/codedokode/pasta/blob/master/php/strings-utf8.md
>>965201
Как насчет Symfony Form Component? Сложный и навороченный, самой Симфони не требует.
>>965599
Если обработчик это анонимная функция то там $this по моему указывает на $app.
Есть вариант controller-as-a-service, почему бы анону его не попробовать?
>>965008
Думаю, что ты путаешь. В DI как раз применяется принцип IoC в том смысле, что не класс ищет зависимости, а их в него инжектируют. Мне само понятие IoC не нравится так как при желании под него можно подвести что угодно.
>>965013
Анон хочет DI в контроллере.
>>965018
Там еще есть вариант когда контроллер это сервис в контейнере.
>>965020
У тебя для контроллера внедряется контейнер и получается ServiceLocator. так часто делают, это нормально, но анон хочет чтобы контроллер был сервисом с DI.
>>965021
Для работы со строками надо использовать mb_substr а не substr и тд. На ideone они могут не работать, используй 3v4l.org Урок https://github.com/codedokode/pasta/blob/master/php/strings-utf8.md
>>965201
Как насчет Symfony Form Component? Сложный и навороченный, самой Симфони не требует.
>>965599
Если обработчик это анонимная функция то там $this по моему указывает на $app.
> То, что ты хочешь, называется Controller as Service. Обычно в этом нет смысла, есть идеи почему?
Некоторые используют этот подход. А почему нет смысла?
Оп, так я правильно хочу сделать, передав таким образом объекты в контроллер? А то меня выше обругали и посоветовали контейнер кидать и из него брать нужное (это ServiceLocator, я так понимаю).
Есть всякие halpers, processors, handlers, makers и другая хуета.
ну вот как я вижу:
- halpers - это например дату подогнать для вывовода, или подготовить данные для вывода(ну если нужно перечитать или отправть)
За остальных вообще не ебу, анон памаги!
Дай совет, название книги, пинок под зад - возьму всё.
За опп неочень знаю, так как пилял сайтики визиточки и мимоговномагазы.
Задача про гамбургер
Ок, теперь все верно.
Электросеть
Там у нас был вопрос про то, что в одном месте можно обойтись без цикла.
Давай я приведу пример, чтобы пояснить свою мысль. Допустим у нас есть money рублей и мы хотим купить на них как можно больше пирожков, при этом каждый стоит price и всего их в наличии stock. Надо узнать, сколько пирожков мы в итоге купили. Можно конечно решить задачу так:
var money = 100;
var price = 10;
var stock = 4;
var result = 0; // ответ
while (money >= price && stock > 0) {
money -= price;
stock--;
result++;
}
Но что-то мне подсказывает, что число купленных пирожков можно найти и без использования цикла, по простой формуле. То же самое касается и расчета закупленной энергии в функции countPowerLinePrice(), где можно обойтись без цикла. Нужна подсказка, как?
Эти строчки:
> price += this.countPowerLinePrice(powerlines, balance);
> balance = this.countRemainingPowerAfterPass(powerlines, balance);
Я бы упростил примерно так:
var amount = this.countEnergyTransfer(powerlines, balance); // объем купленной/проданной энергии
balance += amount;
price += amount * powerlines.getPricePerMegawatt();
Так как у тебя там сейчас две почти одинаковых функции (countPowerLinePrice, countRemainingPowerAfterPass). Ну или можно сделать из них одну функцию, которая возвращает сразу и объем, и стоимость энергии.
> function someTypeOfSolarPanel() {
> SolarPanele.apply(this, arguments);
Вот это неправильно, так как у нас у конструкторов разные наборы аргументов, сравни:
function someTypeOfSolarPanel()
function SolarPanele(power)
Раз у них разный набор аргументов, то нельзя передавать аргументы, предназначенные для одной функции, другой. Вместо этого надо делать так:
var power = 100500;
SolarPanele.call(this, power);
В классе Electrostation лучше было сделать так:
function Electrostation(power) {
if (power неправильный) {
выбросить ошибку;
}
NetworkElement.call(this, power, power);
}
То есть мы вызываем конструктор предка и передаем ему нужные значения. Если позже в конструктор NetworkElement допишут еще какой-то код, то он сработает, а в твоем варианте - конструктор предка не вызывается. И не очень понятно, ради чего ты отказываешься его вызывать. По моему, логичнее вызвать уже написанный конструктор предка (NetworkElement), если он сделает то, что нам нужно.
> Math.pow(10, 3);
Я тут вспомнил, в программировании есть "научный" формат записи чисел, и можно писать так: 1e3 - это значит 1 умножить на 10 в 3 степени: https://learn.javascript.ru/number а например 2.5e3 = 2500.
Кстати "научный" формат есть и в PHP, и в куче других языков, точно в таком же виде.
> Если что, я не согласен с вашим замечанием - потому что мне не нужно было давать ссылку на Сеть, только передать уже посчитанный баланс. Можно было считать Сеть за контроллер, а ЛЭП за модель которая содержит вспомогательные методы расчета. А теперь в эти методы нужно передавать ссылку на ЛЭП. Мне из-за этого кажется что я понял и сделал всё ещё более худшим образом.
Я уже не очень понимаю, о чем речь. Тот метод, что используется сейчас, вполне подходит. Если хочется обсудить другой вариант, то хорошо бы увидеть хотя бы кусочек кода.
> Можно я не буду эту менять? Придётся заново переосмысливать мою программу.
По идее, ты должен стараться писать программу так, что в ней было легко разобраться. И соответственно небольшие изменения не должны вызывать сложностей и ради них не требуется всю программу переделывать, а только небольшую часть. А если все оставить как есть - может ты и дальше будешь писать цикл там, где он не требуется.
Определение типа переменной
> Чем плох свич, если его функционал подходит для этой задачи?
Ничем не плох, если подходит, то пусть будет. Просто мне кажется, с хешем строк бы получилось меньше, так как каждый блок в свитче это минимум 3 строки. Можно было сначала искать в хеше, а если там нет нужного значения, уже применять дополнительные условия.
> if (variable == undefined) {
тут сравнение неточное, через == может получиться что например 0 равен undefined. И неправильно сделана проверка, чтобы проверить, есть ли в объекте ключ, надо использовать
key in object
А твой код не отличит отстуствия поля от поля, в котором записано значение undefined.
> Встроенных объектов довольно много. Мне действительно следует прям для каждого-каждого объекта писать логику?
По условиям задачи - только для Date и массивов (остальное либо примитивные значения либо оыбчные объекты).
> Включая примитивные значения, которые на самом деле тоже объекты?
Это не так. Почитай пожалуйста еще раз про боксинг, например в моих заданиях по JS ( https://gist.github.com/codedokode/ce30e7a036f18f416ae0#Боксинг ) или в других статьях: http://www.jisaacks.com/javascript-boxing/
Примитивные значения - это не объекты, но если пытаться их использовать как объекты (обращаться к свойствам или методам), для них автоматически создается временный объект, в который заворачивается примитивное значение.
Напиши функцию неглубокого копирования объектов и массивов
> clone.setFullYear(object.getFullYear());
> clone.setMonth(object.getMonth());
Вообще, там есть способ проще, можно из исходной даты получить ее в виде числа и создать новую на основе этого числа.
> var clone = object.bind(clone);
Тут ошибка. Во-первых, клонировать функции не требуется (да и это невозможно наверно), во-вторых, если уж клонировать, то непонятно почему надо привязывать this к пустому на тот момент значению clone. Что делает этот bind?
В общем, я думаю, надо убрать клонирование функций, Error, Regexp, так как непонятно, корректно оно делается или нет.
>>Встроенные объекты могут иметь скрытые свойства и просто циклом их копировать нельзя.
> А как узнать про эти свойства? У меня не получилось ничего найти про них.
Узнать про них можно разве что читая исходный код браузеров, так как они не стандартизованы и каждый их реализует как хочет. Более того, эти свойства могут быть не JS-свойствами, а например, доступны только в объекты даты в языке C++, на котором обычно пишут интепретаторы Яваскрипта.
То есть встроенные объекты не обязаны соответствовать правилам языка JS и могут делать то, что ты в своем коде повторить не сможешь. Ты должен использовать только те их возможности, которые описаны в стандарте или документации.
Потому знать эти свойства не требуется, а нужно использовать публично доступные методы (вроде getFullYear()). Если тебе любопытно, как именно этот объект устроен, придется лезть в код интерпретатора Яваскрипт.
В Хроме и другх браузерах на Webkit/Blink в качестве интерпретатора JS используется библиотека v8. Она написана на C++ и очень сложная, вплоть до того, что содержит компилятор JS кода в машинный код, который процессор выполняет напрямую (но зато быстрая).
Вот код, который инициализирует JS-движок и добавляет встроенный объект Date, и его функции:
https://github.com/v8/v8/blob/master/src/bootstrapper.cc#L1976
Дальше, к сожалению, разбираться долго, я сразу так не нашел, что к чему. Можешь поискать сам. Но сразу предупрежу, что это долго и мало что можно понять без подготовки.
В Firefox используется движок SpiderMonkey. Код на Си++, реализующий объекты Date, где-то тут: https://github.com/ricardoquesada/Spidermonkey/blob/master/js/src/jsdate.cpp
Глубокое копирование
Тут те же замечания, что и к предыдущей задаче.
Задача про гамбургер
Ок, теперь все верно.
Электросеть
Там у нас был вопрос про то, что в одном месте можно обойтись без цикла.
Давай я приведу пример, чтобы пояснить свою мысль. Допустим у нас есть money рублей и мы хотим купить на них как можно больше пирожков, при этом каждый стоит price и всего их в наличии stock. Надо узнать, сколько пирожков мы в итоге купили. Можно конечно решить задачу так:
var money = 100;
var price = 10;
var stock = 4;
var result = 0; // ответ
while (money >= price && stock > 0) {
money -= price;
stock--;
result++;
}
Но что-то мне подсказывает, что число купленных пирожков можно найти и без использования цикла, по простой формуле. То же самое касается и расчета закупленной энергии в функции countPowerLinePrice(), где можно обойтись без цикла. Нужна подсказка, как?
Эти строчки:
> price += this.countPowerLinePrice(powerlines, balance);
> balance = this.countRemainingPowerAfterPass(powerlines, balance);
Я бы упростил примерно так:
var amount = this.countEnergyTransfer(powerlines, balance); // объем купленной/проданной энергии
balance += amount;
price += amount * powerlines.getPricePerMegawatt();
Так как у тебя там сейчас две почти одинаковых функции (countPowerLinePrice, countRemainingPowerAfterPass). Ну или можно сделать из них одну функцию, которая возвращает сразу и объем, и стоимость энергии.
> function someTypeOfSolarPanel() {
> SolarPanele.apply(this, arguments);
Вот это неправильно, так как у нас у конструкторов разные наборы аргументов, сравни:
function someTypeOfSolarPanel()
function SolarPanele(power)
Раз у них разный набор аргументов, то нельзя передавать аргументы, предназначенные для одной функции, другой. Вместо этого надо делать так:
var power = 100500;
SolarPanele.call(this, power);
В классе Electrostation лучше было сделать так:
function Electrostation(power) {
if (power неправильный) {
выбросить ошибку;
}
NetworkElement.call(this, power, power);
}
То есть мы вызываем конструктор предка и передаем ему нужные значения. Если позже в конструктор NetworkElement допишут еще какой-то код, то он сработает, а в твоем варианте - конструктор предка не вызывается. И не очень понятно, ради чего ты отказываешься его вызывать. По моему, логичнее вызвать уже написанный конструктор предка (NetworkElement), если он сделает то, что нам нужно.
> Math.pow(10, 3);
Я тут вспомнил, в программировании есть "научный" формат записи чисел, и можно писать так: 1e3 - это значит 1 умножить на 10 в 3 степени: https://learn.javascript.ru/number а например 2.5e3 = 2500.
Кстати "научный" формат есть и в PHP, и в куче других языков, точно в таком же виде.
> Если что, я не согласен с вашим замечанием - потому что мне не нужно было давать ссылку на Сеть, только передать уже посчитанный баланс. Можно было считать Сеть за контроллер, а ЛЭП за модель которая содержит вспомогательные методы расчета. А теперь в эти методы нужно передавать ссылку на ЛЭП. Мне из-за этого кажется что я понял и сделал всё ещё более худшим образом.
Я уже не очень понимаю, о чем речь. Тот метод, что используется сейчас, вполне подходит. Если хочется обсудить другой вариант, то хорошо бы увидеть хотя бы кусочек кода.
> Можно я не буду эту менять? Придётся заново переосмысливать мою программу.
По идее, ты должен стараться писать программу так, что в ней было легко разобраться. И соответственно небольшие изменения не должны вызывать сложностей и ради них не требуется всю программу переделывать, а только небольшую часть. А если все оставить как есть - может ты и дальше будешь писать цикл там, где он не требуется.
Определение типа переменной
> Чем плох свич, если его функционал подходит для этой задачи?
Ничем не плох, если подходит, то пусть будет. Просто мне кажется, с хешем строк бы получилось меньше, так как каждый блок в свитче это минимум 3 строки. Можно было сначала искать в хеше, а если там нет нужного значения, уже применять дополнительные условия.
> if (variable == undefined) {
тут сравнение неточное, через == может получиться что например 0 равен undefined. И неправильно сделана проверка, чтобы проверить, есть ли в объекте ключ, надо использовать
key in object
А твой код не отличит отстуствия поля от поля, в котором записано значение undefined.
> Встроенных объектов довольно много. Мне действительно следует прям для каждого-каждого объекта писать логику?
По условиям задачи - только для Date и массивов (остальное либо примитивные значения либо оыбчные объекты).
> Включая примитивные значения, которые на самом деле тоже объекты?
Это не так. Почитай пожалуйста еще раз про боксинг, например в моих заданиях по JS ( https://gist.github.com/codedokode/ce30e7a036f18f416ae0#Боксинг ) или в других статьях: http://www.jisaacks.com/javascript-boxing/
Примитивные значения - это не объекты, но если пытаться их использовать как объекты (обращаться к свойствам или методам), для них автоматически создается временный объект, в который заворачивается примитивное значение.
Напиши функцию неглубокого копирования объектов и массивов
> clone.setFullYear(object.getFullYear());
> clone.setMonth(object.getMonth());
Вообще, там есть способ проще, можно из исходной даты получить ее в виде числа и создать новую на основе этого числа.
> var clone = object.bind(clone);
Тут ошибка. Во-первых, клонировать функции не требуется (да и это невозможно наверно), во-вторых, если уж клонировать, то непонятно почему надо привязывать this к пустому на тот момент значению clone. Что делает этот bind?
В общем, я думаю, надо убрать клонирование функций, Error, Regexp, так как непонятно, корректно оно делается или нет.
>>Встроенные объекты могут иметь скрытые свойства и просто циклом их копировать нельзя.
> А как узнать про эти свойства? У меня не получилось ничего найти про них.
Узнать про них можно разве что читая исходный код браузеров, так как они не стандартизованы и каждый их реализует как хочет. Более того, эти свойства могут быть не JS-свойствами, а например, доступны только в объекты даты в языке C++, на котором обычно пишут интепретаторы Яваскрипта.
То есть встроенные объекты не обязаны соответствовать правилам языка JS и могут делать то, что ты в своем коде повторить не сможешь. Ты должен использовать только те их возможности, которые описаны в стандарте или документации.
Потому знать эти свойства не требуется, а нужно использовать публично доступные методы (вроде getFullYear()). Если тебе любопытно, как именно этот объект устроен, придется лезть в код интерпретатора Яваскрипт.
В Хроме и другх браузерах на Webkit/Blink в качестве интерпретатора JS используется библиотека v8. Она написана на C++ и очень сложная, вплоть до того, что содержит компилятор JS кода в машинный код, который процессор выполняет напрямую (но зато быстрая).
Вот код, который инициализирует JS-движок и добавляет встроенный объект Date, и его функции:
https://github.com/v8/v8/blob/master/src/bootstrapper.cc#L1976
Дальше, к сожалению, разбираться долго, я сразу так не нашел, что к чему. Можешь поискать сам. Но сразу предупрежу, что это долго и мало что можно понять без подготовки.
В Firefox используется движок SpiderMonkey. Код на Си++, реализующий объекты Date, где-то тут: https://github.com/ricardoquesada/Spidermonkey/blob/master/js/src/jsdate.cpp
Глубокое копирование
Тут те же замечания, что и к предыдущей задаче.
Во-первых, если тебе не нравится ООП, ты можешь попробовать решить задачу без применения ООП, включая часть про антикризисные меры. И сравнить потом код. Я не против, давай сравним ООП-подход против не-ООП подхода.
Правда, код показывает, что ты пока не понимаешь ООП.
> Наследовать Работников от Департамента в корне не верно.
Я по моему об этом и писал выше, тут >>964062
В конструкторе Department ты обращаешься к полю, которое нигде не описано:
> $this->name = $name;
В метод countEmployees($employees) не нужно ничего передавать. Департамент и так знает, кто в нем работает и не надо специально передавать список работников. Зачем его делать методом, если он ничего из объекта не использует? Тогда его было логичнее сделать отдельной функцией.
Ну представь например такую ситуацию. Вот у нас есть функция, которая печатает информацию о депарматенте: название и сколько в нем человек работает. В нее передается только один объект департамента. Как ее написать?
function printDepartmentInfo($dep)
{
echo "Название: {$dep->name}, число сотрудников: ???\n";
}
И метод countEmployees не должен делать echo. Задача метода - посчитать результат и вернуть его, а что с ним делать, выводить его или нет, решает тот, кто вызвал метод. Ну может я хочу среднее по нескольким департаментам найти, но когда я буду вызывать эти методы, они будут что-то печатать, хотя мне это не нужно. Ну и если они печатают что-то они должны не с get, а с print начинаться (но это тоже будет неправильно, делать методы печати в классе Департамента, так как вывод данных на экран это не его зона ответственности).
> public function getSalary($employee)
То же самое, тут в метод не надо ничего передавать.
> case 1:
> $employee->baseSalary;//Ранг 1, зп по дефолту
Эта команда ничего не делает.
> $employee->baseSalary+=($employee->baseSalary)*25/100;
Что будет, если мы вызовем getSalary несколько раз подряд? Зарплата будет при каждом вызове увеличиваться что ли? Тогда метод должен называться "повысить зарплату", а не "узнать зарплату".
Если EmployeeGroup представляет собой группу работников, то логично, что его методы должны возвращать зарплату на всю группу, потребление кофе всей группой. У тебя же вычисление зарплаты для группы работников (умножение зарплаты одного работника на их количество в группе) сделано в классе Департамент. А почему? Это умножение очевидно должно делаться в EmployeeGroup. Он же знает и зарплату одного работника, и их количество в группе.
Ну представь например что мы возьмем из программы только один класс EmployeeGroup. И получается, имея объект этого класса, мы не можем даже узнать какая суммарная зарплата у группы работников, потому что код, который это считает, находится в классе Департамент, и мы даже вызвать его не можем. А хотелось бы чтобы у объекта был метод, который вернет суммарную зарплату этих работников. В одно действие. Твой код это не позволяет и заставляет нас копипастить по всей программе код, который умножает зарплату на количество.
Функция getAll() ничего не возвращает, хотя название "получить" говорит, что она что-то должна возвращать.
>>965298
Сделай все в одной функции, можно даже без классов. Попробуй. Можно даже в начале без антикризисных мер, но потом их надо добавить.
> , после сказали работников заменить на ГруппаРаботников, что и было сделано.
Я такого не говорил.
Я сказал, что если объект хранит информацию о нескольких работниках, то он должен называться EmployeeGrpup, а не Employees так как названия классов должны быть в единственном числе. Потому что нелогично, если например, мы создали всего один объект, называть его в множественном числе.
> Про наследования стало немного доходить, но тут Группуработников нельзя унаследовать от Департамента.
Нельзя, так как это разные вещи, а не сущности одного типа.
Если что-то непонятно, справшивай.
>>965366
У него это действительно группа, там даже есть поле quantity.
>>965428
Ты можешь использовать EmployeeGroup, но в антикризисных мерах например требуется взять часть работников (не всю группу целиком) и части повысить ранг или зарплату. это будет не очень удобно делать с нынешним подходом, но ты можешь попробовать. Лучше всего будет, если ты на деле увидишь недостатки своего решения.
>>965642
Пока не работает, я там кучу замечаний написал.
>>965808
Смысл зависит от конкретного фреймворка, надо читать документацию.
Во-первых, если тебе не нравится ООП, ты можешь попробовать решить задачу без применения ООП, включая часть про антикризисные меры. И сравнить потом код. Я не против, давай сравним ООП-подход против не-ООП подхода.
Правда, код показывает, что ты пока не понимаешь ООП.
> Наследовать Работников от Департамента в корне не верно.
Я по моему об этом и писал выше, тут >>964062
В конструкторе Department ты обращаешься к полю, которое нигде не описано:
> $this->name = $name;
В метод countEmployees($employees) не нужно ничего передавать. Департамент и так знает, кто в нем работает и не надо специально передавать список работников. Зачем его делать методом, если он ничего из объекта не использует? Тогда его было логичнее сделать отдельной функцией.
Ну представь например такую ситуацию. Вот у нас есть функция, которая печатает информацию о депарматенте: название и сколько в нем человек работает. В нее передается только один объект департамента. Как ее написать?
function printDepartmentInfo($dep)
{
echo "Название: {$dep->name}, число сотрудников: ???\n";
}
И метод countEmployees не должен делать echo. Задача метода - посчитать результат и вернуть его, а что с ним делать, выводить его или нет, решает тот, кто вызвал метод. Ну может я хочу среднее по нескольким департаментам найти, но когда я буду вызывать эти методы, они будут что-то печатать, хотя мне это не нужно. Ну и если они печатают что-то они должны не с get, а с print начинаться (но это тоже будет неправильно, делать методы печати в классе Департамента, так как вывод данных на экран это не его зона ответственности).
> public function getSalary($employee)
То же самое, тут в метод не надо ничего передавать.
> case 1:
> $employee->baseSalary;//Ранг 1, зп по дефолту
Эта команда ничего не делает.
> $employee->baseSalary+=($employee->baseSalary)*25/100;
Что будет, если мы вызовем getSalary несколько раз подряд? Зарплата будет при каждом вызове увеличиваться что ли? Тогда метод должен называться "повысить зарплату", а не "узнать зарплату".
Если EmployeeGroup представляет собой группу работников, то логично, что его методы должны возвращать зарплату на всю группу, потребление кофе всей группой. У тебя же вычисление зарплаты для группы работников (умножение зарплаты одного работника на их количество в группе) сделано в классе Департамент. А почему? Это умножение очевидно должно делаться в EmployeeGroup. Он же знает и зарплату одного работника, и их количество в группе.
Ну представь например что мы возьмем из программы только один класс EmployeeGroup. И получается, имея объект этого класса, мы не можем даже узнать какая суммарная зарплата у группы работников, потому что код, который это считает, находится в классе Департамент, и мы даже вызвать его не можем. А хотелось бы чтобы у объекта был метод, который вернет суммарную зарплату этих работников. В одно действие. Твой код это не позволяет и заставляет нас копипастить по всей программе код, который умножает зарплату на количество.
Функция getAll() ничего не возвращает, хотя название "получить" говорит, что она что-то должна возвращать.
>>965298
Сделай все в одной функции, можно даже без классов. Попробуй. Можно даже в начале без антикризисных мер, но потом их надо добавить.
> , после сказали работников заменить на ГруппаРаботников, что и было сделано.
Я такого не говорил.
Я сказал, что если объект хранит информацию о нескольких работниках, то он должен называться EmployeeGrpup, а не Employees так как названия классов должны быть в единственном числе. Потому что нелогично, если например, мы создали всего один объект, называть его в множественном числе.
> Про наследования стало немного доходить, но тут Группуработников нельзя унаследовать от Департамента.
Нельзя, так как это разные вещи, а не сущности одного типа.
Если что-то непонятно, справшивай.
>>965366
У него это действительно группа, там даже есть поле quantity.
>>965428
Ты можешь использовать EmployeeGroup, но в антикризисных мерах например требуется взять часть работников (не всю группу целиком) и части повысить ранг или зарплату. это будет не очень удобно делать с нынешним подходом, но ты можешь попробовать. Лучше всего будет, если ты на деле увидишь недостатки своего решения.
>>965642
Пока не работает, я там кучу замечаний написал.
>>965808
Смысл зависит от конкретного фреймворка, надо читать документацию.
Я хочу еще один пример привести. Там выше в уроке была задача про работников, где известно количество часов, которые этот работник отработал, надо найти сколько там обычных часов, сколько сверхурочных, сколько он заработал. Посмотри на ее код. Если ты ее не решал - вернись и реши.
Там есть класс Employee (сотрудник). Имея объект этого класса, мы можем получить информацию об этом сотруднике, например:
Узнать общее количество отработанных часов:
echo $employee->getTotalHoursWorked();
Узнать зарплату:
echo $employee->getSalary();
Видишь, здесь в методы ничего передавать не надо. Почему у тебя не так? Почему у тебя, даже имея объект EmployeeGroup или Department, нельзя получить какую-то информацию о нем, а надо передавать дополнительно какие-то массивы? Я не вижу, в чем тут выгода. Мне кажется, было бы удобнее, если не надо было ничего передавать, как в примерах выше.
>Там древний код скорее всего, написанный по мотивам того, что видели в других CMS того времени.
На самом деле 2.3 это одна из последних релизнутых версий (ей не больше полугода), и 3 версия готовится к выходу
>Сделай все в одной функции, можно даже без классов.
Я же ООП учу, зачем мне это?
Я тут переписал немного с использованием советов. +создал 4 класса по профессиям
https://3v4l.org/28B8k
В общем есть несколько проблем:
Это подсчет суммы по департаментам кофе/пейдж/зп, я не смог этого сделать и захуярил кривую функцию в конце. Как это правильно реализовать в рамках моего кода?
И конечно же поле public $quantity; у СОТРУДНИКА, предвижу:
>ТЫ ЧЕ ДЕБИЛ, ВСЕМ ТРЕДОМ ТЕБЕ ТУТ ВТИРАЕМ ЧТО ОН ЕДИНСТВЕННАЯ СУЩНОСТЬ
И я понимаю, что так нельзя, не может быть у сотрудника кол-ва сотрудников. Может перенести это поле в департамент? Хотя и там оно не очень подходит, на мой взгляд.
Я не ОП, но мне к примеру, если надо передать больше 2 переменных в метод - я использую ассоциативный массив,
К примеру :
http://ideone.com/KGHKk4
Это не замечание, но на мой взгляд так удобнее
>И конечно же поле public $quantity; у СОТРУДНИКА, предвижу
- Андрей Сергеевич Путин, так как у вас есть полный тезка в нашем департаменте и вы оба занимаете одну должность, поэтому мы вам просто добавим свойство quantity = 2. Может это тебе кажется удобным, но вносит непонятки
Всем привет. В общем у меня в таблице несколько студентов. Команда SELECT * FROM Students WHERE gr='$get' выбирает только первого из них. Как выбрать сразу всех студентов?
Просто всех студентов или отфильтровать ещё надо?
Если просто : SELECT FROM Students либо SELECT FROM Students WHERE 1
Макаба звездочку заменила
Удобным мне это кажется только от моего незнания других способов решения.
>>965906
>Это не замечание, но на мой взгляд так удобнее
Кажется это ненужное усложение.
>Кажется это ненужное усложение.
Когда станет параметров не 4, а 7 к примеру, ты каждый раз будешь вспоминать порядок передачи параметров если не пользуешься IDE, а так ты массивом вместе можешь передать параметры в любом порядке. Если тебе в будущем надо будет сделать не 4, а 5 параметров - придется либо задавать значение по умолчанию этому параметру либо искать все места где вызывается функция и дописывать везде 5ый параметр
Судя по твоему запросу он и выберет все записи, а не одну (если только она не одна под условие подходит). Для выбора 1 записи можно обратиться по первичному ключу, но тогда фильтр смысла не имеет, либо же использовать limit 1. В твоем случае ни того ни другого нет. Ты вообще уверен, что у тебя под условие подходит более одной записи? Что в $get находится? Чому передаешь переменную пхп прямо в строку запроса?
Это имеет свои недостатки:
- надо проверить, что в массиве нет лишних полей, и выдать ошибку в этом случае
- надо писать код перебирающий массив и сохраняющий поля
В твоем коде проверок нет. При опечатке это останется незамеченным и надо будет долго искать, почему ответ не сходится.
Разумное ограничение на число аргументов - это 5-6, если их больше то либо массив, либо отказаться от такого числа аргументов.
Для 3-4 аругментов усложнять код нет смысла, твой код был бы в разы проще с обычными переменными.
quantity в любом случае надо делать отдельно от остальных свойств.
>Судя по твоему запросу он и выберет все записи
Да я прочекал массив. Там почему-то только первый студент оказывается. Хотя условию удовлетворяют все.
Предположу, что ты работаешь через голый пдо. Хз че еще предположить тут. Есть вариант, что ты используешь к примеру fetch, который работает с итератором по результирующему набору, и он возвращает записи по одной. Тогда юзай fetchAll. А вообще код покажи, а то это на кофейной гуще все.
Запусти запрос напрямую в Mysql и посмотри - если возвращает всех - значит проблема не в запросе
Читая твое задание мне аж дурно стало.
Нет, не потому, что это сложно прямо, я с вп вообще не работал и не могу об этом судить, у меня дохуя лет опыта на фреймворках только. А потому, что я будто текст из другой вселенной читаю. Не могу объяснить этого чувства, но все же вот оно есть.
Судя по всему - лютый макакинг почти без программирования. Лучше бы что-то другое искал.
А ещё когда придешь туда, и познакомишься с их тим лидом, почувствуешь легкий шлейф снобизма, ведь он уже с пятерку лет шаблоны натягивает на вордпресс.
Говно какое-то.
>А вообще код покажи, а то это на кофейной гуще все.
$result=mysql_query("SELECT * FROM Students WHERE gr='$get'", $db);
$row=mysql_fetch_assoc($result);
print_r($row); - выводит данные только одного студента, а там их 5, удовлетворяющих условию. Можно ли как-нибудь всех вывести?
Все так, как я описал. Этот метод считай является итератором, возвращает тебе записи по одной за вызов.
Почитай доки и все ок будет.
https://secure.php.net/manual/ru/function.mysql-fetch-assoc.php
Суть токова: юзер нажимает кнопку и получает окошко с таблицей данных. Технически происходит следующее: при нажатии на кнопку срабатывает js-скрипт (Контроллер, так?), он передаёт через аякс пхп-скрипту (Модели) данные (что именно нажал пользователь и кто он вообще есть). Скрипт обращается к БД, что-то там вычисляет и выдаёт результат. И вот тут мне не понятно, как дальше всё сделать по фен-шую.
1) В https://github.com/codedokode/pasta/blob/master/arch/mvc.md написано, что он должен возвращать результат через return. Но пхп-скрипт, который вызывается в аяксе, оформлен у меня просто кодом на пхп, а не функцией (вернее, функции там тоже есть, но уже внутри).
2) Там же написано, что пхп-скрипт не должен выдавать ничего в echo. А как тогда должен? Единственный вариант, который я вижу - json.
3) Опять же, есть два стула. Для таблицы (которая показывается юзеру) нужно, к примеру, десять значений ячеек. Первый стул - это вернуть из пхп-скрипта (Модели) эти значения и уже в js-скрипте (Вид) подставить их в ячейки документа через document.getElementById("div_show_one_flight").innerHTML=data; Сам же внешний вид таблицы прописывается в index.php. Но в том же гайде пишут, что нельзя Виду работать с document. Да как так? Как выводить тогда вообще? Второй стул - это оставить в index.php только место для вставки, а полностью весь код таблицы набрать в пхп-скрипте, передать его через айкс обратно js-скрипту и вставить одним действием. Тоже лажа какая-то, получается: Модель напрямую рулит Видом.
Что-то не въезжаю я в караван мысли авторов этого паттерна.
>Как раз при вызове $this->get() ты и вызываешь метод контейнера.
Неа, не работает. Собственно в чем идея - я сделал класс ContainerWrapper который наследуется от слимовского контейнера. В нем у меня методы типа getTwig и phpDoc для него, все это для автодополнения кода. В контроллере это все работает, а вот в колбеке - нет.
В чем прикол? Зачем скармливать реквест этому компоненту, чтобы потом сразу же отправить пользователю ответ?
О, спасибо. Оно!
Так ты это, гитуй. Особенно студентов и файлообменник. Остальное потерять не страшно
Как сделать форму для одного Entity я разобрался. А как сделать форму, чтоб выводила несколько экземпляров Entity - не пойму
Пиздееееееец нахуя ты используешь глобальные константы?
>А как сделать форму, чтоб выводила несколько экземпляров Entity - не пойму
Так же как и одну.
Это амп, огрызок реакта. В нем нет поддержки ничего. Гугл собирает разметку страниц при индексации и потом добавляет страницы себе в кэш. Юзеры которые заходят на такие страницы - физически находятся на кэшированных страницах Гугла. Поэтому и такой вопрос. Там есть хуевая поддержка форм, но с ответами от сервера оно работать не умеет. Только с парой заголовков специфических, если бы обычный аякс мог работать я бы и не спрашивал
Я бы с радостью, но мне за это бабки платят
>>961633
Спасибо, переделал на Concrete TI и изменил каскадные ограничения: http://sqlfiddle.com/#!9/889f2/1
STI показывал в прошлый раз, а Class TI не вижу смысла использовать в этой задаче. Если захочу запретить пользователю ставить лайк самому себе, то в MySQL нужно писать триггер, а Postgres просто использовать CHECK?
Интересный пост про организацию тестирования iOS приложения.
А нахуя, еще 400 постов можно тут спокойно сидеть.
Да. С другой стороны, приватные свойства дают больше возможностей. Мы можем проверять присваиваемые значения на допустимость или менять одно поле при изменении другого.
>ие), по телефону спросили могу ли в вордпресс. Сказал, что в глаза его не видел, но за неделю как нибудь п
Книга лучшая что есть на русском языка на данный момент ( да и в принципе лучшая про WP). Так что с помощью глубокого чтения книги и гугления активного, сделать тестовое задание вообще на изи. Но я очень не уверен, что это изучить возможно за 1 неделю, система WP достаточно сложная, чё бы там кто не пиздел. Это не цэмээска для бложеков, а вполне себе платформа для создания сайтов любой сложности.
Это плохо что кто-то чужой делает перекат. Думаю, лучше остаться здесь.
>>966853 - про архив тредов ответ тут >>967836
>>966596 - про лайки там же >>967836
>>966275 - про TestHub тут >>967837
>>966146 - про HttpKernel тоже тут >>967837
>>966100 - про MVC тут >>967838
>>965899 - про Вектор тут >>967839
>>967822 - про инъекции тут >>967840
Если я кого-то пропустил и не ответил, напомните о себе
https://github.com/codedokode/pasta/blob/master/html/html.md
6: https://jsfiddle.net/ba2qgzt6/3/ (исправлено)
8: https://jsfiddle.net/7w3eg396/6/ (исправлено)
Теперь подряд идущие aside не накладаваются друг на друга, но всё равно непонятно куда девать лишний aside. Ещё если у aside будет больше высота, чем в соседнем абзаце, то нижний (следующий) абзац влезет вверх. Нужно каждую пару aside+абзац помещать в тег и ему прописывать clearfix?
10: https://jsfiddle.net/18504y5y/2/
11: https://jsfiddle.net/yyedd6ev/3/
Насчёт работы Tab/Shift+Tab - пытался через tabindex, перемещение работает, но по нажатию на Enter элемент не становится :checked. Можно подсказку?
12: https://jsfiddle.net/qozy8zsL/5/
width: 100% указывает, что содержимое элемента (без границ и padding'ов) должно занимать 100% ширины родителя. Погугли блочную модель.
Предполагаю, что width: 100% тебе вообще не нужен, а достаточно прописать display: block, так как блочные элементы занимают всю ширину родителя.
Добавь ссылку на jsfiddle со своим кодом, помочь тебе будет проще.
https://jsfiddle.net/2rwwpmne/
Вот пример из моего кода. Я делю область на несколько панелей. А внутри я хочу разместить вертикально друг за дружкой элементы, занимающие всю ширину панели.
Попробуй убрать стиль для звездочки, и увидишь что блочный div уехал в кукуево.
Вот и получается что я везде леплю первой строкой бордер-бокс. А тут он потерялся при переносе части стилей и весь макет разъехался, я пол часа думал, в чем причина, еле вспомнил про бордер-бокс.
Итак, является ли он необходимым по-умолчанию при верстке резиновых страниц, или я что-то упустил?
> и увидишь что блочный div уехал в кукуево.
Это из-за width: 100% + padding'ов.
Ну и width: 100% не нужен, div ведь занимает всю ширину родителя, так как блочный: https://jsfiddle.net/2rwwpmne/1/
> является ли он необходимым по-умолчанию при верстке резиновых страниц
Вряд ли, вот что ОП пишет:
> не используй код * { box-sizing: border-box } (он изменяет размер всех картинок, у которых есть border или padding)
тут: https://github.com/codedokode/pasta/blob/master/html/html.md#Плохой-код-который-писать-не-стоит/
как тогда сделать чтобы при слишком длинном содержимом панель чуть-чуть раздвинулась, вместила все так же и без полос прокрутки?
https://jsfiddle.net/2rwwpmne/2/
- напиши выражение вида "1 цифра, за ней любое число минусов, скобок, пробелов"
- возьми его в скобки и напиши что оно повторяется ровно 10 раз
>>969469
Ты box model изучал? Width это внутренняя ширина контента, без паддинга и бордера. Тебе скорее всего нужен width: auto, который нефлоаченные элементы с display: block растягивает на всю ширину родителя.
>>969717
В твоем примере кода можно просто для внутреннего элемента поставить width: auto. Изучай особенности определения размеров блочных элементов.
Также, я не понимаю, почему ты используешь звездочку. Тебе надо задать border-box для одного элемента, зачем задавать для всех остальных?
> Итак, является ли он необходимым
Конечно нет. Ставить логичнее его только там, где надо. Иначе происходят плохие вещи:
- картинки у которых задана ширина/высота, уменьшаются при добавлении паддинга
- сторонние виджеты, библиотеки, рассчитанные на box-sizing по умолчанию, отображаются криво
Кстати, bootstrap 3 тоже использует звездочку с border-box. И это примерно те же люди которые несколько лет назад писали везде что звездочки зло.
>>969931
Нужна более сложная верстка. Если ты жестко задал ширину 20% то она никак не раздвинется. Вместо этого можно использовать float или inline-block с шириной auto и min-width: 20%. Но перед этим надо почитать урок https://github.com/codedokode/pasta/blob/master/html/shrink-to-fit.md
Также, может быть, ты захочешь использовать display: table, сделав таблицу с одной строкой. Это позволит раздвигать одни ячейки за счет других и использовать вертикальное выравнивание.
Еще есть flex, но он только для новых браузеров.
- напиши выражение вида "1 цифра, за ней любое число минусов, скобок, пробелов"
- возьми его в скобки и напиши что оно повторяется ровно 10 раз
>>969469
Ты box model изучал? Width это внутренняя ширина контента, без паддинга и бордера. Тебе скорее всего нужен width: auto, который нефлоаченные элементы с display: block растягивает на всю ширину родителя.
>>969717
В твоем примере кода можно просто для внутреннего элемента поставить width: auto. Изучай особенности определения размеров блочных элементов.
Также, я не понимаю, почему ты используешь звездочку. Тебе надо задать border-box для одного элемента, зачем задавать для всех остальных?
> Итак, является ли он необходимым
Конечно нет. Ставить логичнее его только там, где надо. Иначе происходят плохие вещи:
- картинки у которых задана ширина/высота, уменьшаются при добавлении паддинга
- сторонние виджеты, библиотеки, рассчитанные на box-sizing по умолчанию, отображаются криво
Кстати, bootstrap 3 тоже использует звездочку с border-box. И это примерно те же люди которые несколько лет назад писали везде что звездочки зло.
>>969931
Нужна более сложная верстка. Если ты жестко задал ширину 20% то она никак не раздвинется. Вместо этого можно использовать float или inline-block с шириной auto и min-width: 20%. Но перед этим надо почитать урок https://github.com/codedokode/pasta/blob/master/html/shrink-to-fit.md
Также, может быть, ты захочешь использовать display: table, сделав таблицу с одной строкой. Это позволит раздвигать одни ячейки за счет других и использовать вертикальное выравнивание.
Еще есть flex, но он только для новых браузеров.
> 6: https://jsfiddle.net/ba2qgzt6/3/ (исправлено)
Ок, верно
> 8: https://jsfiddle.net/7w3eg396/6/ (исправлено)
> Теперь подряд идущие aside не накладаваются друг на друга, но всё равно непонятно куда девать лишний aside. Ещё если у aside будет больше высота, чем в соседнем абзаце, то нижний (следующий) абзац влезет вверх. Нужно каждую пару aside+абзац помещать в тег и ему прописывать clearfix?
Можно просто поставить на aside свойство clear. Оно добавляет такой margin-top, чтобы элемент оказался ниже самого нижнего из предыдущих флоатов.
А то сейчас как-то кривовато смотрится.
> article p {
> padding-left: 110px;
Тут ошибка. Почитай примечания к задаче. Что, если в тексте будут не только абзацы, а еще списки, картинки, заголовки и текст без тегов?
Если сделать на body max-width 1000px то видно что картинка увеличивается до этих 1000px. Но это неправильно, в задаче надо увеличивать картинку не более ее родного размера (иначе она размывается). Тебе нужен не width, а max-width.
Что-то я не вижу клавиатурной навигации в Хромиуиме тут https://fiddle.jshell.net/yyedd6ev/3/show/
Я думаю, это из-за того что инпуты скрыты через display: none.
Надо скрыть инпуты другим способом, без display: none (например: спозиционировать за пределы страницы, засунуть в див с оверфлоу хидден нулевых размеров, задать нулевую непрозрачность, в общем, заставить браузер думать что инпуты доступны для пользователя), и сделать подсветку кнопки в случае если соответствующий ей инпут сфокусирован (input:focus).
Установка tabindex, я думаю, это не выход, так как это позволяет элементу получить фокус, но ни на какие другие кнопки он без яваскриипта реагировать не будет (хотя если это label, может что-то и возможно, но я не уверен). Попробуй сделать не-стилизованные радиокнопки и проверь, как на них работают стрелки, таб и пробел/enter. Только настоящий чекбокс будет реагировать на пробел/enter, когда сфокусирован.
И вот еще мелочь: если кнопка одна, то не все углы у нее скруглены: https://jsfiddle.net/3qm145b4/
Без клавиатурной навигации, я подозреваю, с кнопками нельзя взаимодействовать например через программу чтения страниц вслух, так как она просто не поймет что кнопку можно нажать и не предложит такую опцию. Это конечно можно решить ARIA разметкой, но проще просто не скрывать инпуты.
Тут почти все хорошо, но из-за того что радиокнопки скрыты через none, невозможна клавиатурная навигация. Возможно ли решить эту проблему?
> 6: https://jsfiddle.net/ba2qgzt6/3/ (исправлено)
Ок, верно
> 8: https://jsfiddle.net/7w3eg396/6/ (исправлено)
> Теперь подряд идущие aside не накладаваются друг на друга, но всё равно непонятно куда девать лишний aside. Ещё если у aside будет больше высота, чем в соседнем абзаце, то нижний (следующий) абзац влезет вверх. Нужно каждую пару aside+абзац помещать в тег и ему прописывать clearfix?
Можно просто поставить на aside свойство clear. Оно добавляет такой margin-top, чтобы элемент оказался ниже самого нижнего из предыдущих флоатов.
А то сейчас как-то кривовато смотрится.
> article p {
> padding-left: 110px;
Тут ошибка. Почитай примечания к задаче. Что, если в тексте будут не только абзацы, а еще списки, картинки, заголовки и текст без тегов?
Если сделать на body max-width 1000px то видно что картинка увеличивается до этих 1000px. Но это неправильно, в задаче надо увеличивать картинку не более ее родного размера (иначе она размывается). Тебе нужен не width, а max-width.
Что-то я не вижу клавиатурной навигации в Хромиуиме тут https://fiddle.jshell.net/yyedd6ev/3/show/
Я думаю, это из-за того что инпуты скрыты через display: none.
Надо скрыть инпуты другим способом, без display: none (например: спозиционировать за пределы страницы, засунуть в див с оверфлоу хидден нулевых размеров, задать нулевую непрозрачность, в общем, заставить браузер думать что инпуты доступны для пользователя), и сделать подсветку кнопки в случае если соответствующий ей инпут сфокусирован (input:focus).
Установка tabindex, я думаю, это не выход, так как это позволяет элементу получить фокус, но ни на какие другие кнопки он без яваскриипта реагировать не будет (хотя если это label, может что-то и возможно, но я не уверен). Попробуй сделать не-стилизованные радиокнопки и проверь, как на них работают стрелки, таб и пробел/enter. Только настоящий чекбокс будет реагировать на пробел/enter, когда сфокусирован.
И вот еще мелочь: если кнопка одна, то не все углы у нее скруглены: https://jsfiddle.net/3qm145b4/
Без клавиатурной навигации, я подозреваю, с кнопками нельзя взаимодействовать например через программу чтения страниц вслух, так как она просто не поймет что кнопку можно нажать и не предложит такую опцию. Это конечно можно решить ARIA разметкой, но проще просто не скрывать инпуты.
Тут почти все хорошо, но из-за того что радиокнопки скрыты через none, невозможна клавиатурная навигация. Возможно ли решить эту проблему?
Ебать, ты!
$exit = array ("Work" => "Hard",
"existense" => "Easy",
"Death" => "Good",
)
foreach ($exit as $do=>$poss) {
echo $poss ."Do". $do;
}
>$exit = array ("Work" => "Hard",
>"existense" => "Easy",
>"Death" => "Good",
>); <---не забывай, никогда.
>
>
>foreach ($exit as $do=>$poss) {
>echo $poss ."Do". $do;
>}
Спасибо.
В новый тред с этим >>966608 (OP)
Этот тред давно закрыт.
Также, можешь погуглить Reactphp и ratchet.
Вы видите копию треда, сохраненную 24 мая 2017 года.
Скачать тред: только с превью, с превью и прикрепленными файлами.
Второй вариант может долго скачиваться. Файлы будут только в живых или недавно утонувших тредах. Подробнее
Если вам полезен архив М.Двача, пожертвуйте на оплату сервера.