Это копия, сохраненная 19 февраля 2016 года.
Скачать тред: только с превью, с превью и прикрепленными файлами.
Второй вариант может долго скачиваться. Файлы будут только в живых или недавно утонувших тредах. Подробнее
Если вам полезен архив М.Двача, пожертвуйте на оплату сервера.
Почему PHP? Потому что фейсбук и википедия на нем написаны, и вакансий море, и учить легко.
Это тред для начинающих. Не написал за свою жизнь ни одной программы? Ты наш человек.
Устанавливать пока что ничего не требуется, разве что редактор кода вроде Sublime Text 3, Notepad++, Netbeans PHP или PhpStorm (с ним будет удобнее).
Предыдущий тред был тут: >>619873 (OP) (почти 1000 постов!)
Что самое главное для программиста? Умение аккуратно оформлять код (читай второй пост).
Правила: ведем себя воспитанно, помогаем новичкам, постим ссылки на решения задачек, ОП их проверяет и дает советы и замечания. ОП отвечает даже на самые нубские вопросы. ОП заходит где-то раз в день-два, не жди его, решай задачки дальше.
У нас есть уроки по основам PHP, они собраны и выложены по адресу http://archive-ipq-co.narod.ru/ Это учебник для изучающих с нуля, то есть если ты вообще ничего не знаешь, то надо начать с него. Он простой и понятный (по крайней мере в начале). Там есть задачи, их надо решать обязательно (чтобы стать программистом, надо писать код — иначе никак). Пости ссылки на решения в тред, мы их проверим, напишем замечания и дадим советы по улучшению.
Если не знаешь как решать, запости код, напиши в каком месте остановился и попроси подсказку.
Учебник дает основы языка PHP, но чтобы делать сайты, этого недостаточно. Если ты его прошел, то надо переходить в более серьезным задачкам, которые научат тебя как выдавать страницы в браузер, работе с таблицами в БД, работе с формами, MVC.
- Простая, но полезная задача сделать список студентов: https://github.com/codedokode/pasta/blob/master/student-list.md
- Более сложная задача сделать файлообменник на микрофреймворке Slim: https://gist.github.com/codedokode/9424217
- Еще более сложная и долгая задача на Yii/Yii2: https://gist.github.com/codedokode/8733007
- После нее можно изучать автоматизированное тестирование
- Если ты все решил, переходи к Symfony 2/Doctrine 2
Чтобы делать эти задания, тебе надо установить Апач + PHP (можно заодно сразу и MySQL) на компьютер. Вот полезные инструкции:
https://gist.github.com/codedokode/10774100
https://gist.github.com/codedokode/7054af4a03865c4cc863
Может тебе понадобится пользоваться командной строкой, вот гайд https://gist.github.com/codedokode/10539568
Вот небольшой туториал по тому как начать использовать PHP на сервере для отдачи странички в браузер: https://php.net/manual/ru/tutorial.php Увы, уроков плавно подводящих к тому, как сделать задачи выше, пока нет, так что если что, задавай вопросы.
Решения задач лучше показать мне, особенно на ООП,так как сам ты вряд ли увидишь все ошибки. Пости свой код на гитхаб и вкидывай ссылку в тред по мере решения. Я прокомментирую и укажу на ошибки.
Также, у нас есть задачи которые позволят тебе изучить или подтянуть до нормального уровня знания JS/HTML/CSS/SQL. Решай их параллельно с задачами выше.
- HTML/CSS: https://gist.github.com/codedokode/58ebc90bd006baf4b35c
- 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://gist.github.com/codedokode/10539213
Что почитать
- Мануал по 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
Нужен ли ООП, фреймворки, MVC? — Да, однозначно. Посмотри любую вакансию.
Сайт опять упал!!!!! — Не паникуй, а открой http://rghost.net/45000175 и получи личную немного устаревшую копию сайта
Оформляй код аккуратно!!! — например пропусти через phpformatter.com . Также, если ты пользуешься IDE вроде PhpStorm, Netbeans, Eclipse, то в них эта опция встроена, подробнее: https://gist.github.com/codedokode/8759492
ОП, сделай за меня мою работу или домашнее задание? — Это конечно, хорошая идея, но нет.
Подскажи сайты для поиска работы, я не умею гуглить? — 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/php-fig/fig-standards/blob/master/accepted/ru/PSR-1-basic-coding-standard.md
PSR-2: https://github.com/php-fig/fig-standards/blob/master/accepted/ru/PSR-2-coding-style-guide.md
------------------
Итак, ты зашел в тред и решил помочь какому-то анону, дав ему совет или подсказку. Спасибо! Но прочти сначала эти напоминания, чтобы твоя помощь действительно была полезной.
Будь доброжелателен
Не годится: «Ты мануал хоть раз в жизни открывал, обезьяна?»
Не годится: «В гугле забанили?»
Не годится: «Твой код плохой»
Хорошо: «Вот, как можно улучшить этот код: ...»
Хорошо: «Ты неправильно используешь функцию abc(). Вот ее описание: ссылка, и как видишь ей надо передать строку, а не массив»
Не придирайся к знанию английского языка.
Объясняй
Не очень хорошо: «сделай как в этом коде»
Хорошо: «если ты вставляешь текст от пользователя в SQL запрос, то получается SQl-инъекция, которая позволяет взломать твой сервер (ссылки). Чтобы этого избежать, надо вставлять данные с помощью плейсхолдеров (ссылки)»
Хорошо: «Помни, что код пишется для людей. Если писать такие большие функции, то в них становится трудно разобраться...»
Не проповедуй
Мы учим использованию самых распространненных подходов, стандартов, библиотеки фреймворков. Если ты не любишь ООП, пробелы в коде, jQuery, сам PHP, то рассказать об этом стоит в каком-нибудь другом треде.
Не придирайся к знанию английского языка, анон пишет как умеет.
Ах да. Если тебе кажется, что что-то в учебнике или задачах можно сделать лучше — пиши, обратная связь всегда очень полезна.
Если тебе лень выравнивать код руками, закачай его на 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/php-fig/fig-standards/blob/master/accepted/ru/PSR-1-basic-coding-standard.md
PSR-2: https://github.com/php-fig/fig-standards/blob/master/accepted/ru/PSR-2-coding-style-guide.md
------------------
Итак, ты зашел в тред и решил помочь какому-то анону, дав ему совет или подсказку. Спасибо! Но прочти сначала эти напоминания, чтобы твоя помощь действительно была полезной.
Будь доброжелателен
Не годится: «Ты мануал хоть раз в жизни открывал, обезьяна?»
Не годится: «В гугле забанили?»
Не годится: «Твой код плохой»
Хорошо: «Вот, как можно улучшить этот код: ...»
Хорошо: «Ты неправильно используешь функцию abc(). Вот ее описание: ссылка, и как видишь ей надо передать строку, а не массив»
Не придирайся к знанию английского языка.
Объясняй
Не очень хорошо: «сделай как в этом коде»
Хорошо: «если ты вставляешь текст от пользователя в SQL запрос, то получается SQl-инъекция, которая позволяет взломать твой сервер (ссылки). Чтобы этого избежать, надо вставлять данные с помощью плейсхолдеров (ссылки)»
Хорошо: «Помни, что код пишется для людей. Если писать такие большие функции, то в них становится трудно разобраться...»
Не проповедуй
Мы учим использованию самых распространненных подходов, стандартов, библиотеки фреймворков. Если ты не любишь ООП, пробелы в коде, jQuery, сам PHP, то рассказать об этом стоит в каком-нибудь другом треде.
Не придирайся к знанию английского языка, анон пишет как умеет.
Ах да. Если тебе кажется, что что-то в учебнике или задачах можно сделать лучше — пиши, обратная связь всегда очень полезна.
Ответы на посты с 18 по 20 января наверно будут запощены в старом треде завтра или послезавтра.
Сделал вот задачу из ОП-поста на список студентов, реализовал все что нужно было, код все равно получился говном (но работает). Подскажите что переделать, что сделано не так.
Поддержки mysql нет потому что мне лень было её ставить на сервер. Взял вместо неё postgresql, хотя в теории если поменять одну строчку в конфиге, то всё должно заработать и с mysql (дамп базы очевидно не подойдет).
реквестирую урок по сессиям.
мое тестовое не забудь проверить плз.
ctrl+a
ТУТ ЕБУЧИЕ ФОРМАТРОВАНИЕ
ctrl+s
alt+shift+q
Что я нажимал подскажите, всегда это одной левой рукой делал точно
Вот у меня тоже такие провалы в памяти бывают, иногда хочу что-то сделать, начинаю делать, а потом на половине пути уже забываю зачем я это делаю.
Это первый знак того что я ОБДВАЧЕВАЛСЯ?
Есть, подключай клавиатуру и ставь какой-нибудь веб-сервер (из бесплатных kWS, Palapa Web Server).
Там и учить нечего, за день можно все осилить.
Про IDE не знаю, все что я делал это запускал на андроиде скрипты написанные на компьютере. Может быть кто-нибудь другой подскажет.
ideone.com, азаза
https://github.com/toppestkek/Test/blob/master/index.php#L5
> substr($_SERVER['REQUEST_URI'], 5)
что за магическое число 5?
>Почему имя класса с маленькой буквы? Почему оно не совпадает с именем файла? Во втором посте треда написана ссылка на рекомендации PSR, почитай-ка их.
А хз, лень было писать заново мвк, взял из какого-то старого примера, в тестовом условием было не использовать фреймворки, так-то бы я взял нормальный роутер от микрофреймворка.
>Инициализацию всяких объектов лучше вынести из контроллера.
Куда это их вынести? В новый объект?
>Ты файл почему-то загружаешь до валидации данных. Более того, тут как я понимаю можно загрузить php или htaccess файл и захватить твой сервер?
В аплоадс у меня стоит хтаксесс с таким кодом, поэтому нельзя.
php_flag engine 0
php_value upload_max_filesize 1G
php_value post_max_size 1G
>Непарвильное использование иключений
А какое правильное?
>Это правило применяется только к php скриптам расположенным внутри uploads
Так у меня же файлы только туда и грузятся
>формы все введенные значения теряются
лень писать было. эта валидация жиесом итак меня выбесила.
https://github.com/toppestkek/Test/blob/master/index.php#L5
> substr($_SERVER['REQUEST_URI'], 5)
что за магическое число 5?
>Почему имя класса с маленькой буквы? Почему оно не совпадает с именем файла? Во втором посте треда написана ссылка на рекомендации PSR, почитай-ка их.
А хз, лень было писать заново мвк, взял из какого-то старого примера, в тестовом условием было не использовать фреймворки, так-то бы я взял нормальный роутер от микрофреймворка.
>Инициализацию всяких объектов лучше вынести из контроллера.
Куда это их вынести? В новый объект?
>Ты файл почему-то загружаешь до валидации данных. Более того, тут как я понимаю можно загрузить php или htaccess файл и захватить твой сервер?
В аплоадс у меня стоит хтаксесс с таким кодом, поэтому нельзя.
php_flag engine 0
php_value upload_max_filesize 1G
php_value post_max_size 1G
>Непарвильное использование иключений
А какое правильное?
>Это правило применяется только к php скриптам расположенным внутри uploads
Так у меня же файлы только туда и грузятся
>формы все введенные значения теряются
лень писать было. эта валидация жиесом итак меня выбесила.
http://ideone.com/2CZC21
2) Генератор стихов:
http://ideone.com/Wqtqet
Иногда пропадают некоторые слова, как это пофиксить?
(Про array_rand из предыдущего поста не особо понял)
3) Про палиндром
http://ideone.com/7n6pqZ
в гугле забанили? ну вот так не ломается, потому что нахуй не всралось никому ломать шаражку рога и копыта.
да и автоматический ввод - дело дорогое и времязатратное для ломания всякого говна.
http://habrahabr.ru/post/145667/
>1) Задача про миллион в банке
Так интереснее с кредитом жи есть: http://ideone.com/TU9s96
echo просто внутрь цикла поставить, чтобы пронаблюдать за работой.
Считает верно всё.
>2) Генератор стихов:
Неправильно рассчитывается конечное число для функции mt_rand.
Чтобы понять ошибку, вспомни, начиная с какой цифры нумеруются ключи у значений в массивах.
Вот так можно исправить - переходи только после нахождения ошибки в своём коде! - : http://ideone.com/Ybpcko
Громоздко и неизящно, с array_rand всё проще выходит.
>3) Про палиндром
Нормально, всё работает и на слове "поп".
Я практически все с нуля переписал - https://github.com/lexdss/shop
ps: опять же интересует только код, на верстку можешь не смотреть, чисто для вида на скорую руку сделал.
И некоторые мелочи в функционал пока не допилил (типа проверки статуса заказа пользователем), но это позже, вдруг опять придется заново переписывать все
Обработка переменных ¶
Если строка указывается в двойных кавычках, либо при помощи heredoc, переменные внутри нее обрабатываются.
Существует два типа синтаксиса: простой и сложный. Простой синтаксис более легок и удобен. Он дает возможность обработки переменной, значения массива (array) или свойства объекта (object) с минимумом усилий.
Сложный синтаксис может быть определен по фигурным скобкам, окружающим выражение.
http://php.net/manual/ru/language.types.string.php
Препод по РНР?
Про палиндром не работает, сравнивает только 1 и последний символы в строке, а в середину хоть хуй напиши он всё равно палиндромом сочтёт.
Ох лол, действительно.
А я проверил только на "попе", код посмотрел - вроде всё логичным показалось.
Цикл не выдерживается до конца. Первые совпадающие буквы его сразу обрывают.
Короче, обрати внимание на то, как ты отсчитываешь буквы с конца строки.
Не читай подсказки, пробуй решить самостоятельно.
Подсказка: там должен быть знак минус, ты же должен с конца идти, а ты идёшь с начала строки. Там должна быть переменная опять же, потому что идёт это всё в цикле, переменная изменяется и буквы передвигаются в этом сравнении
Ещё одна подсказка: не существует такого выражения, как "минус ноль". Поэтому подумай, как там можно обойтись с отниманиями и прибавлениями единиц от переменной $i
Исправленный вариант (не открывать без попыток решить самостоятельно!): http://ideone.com/9wZnM9
А если я сделал через strrev но поправил кодировку в новой функции, меня всё равно пидорнут за такое?
http://ideone.com/htP10c
Забавное решение.
Но так-то задача на разбор циклов всё-таки, ОП вряд ли одобрит именно в плане подхода.
$search = $html->find('table tr td font');
То я получаю всю информацию, которая соответствует этому пути, из всех таблиц, как указать что инфа нужна только с третьей по счёту таблицы.
>Не понял о чем ты. В аргументе нелзя писать PDO Init::$pdo.
В смысле просто __construct(PDO $pdo), а потом просто передавал бы статически new DataGateway(Init::$pdo)
http://ideone.com/NIWEZS
Кстати, мне тут мысль пришла. Создать вторую ветку в проекте. Выслал решение ОПу, и во второй ветке продолжаешь пилить. Потом мержишь дорабатываешь. Годно?
http://ideone.com/GnrR0S
или разницы нет?
Неправильный второй ориентир для функции mt_rand. В массиве нумерация начинается с нуля.
http://ideone.com/hdiflZ - внутри телефонного номера можно траллить телефонисток, я проверял.
Подумай, как можно улучшить это:
>\\W*([0-9]{1})
Номер в фигурных скобках не имеет смысла, потому что в квадратных скобках "один любой указанный символ". После кода все цифры должны быть в одной регулярке, а также возможность ставить пробелы, минусы в любом порядке.
Также у ОПа есть паста для проверки тучи номеров. В предыдущем треде была тоже.
>$random1 = mt_rand(1, count($word1));
Что считает функция count($word1)?
С какого числа начинается нумерация в массиве?
О! Прям то, что нужно, а то как-то громоздко код выглядит. Спасибо.
пхп-алхимия - сродство говна к говну.
Я недавно сталкивался с подобной задачей, только почему-то мне хватило страницы документации, чтобы её решить.
http://simplehtmldom.sourceforge.net/manual.htm
Смотрите: задача про айфон в кредит W5.1 (надо сделать костыль, чтоб в минус не уходил банк). Решил с помощью такой конструкции:
if ($creditBalance <= $monthlyPayment) { / типа если кредита осталось меньше, чем ОП на завтраках экономит /
$monthlyPayment = $monthlyPayment - ($monthlyPayment - $creditBalance); / высчитали, какой будет месячный платёж в данном случае /
echo "последний платёж - $monthlyPayment"; / это чтоб программа показала, что всё сработало и платёж высчитался /
break; } /* закрыли конструкцию
Вот как сделать, чтоб после этого вышла надпись "всё заебок, долг $creditBalance" (ноль)? Час сижу, отложил работу, нибуя не получается. Пробовал решить через конструкцию elseif ($creditBalance = 0) - нихуя. Пробовал писать новый if - тоже не катит. break переносил. В каком направлении думать?
Нуля
Потому что нумерация с нуля это единственная верная нумерация. Посмотри на любую линейку или термометр. Нумерацию с единицы делают только ебаные гуманитарии.
Неправда. Нумеровать что-либо с единицы настолько естественно, что даже ты об этом не задумываешься. Термометр и линейка это шкала, которая служит для измерения и её начало в нуле, как и у любой числовой прямой. Элементы массива не вписываются в эту аналогию
А у меня не получается что-то, ты имеешь в виду решить её вот так?
$ret = $html->find('a', 0);
Где 0 порядковый номер элемента в дереве ДОМ?
Код на Идеоне вбрось, в каком он у тебя виде находится, а то не всё понятно.
Но могу пованговать, потому что несколько дней возился с этой задачей, переписывал её много раз с нуля, а потом и другим анончикам помогал решить правильно.
Короче, скорее всего, главная ошибка в том, что ты не различаешь $creditBalance (который у тебя учитывает и минус $monthlyPayment) и не проверяешь состояние кредита до всяческих условий с if и else. Для этого можно ввести дополнительную переменную.
Алгоритм такой:
1. Имеем сумму кредита.
2. Прибавляем к ней нужный процент и прибавляем комиссию за обслуживание кредита.
3. Проверяем, получившаяся сумма больше или меньше 5000, которые может выплачивать Анончик в месяц.
4. В соответствии с результатом проверки или продолжаем цикл выплат, или выплачиваем имеющуюся сумму и обрываем цикл (не забывай про пункт 1, что она у нас уже должна быть умножена на процент и к ней уже должна быть прибавлена комиссия за обслуживание кредита).
Всё.
Пробуй решить, каждый раз вбрасывай ссылку на код, так нагляднее.
Отличная задача для понимания работы циклов.
Там всё на поверхности, тем приятнее будет решение, когда уже успел намучиться.
Это на данный момент, когда я совета спрашивал
С усталой, но довольной улыбкой Аноним нажимал на кнопку "Submit" на ideone.com и не мог остановиться...
"99" - это "девяносто девять рублей"
"45" - это "сорок пять рублей"
"3" - это "три рубля"
"361" - это "триста шестьдесят один рубль"
"316" - это "триста шестнадцать рублей"
"421" - это "четыреста двадцать один рубль"
"124" - это "сто двадцать четыре рубля"
"787" - это "семьсот восемьдесят семь рублей"
"102" - это "сто два рубля"
"863" - это "восемьсот шестьдесят три рубля"
"160" - это "сто шестьдесят рублей"
"0" - это "ноль рублей"
"911" - это "девятьсот одиннадцать рублей"
"892" - это "восемьсот девяносто два рубля"
"749" - это "семьсот сорок девять рублей"
"150" - это "сто пятьдесят рублей"
"140" - это "сто сорок рублей"
"990" - это "девятьсот девяносто рублей"
"186" - это "сто восемьдесят шесть рублей"
"716" - это "семьсот шестнадцать рублей"
"524" - это "пятьсот двадцать четыре рубля"
"802" - это "восемьсот два рубля"
Как много уже было сделано, а сколько ещё предстояло сделать!
Аноним крепко сжимал ладонь свободной левой руки в кулак, а правой уверенной рукой продолжал настойчиво нажимать на кнопку "Submit"...
На его губах играла усталая довольная улыбка...
С усталой, но довольной улыбкой Аноним нажимал на кнопку "Submit" на ideone.com и не мог остановиться...
"99" - это "девяносто девять рублей"
"45" - это "сорок пять рублей"
"3" - это "три рубля"
"361" - это "триста шестьдесят один рубль"
"316" - это "триста шестнадцать рублей"
"421" - это "четыреста двадцать один рубль"
"124" - это "сто двадцать четыре рубля"
"787" - это "семьсот восемьдесят семь рублей"
"102" - это "сто два рубля"
"863" - это "восемьсот шестьдесят три рубля"
"160" - это "сто шестьдесят рублей"
"0" - это "ноль рублей"
"911" - это "девятьсот одиннадцать рублей"
"892" - это "восемьсот девяносто два рубля"
"749" - это "семьсот сорок девять рублей"
"150" - это "сто пятьдесят рублей"
"140" - это "сто сорок рублей"
"990" - это "девятьсот девяносто рублей"
"186" - это "сто восемьдесят шесть рублей"
"716" - это "семьсот шестнадцать рублей"
"524" - это "пятьсот двадцать четыре рубля"
"802" - это "восемьсот два рубля"
Как много уже было сделано, а сколько ещё предстояло сделать!
Аноним крепко сжимал ладонь свободной левой руки в кулак, а правой уверенной рукой продолжал настойчиво нажимать на кнопку "Submit"...
На его губах играла усталая довольная улыбка...
Делай по алгоритму, там у тебя как раз то, что я и предугадывал:
>$creditBalance = ( $creditBalance * $percent ) + $servicePayment - $monthlyPayment;
От $creditBalance уже отнята $monthlyPayment, когда $creditBalance попадает в условие.
То есть, например, $creditBalance у тебя 3000, а ты прибавляешь к нему комиссию и проценты, а потом отнимаешь $monthlyPayment, вот в минус и уходит.
Вот есть две таблице в одной - user(id, name) в другой - (id, user_id(кто поставил), like_user(кому поставил)). Как тут можно подсчитать одновременно сколько юзер поставил лайков и сколько ему? Если я сгруппирую так GROUP BY user.id (или user_id, неважно), то через COUNT смогу соответственно подсчитать сколько он лайков поставил, но не смогу подсчитать сколько ему поставили потому что COUNT зависит от GROUP BY. А еесли так GROUP BY like_user, то смогу подсчитать сколько пользователю поставили лайков, но теперь не смогу подсчитать сколько он поставил.
- chromium - вываливается куча непонятных пакетов, среди них есть нужный
- skype - нету
- flash - вываливается куча хлама, оказывается надо писать flashplugin в поиске
Вы ставите галочки, посмеиваясь над клоунами с виндой которые должны вручную искать программы в интернете, уворачиваясь от вирусов и троянов.
Вы жмете появившуюся кнопку "применить изменения", выскакивает запрос пароля рута, вводите, кнопка "применить изменения" исчезает. В журнале приложения написано что выбранные пакеты установлены.
Разумеется на самом деле ничего не установилось, иконок хромиума нет, самого пакета в dpkg -l тоже нет.
Предлагаю любителям линукса попробовать разгадать эту загадку. В /var/log/messages ничего нет.
Я конечно не удивлен, в линуксе всегда все было так, сколько раз я не пробовал им пользоваться. Но так сломать все надо еще постараться. В сравнении с гномом/дебиан тот же андроид на несколько порядков продуманнее - по крайней мере установка пакетов там работает из коробки.
Хуйней занимаешься. Качай исходники и компилируй сам. Скайп под линукс майкрософты не обновляли уже лет пять, я удивлюсь если он вообще там работает. В качестве флэша можно взять гугловский pepperflash. Ах да, забудь про гуй, он не нужен и для инвалидов.
Зачем мне качать исходники? В том же андроиде все ставится через менеджер пакетов, в дебиане без гнома - тоже. Только в дебиане с гномом и ГУИ все сломано.
В debian? Все сломано? В Debian?
В дистрибутиве, в котором по определению в репозиториях только стабильные версии ПО.
Может тебе Убунту попробывать?
Он просто криворукий виндузяткик, который ничего кроме как МЕНЕДЖЕР ПАКЕТОВ не может. Завтра он побежит создавать тред в /s/ какой этот ваш линукс говно и как там все неудобно.
У меня арч сам по себе упал. Просто сам по себе. До сих пор лень поднимать, стоит второй системой шиндовс.
Он не может сам по себе упасть. Упасть могли иксы, плазма и даже Аллах. Смотри и читай логи, отслеживай из-за чего это происходит.
На втором компьютере стоит центОС, не выключал его с сентября. Ни единого падения или тормоза, все работает идеально.
>Как тут можно подсчитать одновременно сколько юзер поставил лайков и сколько ему?
Логично иметь для такого две разные таблицы для разных лайков, не?
Отдельно лайки юзера, отдельно лайки юзеру.
Я хз.
У тебя и так две таблицы, ну да пох, я все равно пока не дошел.
Хз, в чем сложность дважды по разным параметрам группировать тогда.
Здесь связь одни ко многим, достаточно две таблицы. Кроме того если сделать как ты говоришь, то будет непонятно кто кому ставил лайки
>Хз, в чем сложность дважды по разным параметрам группировать тогда.
Сложности нет, но у ОПа написано, что это можно сделать одной группировкой и двумя джоинами
Ну может я разик обновился до перезагрузки, пол года назад было лол. До сих пор висит.
$app->get("/files/:id", $test($id));
Забудьте, оказывается аргументы передавать не нужно.
> Скайп под линукс майкрософты не обновляли уже лет пять, я удивлюсь если он вообще там работает.
У меня в Убунту 12.04 работает. Поставлен он был еще во времена 10.04 ни разу не обновлялся, пережил апгрейд на 12.04.
Никто тебе не мешает в Дебиана с Гномом и Гуи пользоваться командной строкой для установки пакетов.
Там новые облачные чатики не работают.
Как заказчик скажу: на лояльность влияет.
Идентифицированный пользователь, безопасная сделка.
А так будешь жумлу с вротперсом устанавливать, а точнее - грызться с кучами школьников ради этого.
Поправил выражение, но всё равно слишком громоздко вышло, не знаю как ещё упростить, взгляните кто шарит.
http://ideone.com/AhNYfb
ОП проверь, пожалуйста задание на js про ООП и гамбургеры
https://jsbin.com/pakonaseho/1/edit?js,console
сажа случайно прицепилась
Ты уже пробовал так делать?
Ты же тот кун что как и я делает задачу со студентами?
Как насчет обменяться контактами чтобы в будущем были совместные проекты?
Так лучше сначала в контору какую пойти работать за просто так, набраться опыта и потом вкатываться на апворк. Сам с нуля ты наврядли сможешь конкуренцию составить там кому-либо
Нет, я тот кун со студентами, а он нет. И я уже знаю вордпрессы. Контакты еще актуальны?
>Контакты еще актуальны?
Да, вот моя фейкопочта someapp( `renticeANUSopGP+enmailboxPUNCTUM=-]org
Отписал.
Чего ты там дошёл до хтмл, где в треде куча сложных заданий типа калькулятора или чисел прописью?
Дошел он, посмотрите на него..
Да я уже скидывал их в прошлые треды, за исключением 1 или 2 задач все выполнил
Да ладно, где калькулятор и числа прописью, например?
Лиличку и всякие клавиши шифт я видел, разные аноны делали.
А что посложнее - не было ни одного.
>Калькулятор точно кидал.
А числа прописью? Калькулятор увидел сейчас, да.
Мне-то все равно, просто не раз уже видел, как перескакивают через задачи, а потом потыкаются со студентами и пропадают.
Значит, ты просто пока еще не делал числа прописью, азаза!!1
Числа прописью было тем, что пропустил, ты прав. Примерный принцип я разобрал, но не было времени нормально решить задачу, т.к. жрёт много времени она, а у меня работа. Думаю, на выходных я вернусь к ней
А с чем работа связана? Вообще какой бэкграунд, образование, левел и т.п.?
Для чего решил изучать программирование?
С перекладыванием бумажек с одного места на другое.
>Для чего решил изучать программирование?
чтобы вырваться из этого круга пиздеца и уныния
Это 100% баг. Я установил чистую систему + из нее гном + gdm3, никаких настроек не менял, ничего не устанавливал, версия дебиана №8 (в названиях я путаюсь так как в них нет никакой логики).
И я знаю причину бага.
Алсо линукс я знаю не так и плохо.
>>631167
Нет, нелогично. Хватит одной, обычная связь многие-ко-многим.
>>631173
Добалвено. Баг не в том что поиск плохой и скайпа нет (или хотя бы инструкций по установке). Баг в том что я отмечаю пакеты (любые, в том числе свободные), жму установить, ввожу пароль и ничего не происходит, а интерфейс делает вид что все ок.
>>631210
Работает в 15-й убунте, скайп 4 версии без рекламы, фейсбука и прочей дряни.
Кстати кто не умеет отключать фейсбук и рекламу в скайпе на винде: прописываете в хостс apps.skype.com на 127.0.0.1 и перезапускаете скайп.
>>631214
Зачем мне лезть в командную строку если я хочу пользоваться удобным приложением наподобие маркета? Командная строка удобна ели у тебя например есть список пакетов для установки, их кодовые названия. А если ты не знаешь как называется пакет, а просто хочешь скайп или хромиум то аналог маркета был бы удобнее.
Это 100% баг. Я установил чистую систему + из нее гном + gdm3, никаких настроек не менял, ничего не устанавливал, версия дебиана №8 (в названиях я путаюсь так как в них нет никакой логики).
И я знаю причину бага.
Алсо линукс я знаю не так и плохо.
>>631167
Нет, нелогично. Хватит одной, обычная связь многие-ко-многим.
>>631173
Добалвено. Баг не в том что поиск плохой и скайпа нет (или хотя бы инструкций по установке). Баг в том что я отмечаю пакеты (любые, в том числе свободные), жму установить, ввожу пароль и ничего не происходит, а интерфейс делает вид что все ок.
>>631210
Работает в 15-й убунте, скайп 4 версии без рекламы, фейсбука и прочей дряни.
Кстати кто не умеет отключать фейсбук и рекламу в скайпе на винде: прописываете в хостс apps.skype.com на 127.0.0.1 и перезапускаете скайп.
>>631214
Зачем мне лезть в командную строку если я хочу пользоваться удобным приложением наподобие маркета? Командная строка удобна ели у тебя например есть список пакетов для установки, их кодовые названия. А если ты не знаешь как называется пакет, а просто хочешь скайп или хромиум то аналог маркета был бы удобнее.
Если ты ххочешь как-то обозначать версии то есть способ проще. Просто помечаешь определенную ревизию тегом, например v1 и продолжаешь работу в мастере, а ОПу даешь ссылку на гитхаб с этим тегом. Теги как раз придуманы чтобы помечать определенные версии.
Ветка это если ты хочешь например сделать отдельное улучшение но не хочешь пока его добавлять в мастер или если ты хочешь сдеоать какую-то алтернативную версию.
https://git-scm.com/book/ru/v1/%D0%9E%D1%81%D0%BD%D0%BE%D0%B2%D1%8B-Git-%D0%A0%D0%B0%D0%B1%D0%BE%D1%82%D0%B0-%D1%81-%D0%BC%D0%B5%D1%82%D0%BA%D0%B0%D0%BC%D0%B8
Гит очень крутая штука, я все время удивляюсь сколько в нем всего есть.
И поскольку мне лень вникать.
Дайте мне, пожалуйста, максималистское ревью, что нового и круто ли там?
Новая цифарка
Каким образом ты это в сессию записывать собрался? Ты вообще понимаешь как сессии работают?
http://ideone.com/GC1nHL - не работает.
Вспомни, что означают квадратные кавычки, как ведут себя в них все символы, как действуют символы ?, + и после квадратных кавычек. Это поможет избавиться от конструкции (\\s|\\(|\\)|\\"|-?), например.
Также тут же поймёшь, почему конструкция ([\\s\\-\\)\\"]) вообще нелепо выглядит
Вот паста ОПа, как минимум, все эти номера должно проверять верно:
----------
Задачу про номера телефонов надо проверить на большом числе телефонов, чтобы убедиться что твой код правильный. Но руками подставлять номера — долго и скучно. Пусть работает робот, а не человек!
Для этого давай добавим в программу тесты, чтобы сразу было видно, верно все работает или нет. Сделай 2 списка номеров (правильные и нет), добавь их в программу и напиши цикл, который их по очереди прогоняет через регулярку и проверяет что они определяются как надо (если нет — надо вывести какой именно номер не распознается правильно).
Вот список номеров:
Правильные: array('84951234567', '+74951234567', '8-495-1-234-567', ' 8 (8122) 56-56-56', '8-911-1234567', '8 (911) 12 345 67', '8-911 12 345 67', '8 (911) - 123 - 45 - 67', '+ 7 999 123 4567', '8 ( 999 ) 1234567', '8 999 123 4567');
Неправильные: array('02', '84951234567 позвать люсю', '849512345', '849512345678',
'8 (409) 123-123-123', '7900123467', '5005005001', '8888-8888-88',
'84951a234567', '8495123456a',
'+1 234 5678901', // неверный код страны
'+8 234 5678901', // либо 8 либо +7
'7 234 5678901' // нет +
);
А потом сессия обрывается и лайки пропадают?
Блин, звёздочки всю разметку порушили.
Ну ты там увидишь фрагменты своей регулярки, всё поймёшь, я думаю.
А я возьму и получу новую сессию. И буду так делать когда хочу поставить новый лайк. В итоге накручу себе лайков сколько захочу.
Сап, чуваки. Извините, если не в тот тред, но у вас в шапке вроде CSS упомянут. У меня пара вопросов по нему, ответы на которые чёт не гуглятся.
1. Что делаете с уродливыми чекбоксами и радио в Firefox-based браузерах? Хочется рамки в 1px и никаких больше теней и обводок. Перепробовал разные варианты. В поиске громадные фидлы с jquery и анимацией.
2. Насколько уместно в глобальном CSS (через Stylish) добавлять проверку на имена/классы? Например чтобы ютуб не ломался от background-color как на прирепленом скрине. Насколько в целом бьёт по производительности? Если есть опыт, пишите браузер. Я на своей пеке с i5 и 8 Gb оперативки совсем перестал понимать эти вещи (не хвастаюсь, кек).
Кстати, поэтому лайки от анонима - дохлый номер априори.
Сессии-то ладно, но и тупо IP можно менять и ставить лайки, скрипт какой-нибудь с проксями.
Если только как-то проверять конфигурацию системы, я даже хз.
Хотя нет. Есть знакомый админ на Питоне, он говорит, что можно тупо воровать данные об аккаунтах в соцсетях. Когда заходишь на страницу и при этом залогинен в какой-нибудь соцсети -система видит тебя и собирает инфу обо всех твоих профилях в соцсетях, чтобы потом продажники донимали тебя ещё и там. Жестоко и по-пидорски, но вот такие дела, такое возможно.
Есть даже какой-то сервис, который траллит тебя тем, что всю инфу о твоих соцсетях выдаёт - чекает, что там у тебя в браузере связано с ними.
Вот по такому можно ещё отслеживать реального юзера, получается. Только сложнота, наверное, я пока до такого не дошёл ещё.
>Вот по такому можно ещё отслеживать реального юзера, получается
А если я выйду из всех соц. сетей и каждый раз буду менять проксю и удалять все сессии? Плюс к этому прикрутить еще смену юзерагента и тогда только капчей можно будет защитить от накрутки (да и то капчу можно через антигейт прогнать, если деньги есть).
>А если я выйду из всех соц. сетей и каждый раз буду менять проксю и удалять все сессии?
Как раз может быть сигналом для срабатывания условия, при котором лайки перестают засчитываться. Я это и имею в виду.
Хоть в одной соцсети, но юзер зареган обычно. При этом аккаунты на Google или Yandex тоже ведь проверяются.
Тут уже зависит от способа получения конфига системы. Насколько я знаю, без анальных плагинов на джаве (не джаваскрипте) его нормально не получить.
Да.
Так я думал, что мы говорим только про отдельные анонимные лайки. Что лайки при регистрации - это само собой.
Так-то можно ещё сказать, что тогда проще для накрутки лайков и зарегистрироваться 100500 раз...
Но опять же можно и прочие моменты включать: аккаунты в соцсетях, IP, куки и т.п.
Это так-то болезнь программистов - доводить всё до ситуаций, которые могут и не произойти никогда, при этом не думать о капитальных вещах для пользователей. Аллан Купер об этом пишет хорошо в "Психбольнице...".
Если активность аккаунта нулевая в течение какого-либо периода времени - удалять его и все лайки.
Я отдельно посчитал баланс кредита (просто не стал отнимать месячный платёж) и ввёл новую переменную olbigation, которая считает не размер кредита, а размер обязательства анона перед банком. Т.е. если у него, к примеру, кредит - 100, а уплатил он 80, то размер обязательства - 20.
Когда размер обязательства становится меньше месячного платежа, вводится новая переменная - lastPay. Она нужна для того, чтоб сравнять размер общей суммы кредита с общими выплатами анона.
Таким образом, на последнем этапе вычисленный lastPay заменит месячный платёж анона (5000) - lastPay прибавится к тому, что анон уже заплатил. Итого (схематично):
долг анона - 100;
анон внёс суммарно - 100;
размер обязательств перед банком: 100 - 100 = 0
эхо "$размер обязательства"
>>631997
Бро, вынужден тебя дважды огорчить: я не ОП хотя и польщён тем, что меня за него приняли и калькулятор считает неправильно...
Там должна сумма всех выплат ($paymentTotal) составить 61270 рублей со многими копейками.
>долг анона - 100;
>анон внёс суммарно - 100;
>размер обязательств перед банком: 100 - 100 = 0
>эхо "$размер обязательства"
Ноуп, неверно! Долга Анончика 100 - прибавляем к этому проценты от 100, прибавляем 1000 за обслуживание кредита (а как же, ведь кредит не выплачен, а новый месяц пошёл), а потом уже выплачиваем именно эту получившуюся сумму и прибавляем её к общей выплате.
В предыдущем моём сообщении же весь алгоритм был, ты куда-то не туда улез, братишка, такие дела.
>Блядь, как же я долго дня ебался с этим кодом.
Я сам почти неделю всех терроризировал в треде, но в итоге решил практически в пару строк.
Обрати внимание на алгоритм вот тут ещё раз: >>631035
Просто отбрось всё и попробуй его реализовать. Тем более, что это и есть алгоритм задачи на самом сайте ОПа, только более развёрнутый.
Ахаха, ты - это я месяц назад...
Я просто даже сон и аппетит потерял в тот момент.
У меня там, правда, сумма почти сразу получилась верная, но уходило в минус, вот я посношался с этим...
После седьмого раза перестал считать, сколько переписывал ВЕСЬ скрипт с нуля, включая error_reporting(-1), блиять.
регулярка исправления по номеру телефона
http://ideone.com/NuO5fo
регулярка тест на граммар наци
http://ideone.com/I2Q3I9
http://ideone.com/jhtZ7c - неправильно показывает некоторые номера. Паста ОПа для проверки: >>631698.
http://ideone.com/MdRvFa - неправильно в некоторых местах. Также почему оставшихся моментов нет? Там много всего помимо этого должно быть.
Также надо показывать как минимум слово до ошибки и слово после - чтобы было понятно, где именно ошибка в тексте. Таковы условия задачи.
Процент от 40к и дальше от того, что остаётся после каждой выплаты.
Что поделать, Десу, но вот такие задачки у ОПа.
Зато потом начинаешь себя чувствовать вполне себе способным на многое.
Внешня библиотека не нужна. Из коробки идет встроенный html DOM document. Для парсинга лучше использовать xpath селектор, вместо CSS. Он более гибкий, но может показаться сложнее по началу.
запрос xpath будет типа:
.//table[3]//tr/td
Проверит можно в хроме, через меню разработчика, на панели HTML нажимаешь ctrl+f и вводишь xpath. На мозиле нужно ставить файрбаг + файрпав.
На мой взгляд так.
Если ты выполняешь какое либо действие над элементом на странице, не меняя контекст, то это аякс.
Самое простое: в браузере при открытой менюшке разработчика, при открытой вкладке запросов, отправить эту форму. Пото, правой кнопкой щелкаешь на запрос, и выбираешь "копировать как curl". Все необходимое у тебя теперь в буфере обмена.
"672" - это "шестьсот семьдесят две тысячи".
"351" - это "триста пятьдесят одна тысяча".
"354" - это "триста пятьдесят четыре тысячи".
"2" - это "две тысячи".
"1" - это "одна тысяча".
"681" - это "шестьсот восемьдесят одна тысяча".
"11" - это "одиннадцать тысяч".
"886" - это "восемьсот восемьдесят шесть тысяч".
"808" - это "восемьсот восемь тысяч".
"110" - это "сто десять тысяч".
"847" - это "восемьсот сорок семь тысяч".
"200" - это "двести тысяч".
Осталось миллионы вот так же разложить и собрать воедино всё. С миллионами должно быть просто, а вот собирать воедино будет непросто.
Для нулей поставлю условие, которое будет проверять, нет ли цифр больше нуля, а затем либо переводить дальше, либо выявлять имеющиеся цифры.
Очень много говнокода, просто очень много говнокода. Я думал, гораздо лучше будет это всё.
Я кода задачу на кредит для Айфона де-е-елал...
http://ideone.com/uimaxJ
>зависть-кун
Прости анончик, я не заходил в тред после того как оставил почту. Можешь оставить свои контакты тоже - я рад любым знакомствам!
Можете сами убедиться http://ideone.com/DXVHsD
По идее еще можно избавиться от элса и повторяющихся строк через функцию min или max.
Также, не называй переменные по-русски. Используй гугл транслейт или яндекс-словари. И форматируй код нормально - например код внутри функции должен быть с отступом. Второй пост треда рассказывает как это автоматизировать.
>>628329
На гитхабе написано: скачать полный пакет + подключить autoload из папки vendor. Зачем ты свои способы изобретаешь? В других туториалах очевидно предполагается что ты его ставил через композер, потому и код другой. Возможно даже тебе надо подключить 2 файла автолад: один из папки вендор, другой как в примере.
Если это не поможет то надо лезть в код и разбираться.
>>628393
Можно, если у тебя есть хорошие способности и ты лучше других кандидатов. Но не во все компании, есть компании с бюрократией, например государственные.
>>628490
ВО-первых, ты зря испольузешь левые сборки вместо оригинальных программ, ведь в этом случае никто не гарантирует работоспособность и совместимость. Да и теряешь ценный опыт возни с конфигами. Во-вторых, как ты открываешь консоль? Через меню опенсервера? В нем по моему своя, отдельная консоль и команды в обычной консоли вводить бесполезно - там нет некоторых переменных окружения.
Вот тут я не уверен, какой смысл делать библиотеку работы с картинками заменяемой? Это позволит генерировать превьюшки разных видов? Нет, не позволит, как я понимаю, какую бы ты библиотеку не использовал, результат одинаков. А зачем тогда это нужно? Выбери сам лучшую и используй ее.
АПИ адаптера не очень удачное:
> merge($background, $overlay, $left, $top, $opacity = 100);
А если мы хотим прижать ватермарк к правому краю? Нам было бы удобнее указать расстояние от него чем высчитывать отступ слева.
> public function getWidth($image);
> public function getHeight($image);
> public function resizeDown($image, $width = null, $height = null);
У тебя нет ощущения что логичнее было бы так:
$image->getWidth();
$image->getHeight();
$image->resizeDown(....);
Но это не самое важное, самое важное - это вопрос:
какие возможности добавляет твоя библиотека? Почему я должен взять ее, а не WideImage? На первый взгляд это просто обертка которая передает вызовы библиотеке. Единственное, что я вижу, что она предоставляет адаптеры с единым интерфейсом к разным библиотекам, но я не уверен что это нам нужно.
Еще я вижу что там заданы размер и цвет фона по умолчанию, но это как раз делает библиотеку не универсальной, а заточенной под один конкретный проект. Мне кажется, эти настройки должны быть в проекте, исплоьзующем библиотеку, иначе это какая-то неправильная библиотека. Хорошая библиотека не знает ничего об использующих ее проектах (как класс не знает про своих наследников).
Ну и это наверно не совсем по теме, но почитай (если ты еще не читал) статью про выпечку хлеба: https://habrahabr.ru/post/153225/ (хотя там по моему сломались картинки)
Алсо придерусь немного к английскому, в порядке исключения:
> add to your ... next code:
add the following code to your ...
В общем пока мое мнение: не нужно, надо просто сделать в проекте класс который будет вызывать WideImage с требуемыми настройками. Если это виджет с неизвестными заранее размерами то эти размеры надо сделать свойствами виджета и передавать ниже лежащей библиотеке. Зачем может понадобиться использовать несколько библиотек для уменьшения картинок, мне неясно.
Вот тут я не уверен, какой смысл делать библиотеку работы с картинками заменяемой? Это позволит генерировать превьюшки разных видов? Нет, не позволит, как я понимаю, какую бы ты библиотеку не использовал, результат одинаков. А зачем тогда это нужно? Выбери сам лучшую и используй ее.
АПИ адаптера не очень удачное:
> merge($background, $overlay, $left, $top, $opacity = 100);
А если мы хотим прижать ватермарк к правому краю? Нам было бы удобнее указать расстояние от него чем высчитывать отступ слева.
> public function getWidth($image);
> public function getHeight($image);
> public function resizeDown($image, $width = null, $height = null);
У тебя нет ощущения что логичнее было бы так:
$image->getWidth();
$image->getHeight();
$image->resizeDown(....);
Но это не самое важное, самое важное - это вопрос:
какие возможности добавляет твоя библиотека? Почему я должен взять ее, а не WideImage? На первый взгляд это просто обертка которая передает вызовы библиотеке. Единственное, что я вижу, что она предоставляет адаптеры с единым интерфейсом к разным библиотекам, но я не уверен что это нам нужно.
Еще я вижу что там заданы размер и цвет фона по умолчанию, но это как раз делает библиотеку не универсальной, а заточенной под один конкретный проект. Мне кажется, эти настройки должны быть в проекте, исплоьзующем библиотеку, иначе это какая-то неправильная библиотека. Хорошая библиотека не знает ничего об использующих ее проектах (как класс не знает про своих наследников).
Ну и это наверно не совсем по теме, но почитай (если ты еще не читал) статью про выпечку хлеба: https://habrahabr.ru/post/153225/ (хотя там по моему сломались картинки)
Алсо придерусь немного к английскому, в порядке исключения:
> add to your ... next code:
add the following code to your ...
В общем пока мое мнение: не нужно, надо просто сделать в проекте класс который будет вызывать WideImage с требуемыми настройками. Если это виджет с неизвестными заранее размерами то эти размеры надо сделать свойствами виджета и передавать ниже лежащей библиотеке. Зачем может понадобиться использовать несколько библиотек для уменьшения картинок, мне неясно.
Попробуй порешать наши задачи, показывать решения, исправлять замечания - я уверен, что будет прогресс. Тем более что ты не совсем начинающий, тебе легче чем другим. Вуз вузу рознь, если тебя интересуют информационные технологии, то надо искать такие программы: https://park.mail.ru/pages/index/ или например ШАД Яндекса. Ну и есть большая разница, сдавать зачеты или сидеть разбираться в заданиях.
>>628704
Названия неудачные и затрудняют чтение кода.
$totalAr -> $girls, $positions (и не пиши слово array в названии переменной, и тем более не сокращай его)
$e -> $number, $current
as $k => $v -> $key => $position
Заполнение массива проще сделать функцией range (или хотя бы циклом for).
В остальном верно.
>>628710
Обычно это появляется если ты указываешь неправильную версию или указываешь 2 пакета, которым нужен один и тот же пакет, но разной версии.
Покажи свой composer.json и что выводится, там должны быть подробности какие именно пакеты не удалось найти.
>>628770
Убунта и на реальном железе подтормаживает. В случае с виртуалкой надо обязательно дать убунте доступ к аппаратному ускорению на видеокарте, для этого обычно нужно установить в убунту дополнения от виртуалбокса (в виртуалбокс уже встроен диск с ними, или их может можно как-то через установку пакетов поставить). Без них виртуальная видеокарта работает в каком-то слоупочном режиме и не может использовать ускорение, а у Убунты интерфейс без аппаратного ускорения не работает нормально.
>>628775
Все правильно!
Верно.
Тут тоже верно.
Верно, но тут
> $anonDice1 + $anonDice2) > ($compDice1 + $compDice2))
можно было использовать compSum/anonSum, и иф принято писать с маленькой букв.
>>628800
Молодец, верно.
Попробуй порешать наши задачи, показывать решения, исправлять замечания - я уверен, что будет прогресс. Тем более что ты не совсем начинающий, тебе легче чем другим. Вуз вузу рознь, если тебя интересуют информационные технологии, то надо искать такие программы: https://park.mail.ru/pages/index/ или например ШАД Яндекса. Ну и есть большая разница, сдавать зачеты или сидеть разбираться в заданиях.
>>628704
Названия неудачные и затрудняют чтение кода.
$totalAr -> $girls, $positions (и не пиши слово array в названии переменной, и тем более не сокращай его)
$e -> $number, $current
as $k => $v -> $key => $position
Заполнение массива проще сделать функцией range (или хотя бы циклом for).
В остальном верно.
>>628710
Обычно это появляется если ты указываешь неправильную версию или указываешь 2 пакета, которым нужен один и тот же пакет, но разной версии.
Покажи свой composer.json и что выводится, там должны быть подробности какие именно пакеты не удалось найти.
>>628770
Убунта и на реальном железе подтормаживает. В случае с виртуалкой надо обязательно дать убунте доступ к аппаратному ускорению на видеокарте, для этого обычно нужно установить в убунту дополнения от виртуалбокса (в виртуалбокс уже встроен диск с ними, или их может можно как-то через установку пакетов поставить). Без них виртуальная видеокарта работает в каком-то слоупочном режиме и не может использовать ускорение, а у Убунты интерфейс без аппаратного ускорения не работает нормально.
>>628775
Все правильно!
Верно.
Тут тоже верно.
Верно, но тут
> $anonDice1 + $anonDice2) > ($compDice1 + $compDice2))
можно было использовать compSum/anonSum, и иф принято писать с маленькой букв.
>>628800
Молодец, верно.
О, интересно, но можно улучшить код:
> elseif ($height == $anonHeight) {
Лучше просто else без условия
> foreach ($ending as $keys => $value){
> foreach ($value as $i => $o) {
Какие плохие и нечитаемые имена переменных:
keys -> word
value -> digits
o -> digit
as $i -> убрать
Да и код трудно понять. Такие вещи обычео пишут через операцию деления с остатком:
if ($x % 10 == 1) ...
Ну и алгоритм неверный, твой код для числа 12 напишет "12 человека". Числа от 11 до 19 идут как исключение (видимо древнию люди умели считать только до 20).
А еще, не хочешь число человек через array_filter? Это тоже интересно будет, если ты конечно знаешь анонимные функции.
>>628913
Твой код работает только пока сайтом пользуется 1 человек с 1 браузером, не удаляет куки и не отходит от компьютера больше чем на 15 минут. Это особенности сессий.
>>628914
Для каждого пользователя создается файл на сервере, данные хранятся в нем, а у пользователя в куке идентификатор (часть имени) этого файла. По куке сервер находит файл с данными этого пользователя. Не используемые 20-30 минут файлы на сервере удаляются.
>>628977
Решение покажешь?
О, интересно, но можно улучшить код:
> elseif ($height == $anonHeight) {
Лучше просто else без условия
> foreach ($ending as $keys => $value){
> foreach ($value as $i => $o) {
Какие плохие и нечитаемые имена переменных:
keys -> word
value -> digits
o -> digit
as $i -> убрать
Да и код трудно понять. Такие вещи обычео пишут через операцию деления с остатком:
if ($x % 10 == 1) ...
Ну и алгоритм неверный, твой код для числа 12 напишет "12 человека". Числа от 11 до 19 идут как исключение (видимо древнию люди умели считать только до 20).
А еще, не хочешь число человек через array_filter? Это тоже интересно будет, если ты конечно знаешь анонимные функции.
>>628913
Твой код работает только пока сайтом пользуется 1 человек с 1 браузером, не удаляет куки и не отходит от компьютера больше чем на 15 минут. Это особенности сессий.
>>628914
Для каждого пользователя создается файл на сервере, данные хранятся в нем, а у пользователя в куке идентификатор (часть имени) этого файла. По куке сервер находит файл с данными этого пользователя. Не используемые 20-30 минут файлы на сервере удаляются.
>>628977
Решение покажешь?
Файлы names/surnames лучше убрать в папку, например data.
> name text NOT NULL,
> surname text NOT NULL,
Тут надо varchar с разумным ограничением длины. Тебе надо прочитать в мануале главу про типы колонок (всю!) и выучить названия не менее 5 разных типов (INT и BIGINT считаются за один). Также, ответь на вопрос, в чем разница между REAL и NUMERIC? Где может пригодиться нумерик? Какой тип использовать для хранения телефонного номера? Номера паспорта?
> status text NOT NULL,
> gender text NOT NULL,
Тут нужен enum (который судя по документации в постгрессе даже лучше чем в майскул: http://www.postgresql.org/docs/9.1/static/datatype-enum.html , перевод http://postgresql.ru.net/manual/datatype-enum.html )
> sgroup text NOT NULL,
> email text NOT NULL,
варчар нужен
> byear text NOT NULL,
В майскул есть тип YEAR, а в пострес нужен либо инт, либо децимал (для него можно задать длину).
Также, в постргресе есть очень крутая штука, ограничение на значение поля CHECK: http://postgresql.ru.net/manual/ddl-constraints.html#AEN2554
Пройдись по таблицам и проставь ограничения там где это уместно. Ограничения защищают базу от неправильных данных, экономят твое время, облегчают понимание ее структуры.
Для уникальных полей надо поставить соответствующее ограничение.
> CREATE TABLE tokens (
А почему отдельной таблицей? И почему нет внешнего ключа? И почему ид текстом?
Также, я вижу ты не очень знаешь SQL, советую порешать задачи на него из ОП-поста.
> CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog;
> REVOKE ALL ON SCHEMA public FROM PUBLIC;
> REVOKE ALL ON SCHEMA public FROM postgres;
Это не надо включать в дамп. Имя базы данных также нежелательно указывать, так как нельзя загрузить дамп в другую базу.
https://github.com/foobar1643/student-list/blob/master/public/design/template/form.html
Это не должно быть в публичной папке, так как это код, не предназначеннный для вызова пользователем напрямую.
https://github.com/foobar1643/student-list/blob/master/app/AutoLoader.php
Не надо копипастить, копипаста - зло, сделай список путей в массиве, и их перебор в автозагрузчике. Более того, если указать эти папки в include_path то можно использовать встроенный в пхп автозагрузчик spl_autoload (детали в мануале).
А лучше конечно освой неймспейсы, урок https://github.com/codedokode/pasta/blob/master/php/autoload.md
> https://github.com/foobar1643/student-list/blob/master/app/AppCore.php#L11
> $this->view_settings = new stdClass();
Тут нужен массив. Объекты это не массивы, для массивов есть куча вспомогательных функций.
> } catch(PDOException $e) {
> print("Database connection error. " . $e->getMessage()
Неправильная работа с исклчениями. ВОт паста.
--------
Как надо обрабатывать исключения:
- записать информацию в лог
- показать пользователю заглушку
- на заглушке выставить HTTP 503 код ответа для роботов
- на компьютере разработчика (при display_errors = 1) показать подробности и стектрейс
Как сделано у тебя:
- в лог ничего не фиксируется, ты не узнаешь об ошибках
- пользователь видит непонятную белиберду на английском
- отдается код 200
Как будет если просто не ловить исключение:
- информация пишется в лог (ок)
- на компьютере разработчика выводятся подробности (ок)
- пользователь видит белую страницу (не ок)
- отдается код 200 (не ок)
Но даже так лучше чем твой вариант.
Почитай также урок https://gist.github.com/codedokode/65d43ca5ac95c762bc1a
------------
Неправильно что ты создаешь PDO в контроллере. Заечм он там? Его надо создавать например в файле bootstrap.php одитн раз и использовать для создания классов работающих с БД. А ты в каждом контроллере создаешь свой ПДО.
Название странное AppCore. Что еще за коре? Это базовый класс контродлера, ControllerBase.
> protected $connection_error;
Зачем поле? Зачем хранить строку с ошибкой?
> $this->view_settings->page_data = new stdClass();
> $this->view_settings->error = array();
> $this->view_settings->page_data->student = array();
Не очень понятно зачем это. Например зачем в базовом классе создавать поле student - он нужен на всех страницах? И что значит page_data? Название ничего не говорит мне.
> https://github.com/foobar1643/student-list/blob/master/app/Controller/ControllerIndex.php
> private $pager;
> private $total_pages;
> private $offset;
> private $sorting_pattern;
Зачем их делать полями? Тебе надо эти значения сохранять между вызовами?
> process_get_request
У нас в пхп в рекомендации PSR принято функции и переменные именовать кемел кейсом: processGetRequest()
> if($get_data['page']
А если нет гет-параметра page то мы получаем ошибку доступа к несуществующему элементу массива? У тебя включено отображения ошибок? Ты видишь, что они есть? Если нет, выставь error_reporting = -1, display_errors = On в php.ini у себя локально.
> $index = array_search($get_data['sort'], $this->sorting_patterns);
> if($this->sorting_patterns[$index]) {
Тут нужен in_array()
Также, не вижу смысла разделять контроллер на process_get_request и run, так как непонятно по какому принципу код разделен на 2 части. Лучше сделать одну функцию.
https://github.com/foobar1643/student-list/blob/master/app/View/ViewIndex.php
Не очень понятен смысл этого класса, не проще ли этот код поместить в контроллер?
https://github.com/foobar1643/student-list/blob/master/app/AppConfig.php
Конфиг лучше сделать обычным php- или ini-файлом:
$config['x'] = 1;
или
[db]
host=localhost
username = 1
https://github.com/foobar1643/student-list/blob/master/public/design/template/form.html#L2
> Проверьте правильность вводимых данных и попробуйте еще раз.
А где текст ошибки?
https://github.com/foobar1643/student-list/blob/master/public/design/template/form.html#L23
Вместо print надо использовать <?= ... ?>. Также, нужна защита от XSS (htmlspecialchars). У меня есть урок. Также нужна клиентская HTML5 валидация.
https://github.com/foobar1643/student-list/blob/master/app/Controller/ControllerForm.php#L28
> $this->student->name = $this->form_validator->process_field($post_data["name_field"]);
htmlspecialchars надо делать только при выводе данных. Зачем ты в базу данных вставляешь данные в HTML виде? Надо хранить в базе исходыне неискаженные данные.
Работу с авторизацией и токенами надо вынести в отдельный класс.
https://github.com/foobar1643/student-list/blob/master/app/Controller/ControllerForm.php#L43
> header("Location: form.php?notify=success"); /
После этого не надо выводить страницу. Ее все равно никто не увидит.
Файлы names/surnames лучше убрать в папку, например data.
> name text NOT NULL,
> surname text NOT NULL,
Тут надо varchar с разумным ограничением длины. Тебе надо прочитать в мануале главу про типы колонок (всю!) и выучить названия не менее 5 разных типов (INT и BIGINT считаются за один). Также, ответь на вопрос, в чем разница между REAL и NUMERIC? Где может пригодиться нумерик? Какой тип использовать для хранения телефонного номера? Номера паспорта?
> status text NOT NULL,
> gender text NOT NULL,
Тут нужен enum (который судя по документации в постгрессе даже лучше чем в майскул: http://www.postgresql.org/docs/9.1/static/datatype-enum.html , перевод http://postgresql.ru.net/manual/datatype-enum.html )
> sgroup text NOT NULL,
> email text NOT NULL,
варчар нужен
> byear text NOT NULL,
В майскул есть тип YEAR, а в пострес нужен либо инт, либо децимал (для него можно задать длину).
Также, в постргресе есть очень крутая штука, ограничение на значение поля CHECK: http://postgresql.ru.net/manual/ddl-constraints.html#AEN2554
Пройдись по таблицам и проставь ограничения там где это уместно. Ограничения защищают базу от неправильных данных, экономят твое время, облегчают понимание ее структуры.
Для уникальных полей надо поставить соответствующее ограничение.
> CREATE TABLE tokens (
А почему отдельной таблицей? И почему нет внешнего ключа? И почему ид текстом?
Также, я вижу ты не очень знаешь SQL, советую порешать задачи на него из ОП-поста.
> CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog;
> REVOKE ALL ON SCHEMA public FROM PUBLIC;
> REVOKE ALL ON SCHEMA public FROM postgres;
Это не надо включать в дамп. Имя базы данных также нежелательно указывать, так как нельзя загрузить дамп в другую базу.
https://github.com/foobar1643/student-list/blob/master/public/design/template/form.html
Это не должно быть в публичной папке, так как это код, не предназначеннный для вызова пользователем напрямую.
https://github.com/foobar1643/student-list/blob/master/app/AutoLoader.php
Не надо копипастить, копипаста - зло, сделай список путей в массиве, и их перебор в автозагрузчике. Более того, если указать эти папки в include_path то можно использовать встроенный в пхп автозагрузчик spl_autoload (детали в мануале).
А лучше конечно освой неймспейсы, урок https://github.com/codedokode/pasta/blob/master/php/autoload.md
> https://github.com/foobar1643/student-list/blob/master/app/AppCore.php#L11
> $this->view_settings = new stdClass();
Тут нужен массив. Объекты это не массивы, для массивов есть куча вспомогательных функций.
> } catch(PDOException $e) {
> print("Database connection error. " . $e->getMessage()
Неправильная работа с исклчениями. ВОт паста.
--------
Как надо обрабатывать исключения:
- записать информацию в лог
- показать пользователю заглушку
- на заглушке выставить HTTP 503 код ответа для роботов
- на компьютере разработчика (при display_errors = 1) показать подробности и стектрейс
Как сделано у тебя:
- в лог ничего не фиксируется, ты не узнаешь об ошибках
- пользователь видит непонятную белиберду на английском
- отдается код 200
Как будет если просто не ловить исключение:
- информация пишется в лог (ок)
- на компьютере разработчика выводятся подробности (ок)
- пользователь видит белую страницу (не ок)
- отдается код 200 (не ок)
Но даже так лучше чем твой вариант.
Почитай также урок https://gist.github.com/codedokode/65d43ca5ac95c762bc1a
------------
Неправильно что ты создаешь PDO в контроллере. Заечм он там? Его надо создавать например в файле bootstrap.php одитн раз и использовать для создания классов работающих с БД. А ты в каждом контроллере создаешь свой ПДО.
Название странное AppCore. Что еще за коре? Это базовый класс контродлера, ControllerBase.
> protected $connection_error;
Зачем поле? Зачем хранить строку с ошибкой?
> $this->view_settings->page_data = new stdClass();
> $this->view_settings->error = array();
> $this->view_settings->page_data->student = array();
Не очень понятно зачем это. Например зачем в базовом классе создавать поле student - он нужен на всех страницах? И что значит page_data? Название ничего не говорит мне.
> https://github.com/foobar1643/student-list/blob/master/app/Controller/ControllerIndex.php
> private $pager;
> private $total_pages;
> private $offset;
> private $sorting_pattern;
Зачем их делать полями? Тебе надо эти значения сохранять между вызовами?
> process_get_request
У нас в пхп в рекомендации PSR принято функции и переменные именовать кемел кейсом: processGetRequest()
> if($get_data['page']
А если нет гет-параметра page то мы получаем ошибку доступа к несуществующему элементу массива? У тебя включено отображения ошибок? Ты видишь, что они есть? Если нет, выставь error_reporting = -1, display_errors = On в php.ini у себя локально.
> $index = array_search($get_data['sort'], $this->sorting_patterns);
> if($this->sorting_patterns[$index]) {
Тут нужен in_array()
Также, не вижу смысла разделять контроллер на process_get_request и run, так как непонятно по какому принципу код разделен на 2 части. Лучше сделать одну функцию.
https://github.com/foobar1643/student-list/blob/master/app/View/ViewIndex.php
Не очень понятен смысл этого класса, не проще ли этот код поместить в контроллер?
https://github.com/foobar1643/student-list/blob/master/app/AppConfig.php
Конфиг лучше сделать обычным php- или ini-файлом:
$config['x'] = 1;
или
[db]
host=localhost
username = 1
https://github.com/foobar1643/student-list/blob/master/public/design/template/form.html#L2
> Проверьте правильность вводимых данных и попробуйте еще раз.
А где текст ошибки?
https://github.com/foobar1643/student-list/blob/master/public/design/template/form.html#L23
Вместо print надо использовать <?= ... ?>. Также, нужна защита от XSS (htmlspecialchars). У меня есть урок. Также нужна клиентская HTML5 валидация.
https://github.com/foobar1643/student-list/blob/master/app/Controller/ControllerForm.php#L28
> $this->student->name = $this->form_validator->process_field($post_data["name_field"]);
htmlspecialchars надо делать только при выводе данных. Зачем ты в базу данных вставляешь данные в HTML виде? Надо хранить в базе исходыне неискаженные данные.
Работу с авторизацией и токенами надо вынести в отдельный класс.
https://github.com/foobar1643/student-list/blob/master/app/Controller/ControllerForm.php#L43
> header("Location: form.php?notify=success"); /
После этого не надо выводить страницу. Ее все равно никто не увидит.
Бля, это та картинка, где она говорит: "Ну как, в очках я выгляжу умной?))". Как раз та причина, по которой я не хочу линзы, а люблю очки))
Если не шаришь то придется начать с изучения языка. Это тред изучения пхп, а не выполнения чужой работы бесплатно.
>>629158
Не, надо знать раза в 2-3 боьше чем ты перечислил, ветки еще, мерджи, конфликты, пул/пуш. Советую почитать git-book, есть на русском и там достаточно просто все.
>>629279
Для этого надо знать языки HTML, CSS, JS, PHP, работу с базой данных. Довольно много знаний надо.
> посоветовали бесплатное амазноновское хранилище.
Оно не бесплатное. Особенно с нынешним-то курсом.
>>629285
> private function chooseProfession($post) {
Надо убрать отсюда так как это не позволит добавлять профессии не трогая старые классы. Также, у тебя не проверяется в свитче вариант если указана неправильная профессия, это плохо.
> public function countTotalSalary($qty, $rank, $post, $boss) {
Это не очень правльная функция, должно быть так:
public function countTotalSalary() { ... }
то есть не требюуется указывать никаких аргументов, у нас ведь департамент сам знает кто в нем состоит, какие у них должности и тд.
> abstract class Employee extends Department {
Абсолютно неправильное наследование. Наследование - это создание одного класса на основе другого, когда мы хотим изменить поведение или сделать улучшенную версию чего-то. Ну к примеру мы можем создать класс Транспорт с методом переместиться(), а от него унаследовать Машину, Самолет и Велосипед в которых этот метод реализован по-разному.
У тебя же неправильно: Сотрудник это не разновидност Департамента, значит наследование использовать так нельзя.
> class Manager extends Employee {
> protected function countSalary() {
Ты скопипастил тут код 4 раза.
>>629306
Будем считать этот косяк ОПа тестом на сообразительность.
Если не шаришь то придется начать с изучения языка. Это тред изучения пхп, а не выполнения чужой работы бесплатно.
>>629158
Не, надо знать раза в 2-3 боьше чем ты перечислил, ветки еще, мерджи, конфликты, пул/пуш. Советую почитать git-book, есть на русском и там достаточно просто все.
>>629279
Для этого надо знать языки HTML, CSS, JS, PHP, работу с базой данных. Довольно много знаний надо.
> посоветовали бесплатное амазноновское хранилище.
Оно не бесплатное. Особенно с нынешним-то курсом.
>>629285
> private function chooseProfession($post) {
Надо убрать отсюда так как это не позволит добавлять профессии не трогая старые классы. Также, у тебя не проверяется в свитче вариант если указана неправильная профессия, это плохо.
> public function countTotalSalary($qty, $rank, $post, $boss) {
Это не очень правльная функция, должно быть так:
public function countTotalSalary() { ... }
то есть не требюуется указывать никаких аргументов, у нас ведь департамент сам знает кто в нем состоит, какие у них должности и тд.
> abstract class Employee extends Department {
Абсолютно неправильное наследование. Наследование - это создание одного класса на основе другого, когда мы хотим изменить поведение или сделать улучшенную версию чего-то. Ну к примеру мы можем создать класс Транспорт с методом переместиться(), а от него унаследовать Машину, Самолет и Велосипед в которых этот метод реализован по-разному.
У тебя же неправильно: Сотрудник это не разновидност Департамента, значит наследование использовать так нельзя.
> class Manager extends Employee {
> protected function countSalary() {
Ты скопипастил тут код 4 раза.
>>629306
Будем считать этот косяк ОПа тестом на сообразительность.
Первый файл открыл и сразу ахуел. Что у тебя кол-во элементов на странице в КОНФИГЕ ДБ делает, дурень?
Этот параметр должен быть в классе Pager.
У мамки на шее сидишь?
$dsn = AppConfig::db_type . ":dbname=" . AppConfig::db_name . ";host=" . AppConfig::db_host; //"pgsql:dbname=students;host=127.0.0.1"
try {
$this->pdo = new PDO($dsn, AppConfig::db_user, AppConfig::db_pswd);
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch(PDOException $e) {
print("Database connection error. " . $e->getMessage());
exit();
}
И класс работы с бд должен лежать отдельно и называться Data Mapper, а не в вперемешку с моделями. И что там за работа с файлом тхт, зачем это?
Вот в этот лучше массив записать, а не повторять, как быдлокодер. И зачем ты exit() везде пишешь? лол, нуб.
$this->student->id = $this->form_validator->process_field($post_data["id_field"]);
$this->student->name = $this->form_validator->process_field($post_data["name_field"]);
$this->student->surname = $this->form_validator->process_field($post_data["surname_field"]);
$this->student->gender = $this->form_validator->process_field($post_data["gender_field"]);
$this->student->group = $this->form_validator->process_field($post_data["group_field"]);
$this->student->email = $this->form_validator->process_field($post_data["email_field"]);
$this->student->byear = $this->form_validator->process_field($post_data["byear_field"]);
$this->student->status = $this->form_validator->process_field($post_data["status_field"]);
$this->student->rating = $this->form_validator->process_field($post_data["rating_field"]);
И кто так пишет? не нужно столько вложенных методов или что там.
$this->view_settings->page_data->next_page
>$dsn = AppConfig::db_type . ":dbname=" . AppConfig::db_name . ";host=" . AppConfig::db_host; //"pgsql:dbname=students;host=127.0.0.1"
>try {
>$this->pdo = new PDO($dsn, AppConfig::db_user, AppConfig::db_pswd);
Я про это.
Нет, ты не прав. Это может быть не конфиг ДБ, а конфиг приложения (посмотри на название) и может быть он хочет разрешить администратору настраивать число элементов на странице.
>>632597
Не, лучше не использовать класс для конфига. Ведь по идее конфиг предназначен для не-программистов и стоит испольозовать что-то попроще, например ini, xml, json, yml, на худой конец пхп файл с переменными. Идея конфига чтобы вынести настройки из кода. А тут они и не вынесены.
И константы надо писать большими буквами. Слова разделять через подчеркивания.
>>632600
НЕт, TDG это нормальное название, это паттерн такой. https://github.com/codedokode/pasta/blob/master/db/patterns-oop.md
Ну и это первая попытка анона, так что это нормально. И не надо резкие выражения использовать.
Нет, мы тоже поможем.
>>631726
На мой взгляд они не уродливые, стандартные элементы лучше всего (ты ведь как-то терпишь их в других программах, и можешь менять с помощью тем для твоей ОС), а вообще есть возможность кастомизации. Что хорошего когда один и тот же элемент везде выглядит по-разному?
> 2. Насколько уместно в глобальном CSS (через Stylish) добавлять проверку на имена/классы? Например чтобы ютуб не ломался от background-color как на прирепленом скрине.
Не знаю. С классами наверно проблем не должно быть, так как движок ксс под них может быть оптимизирован, они везде использованы. Но это надо мерять.
> Насколько в целом бьёт по производительности? Если есть опыт, пишите браузер
Не знаю, надо делать измерения (например сравнивать время и потребление памяти со стилями и без или с плагином и без). Вообще, по моим ощущениям фаерфакс сам по себе не очень быстрый, а с расширениями и того медленнее.
>И класс работы с бд должен лежать отдельно
Сделаю.
>и называться Data Mapper
В условии задачи не DataMapper, а TableDataGateway
>И что там за работа с файлом тхт, зачем это?
Заполнитель базы данных новыми записями, чтобы вручную не вводить. Делал для тестирования поиска и постраничной навигации, решил оставить.
>Вот в этот лучше массив записать, а не повторять, как быдлокодер
Мне это тоже не понравилось, но заполнять объект Student циклом я не хотел (по понятным причинам). Попробую что-нибудь с этим сделать.
>И зачем ты exit() везде пишешь?
Это последствия того, что я не знал как правильно обрабатывать исключения. Тоже переделаю.
Спасибо за помощь.
http://pastebin.com/Nb3nztp9
Зависит от человека, есть такие, что дропают по 20 раз в процессе и потом наверстывают, есть такие что не от фрустрации бросают вовсе.
Зависит от твоих текущих знаний. Список необходимых технологий для джуниора можно задрочить и за три месяца (это если ты вообще ничего не знаешь), если ты каждый день по 8 - 10 часов будешь учить. А если размазать на 3 часа в день + выходные, тогда полгода-год, да.
>Сколько там последний срок по возрасту последний шанс вкатиться?
Такого нет. Я знал людей которые в 27 - 28 начинали джуниорами работать. Им уже за 30, один стал тимлидом, другой синьером в каком-то Московском бодишопе.
Успех уровня /pr/, ага.
В этом то и по сути основная проблема. Буду гнаться за двумя зайцами, потом на одного забью.
В зависимости от того, что админишь - линукс или серверную венду.
Энивей, вангую что поциент сверху - типичный втыкатель мышек.
Ты это, не бухти, тут и люди с похуже данными входными есть, а ты сразу "поздно".
25-лвл, экономист-кун
Вот же у него прямо в валидаторе метод работы с ДБ запихан, никакого принципа солид.
https://github.com/foobar1643/student-list/blob/master/app/FormValidator.php
В местных вакансиях написано, что чуть ли не телефонию надо уметь прокладывать, чинить оргтехнику и знать TCP-протоколы. Я один раз звонил, спросили: как вы будете работать сисадмином, если у вас опыта нет?
Так надо было сказать что опыт есть. А потом уже по ходу дела научился бы телефонию прокладывать и чиить оргтехнику.
>= $this->form_validator->process_field($post_data["id_field"]);
А что это вообще обозначает? Это ты так пост запрос принял что ли? конструкция прост слишком длинная, выглядит некрасиво. Для валидации лучше передавать данные массивом или через экземпляр класса.
У меня вот такой класс для PDO.
class Db {
private static $instance = null;
public static function get()
{
if(self::$instance == null)
{
try
{
self::$instance = new PDO('mysql:host=localhost;dbname=guestbook;charset=utf8', 'root', '');
self::$instance->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch(PDOException $e)
{
echo $e->getMessage();
}
}
return self::$instance;
}
}
Лучше вынести имя, пароль и название дб в конфиг константы и потом подставлять их таким же методом в этот класс?
AppConfig::db_type . ":dbname=" . AppConfig::db_name . ";host=" . AppConfig::db_host;
У меня вот такой класс для PDO.
class Db {
private static $instance = null;
public static function get()
{
if(self::$instance == null)
{
try
{
self::$instance = new PDO('mysql:host=localhost;dbname=guestbook;charset=utf8', 'root', '');
self::$instance->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch(PDOException $e)
{
echo $e->getMessage();
}
}
return self::$instance;
}
}
Лучше вынести имя, пароль и название дб в конфиг константы и потом подставлять их таким же методом в этот класс?
AppConfig::db_type . ":dbname=" . AppConfig::db_name . ";host=" . AppConfig::db_host;
>Лучше вынести имя, пароль и название дб в конфиг константы
Нет. ОП выше писал что константами хранить не стоит. Конфиг должен быть в .ini, .txt или в крайнем случае в php формате ($config['x'] = y), чтобы любой не программист смог легко отредактировать данные.
> какой смысл делать библиотеку работы с картинками заменяемой
Чтобы иметь возможность заменить одну библиотеку для работы с графикой на другую.
Может она устареет через 3-4 года? Может мне ночальники без аргументации прикажут "WideImage говно, юзай Imagine" (хотя такая ситуация ближе сосачу а не IRL).
В приложении мне понадобится поменять одну строчку кода (заменить new WideImageAdapter на другой), плюс дописать эту обертку-адаптер, если она еще не включена в основной пакет, а она скорее всего будет включена.
Аналогичные врапперы для работы с клиентами редис мы с тобой писали. Почему там нужно было выносить в модуль, а здесь нет?
>У тебя нет ощущения что логичнее было бы так:
>$image->getWidth();
>вместо
>$adapter->getWidth($image)
Нет такого ощущения. Я не знаком с другими графическими библиотеками, но там этот метод может называться по-другому, или принадлежать другому объекту, не $image.
В конце концов в качестве $image можно использовать вовсе не объект, а ресурс. Тогда getWidth адаптера будет вызывать уже не метод объекта, а функцию типа imagesx.
Пока не убедил короче. Мне кажется суть ООП в том, чтобы разбивать код на логические составляющие, каждая из которых занимается своим делом и ничего не знает об общей логике приложения, чтобы можно было без последствий переписать отдельный модуль/класс/метод. Я слышал, что у симфони например вообще любой компонент можно использовать вне фреймворка, как отдельный пакет.
>зачем это нужно
Чтобы попрактиковать ооп.
Посмотри еще верстку
https://jsfiddle.net/tLwp60qh/3/
похоже на 8 задание. Во всяком случае я использовал тот же трюк с большим левым полем-паддингом и отрицательным марджином для превью.
Семантичны ли теги типа strong/small, или использовать css для этих целей? Уместно ли абсолютное позиционирование, или это дурной тон (мало ли)?
>Решение покажешь?
Обязательно!
Но у меня пока три разных решения: для первых 999 с возвратом "рублей", для тысяч с возвратом "тысяч" и для миллионов с возвратом "миллионов".
Сейчас вот думаю, как всё соединить. Но это уже не так всё сложно, хотя код разросся катастрофически. Чую - ругать и поносить последними словами меня будешь...
Вообще изначально неправильно начал делать через преобразование числа в строку и подсчёт количества символов в ней.
Куча повторяющегося кода, который, правда, убрал в функции, куча условий - можно запутаться. Ты, братишка-ОП, такое не одобряешь. Но я часто сначала делаю говнокодом, а потом преобразую в более-менее человеческое.
На первом же часу работы над задачей понял, что решать её надо делением чисел на 10, 100, 1000 - и так до 100 миллионов с последующим округлением, однако продолжил именно с преобразованием в строку.
Потом попробую и так.
Я никуда не тороплюсь, мне это нравится.
Я вообще забалдел от самого твоего учебника, не хочу ничего пропускать.
Бамп вопросу, есть ли общее какое-нибудь решение?
Ее
1) Ксс в бутстрапе генерируется по моему из ЛЕСС файла. Измени исходники и скомпилируй свою версию бутстрапа, с нужными тебе параметрами сетки.
2) поиграй с параметрами теги meta viewport, может там модно задать минимальную ширину вьюпорта. Но то что ты делаешь это глупость так как при адаптивной верстке сайт должен работать на любой ширине страницы, а ты фактически для пользователей смартфонов и вертикальных планшетов делаешь сайт не адаптивным.
Ну он начинающий. Наша цель не критиковать людей (какая от этого выгода?), а помогать им сделать код лучше. Если ты не знаешь как сделать лучше, но чувствуешь что что-то не так, то так и пиши, "мне кажется это сделано не очень правильно потому-то потому-то".
Конечно, там есть еще архитектурные ошибки, но мы их постепенно все найдем и исправим. Я написал только то, что успел, там и так большой список вышел.
Что касается валидатора, это анон перепутал, он функцию экранирования спецсимволов в хтмл (htmlspecialchars) вызывает не в шаблоне, а в контроллере. Еще и назвал неудачно, "process_field" вместо escapeHtmlCharacters, и объединил с полезными функциями trim/strval (которые как раз вызываются из контроллера). Не беда, многие начинающие делают такую ошибку, и что хуже, в некоторых курсах советуют так делать. Вот паста с описанием уязвимости XSS и как с ней бороться:
https://github.com/codedokode/pasta/blob/master/security/xss.md
Ну и урок про работу с формами тоже может пригодится: https://github.com/codedokode/pasta/blob/master/forms.md
А объясни, в чем смысл твоего класса? Я вижу, что он использует ПДО, а какие возможности он к нему добавляет? Зачем нужен этот твой класс? Нельзя ли объект ПДО напрямую использовать без него?
> Может она устареет через 3-4 года
Ну поменяешь код в своем классе. Может устареет, а может и нет. Да и даже если она устареет, она ведь по-прежнему будет уменьшать картинки.
В случае со счетчиком просмотров польза адаптеров видна - чтобы можно были код использовать с разными фреймворками, интегрировать в любое существующее приложение. Чтобы счетчик использовал существующие соединения, чтобы он использовал заданные в приложении для них настройки. Без адаптеров пришлось бы делать отдельное соединение с базой и редисом, неудобно.
Тут по моему другая ситуация. Счетчик добавляет в приложение дополнительный функционал, а что добавляет эта библиотека, непонятно. Почему бы сразу не подключить WideImage или любую другую библиотеку без лишних прослоек?
Главные проблемы такие:
- библиотека не универсальна, а явно завязана на определенный проект. В ней небольшое число функций и прописаны конкретные значения для размеров картинки, конкретный алгоритм наложения ватермарок. Библиотеки так не делаются.
- непонятно в чем ее ценность, она не добавляет дополнительного функционала (пока я вижу только возможность менять библиотеки работы с картинками. Причем при использовании твоего адаптера мы получаем ограниченный функционал из нижележащей библиотеки)
Потому как я и написал выше, это должен быть просто класс в твоем приложении без адпатеров. Либо, если ты хочешь сделать именно библиотеку-адаптер для унификации интерфейса классов работы с картинками, то надо так ее и позиционировать и убрать все, что относится к твоему приложению, размеры превьюшки например. Сделать более универсальный и удобный в использовании метод наложения превьюшек, не привязанный к левому верхнему краю.
Ну и погуглить, может же что-то такое есть.
> В конце концов в качестве $image можно использовать вовсе не объект, а ресурс. Тогда getWidth адаптера будет вызывать уже не метод объекта, а функцию типа imagesx.
Это потому что у тебя в базовом классе не указан тип, возвращемый функцией load. Укажи его, и ресурс уже вернуть будет нельзя. Конечно, до PHP7 указывать тип возврата нельзя, но семерка уже выпущена, да и в "правильном" ООП этот тип должен быть определен, пусть даже через phpDoc.
ИЗображение тут явно выглядит как объект. Я считаю, ради ресурсов отказываться от ООП подхода неправильно. Проще ресурс обернуть в класс и тогда на нем тоже можно будет делать $image->getWidth(). А передавать $image в каждый метод как раз напоминает больше процедурный, а не ООП подход.
> Я слышал, что у симфони например вообще любой компонент можно использовать вне фреймворка, как отдельный пакет.
Да. Потому что там не прописано никаких фреймворкоспецифичных настроек, и код сделан универсально. И тоже куча адаптеров, кстати.
> Может она устареет через 3-4 года
Ну поменяешь код в своем классе. Может устареет, а может и нет. Да и даже если она устареет, она ведь по-прежнему будет уменьшать картинки.
В случае со счетчиком просмотров польза адаптеров видна - чтобы можно были код использовать с разными фреймворками, интегрировать в любое существующее приложение. Чтобы счетчик использовал существующие соединения, чтобы он использовал заданные в приложении для них настройки. Без адаптеров пришлось бы делать отдельное соединение с базой и редисом, неудобно.
Тут по моему другая ситуация. Счетчик добавляет в приложение дополнительный функционал, а что добавляет эта библиотека, непонятно. Почему бы сразу не подключить WideImage или любую другую библиотеку без лишних прослоек?
Главные проблемы такие:
- библиотека не универсальна, а явно завязана на определенный проект. В ней небольшое число функций и прописаны конкретные значения для размеров картинки, конкретный алгоритм наложения ватермарок. Библиотеки так не делаются.
- непонятно в чем ее ценность, она не добавляет дополнительного функционала (пока я вижу только возможность менять библиотеки работы с картинками. Причем при использовании твоего адаптера мы получаем ограниченный функционал из нижележащей библиотеки)
Потому как я и написал выше, это должен быть просто класс в твоем приложении без адпатеров. Либо, если ты хочешь сделать именно библиотеку-адаптер для унификации интерфейса классов работы с картинками, то надо так ее и позиционировать и убрать все, что относится к твоему приложению, размеры превьюшки например. Сделать более универсальный и удобный в использовании метод наложения превьюшек, не привязанный к левому верхнему краю.
Ну и погуглить, может же что-то такое есть.
> В конце концов в качестве $image можно использовать вовсе не объект, а ресурс. Тогда getWidth адаптера будет вызывать уже не метод объекта, а функцию типа imagesx.
Это потому что у тебя в базовом классе не указан тип, возвращемый функцией load. Укажи его, и ресурс уже вернуть будет нельзя. Конечно, до PHP7 указывать тип возврата нельзя, но семерка уже выпущена, да и в "правильном" ООП этот тип должен быть определен, пусть даже через phpDoc.
ИЗображение тут явно выглядит как объект. Я считаю, ради ресурсов отказываться от ООП подхода неправильно. Проще ресурс обернуть в класс и тогда на нем тоже можно будет делать $image->getWidth(). А передавать $image в каждый метод как раз напоминает больше процедурный, а не ООП подход.
> Я слышал, что у симфони например вообще любой компонент можно использовать вне фреймворка, как отдельный пакет.
Да. Потому что там не прописано никаких фреймворкоспецифичных настроек, и код сделан универсально. И тоже куча адаптеров, кстати.
> <div><strong>Moscow</strong></div>
Такие ошибки:
- зачем-то использовано 2 тега вместо одного (это допустимо если без этого не сверстать, но у тебя по моему простая верстка). Не добавляй лишние элементы.
- в хтмл разметке мы размечаем текст страницы семантически (по смыслу), не думая о его внешнем виде. Внешний вид задается только в CSS. Это семантично:
<div class="offer offer__special">
<img class="offer-image" src alt>
<div class="offer-city">Москва</div>
<div class="offer-price">100 Тугр.</div>
</div>
Смотри как логично: есть блок предложения (причем не обычного, а special), в нем есть картинка, город и цена. Прекрасная разметка!
Это семантично:
<ul class="main-menu">
<li><a href>Первый урок</a></li>
...
</ul>
Это в общем тоже:
Переменная <var>$x</var> равна 10, потому код <code>echo $x;</code> выведет <samp>10</samp>.
Это несемантично:
<div class="blue-text">Москва</div>
Переменная <span class="monospace-font">$x</span>
Так как тут в разметку закладывается внешний вид (но такое все равно бывает на практике, например классы вроде margin-top-10 или width-100, но лучше этого избегать).
Это неправильное использование тега:
Переменная <pre>$x</pre>
Советую найти и прочесть список HTML5 тегов (что они обозначают). Учить наизусть не надо. Также советую прочитать про систему именования классов БЭМ от Яндекса.
Для разметки даты и времени есть тег time.
Тег a нельзя вкладывать внутрь тега a. Попробуй пропустить код через валидатор.
div без класса это очень плохо так как непонятно, что он значит? div и span это универсальные блочный и строчный теги и без атрибутов они ничего не значат.
Теперь по CSS
> .price {
> position: absolute;
Такие вещи удобнее делать флоатом, так как он расталкивает текст. Если ты делаешь абсолютом, то протестируй случаи когда длинная цена, длинный заголовок и длинное название города.
Также нужен тест где в блоке есть длинное описание, по высоте больше чем высота картинки. И тест что будет если убрать картинку (не наедет ли цена на город?).
Пока решение требует доработки. Пока все плохо.
А, и еще, бросается в глаза:
> 123$
или $123 или 123 долл.
> <div><strong>Moscow</strong></div>
Такие ошибки:
- зачем-то использовано 2 тега вместо одного (это допустимо если без этого не сверстать, но у тебя по моему простая верстка). Не добавляй лишние элементы.
- в хтмл разметке мы размечаем текст страницы семантически (по смыслу), не думая о его внешнем виде. Внешний вид задается только в CSS. Это семантично:
<div class="offer offer__special">
<img class="offer-image" src alt>
<div class="offer-city">Москва</div>
<div class="offer-price">100 Тугр.</div>
</div>
Смотри как логично: есть блок предложения (причем не обычного, а special), в нем есть картинка, город и цена. Прекрасная разметка!
Это семантично:
<ul class="main-menu">
<li><a href>Первый урок</a></li>
...
</ul>
Это в общем тоже:
Переменная <var>$x</var> равна 10, потому код <code>echo $x;</code> выведет <samp>10</samp>.
Это несемантично:
<div class="blue-text">Москва</div>
Переменная <span class="monospace-font">$x</span>
Так как тут в разметку закладывается внешний вид (но такое все равно бывает на практике, например классы вроде margin-top-10 или width-100, но лучше этого избегать).
Это неправильное использование тега:
Переменная <pre>$x</pre>
Советую найти и прочесть список HTML5 тегов (что они обозначают). Учить наизусть не надо. Также советую прочитать про систему именования классов БЭМ от Яндекса.
Для разметки даты и времени есть тег time.
Тег a нельзя вкладывать внутрь тега a. Попробуй пропустить код через валидатор.
div без класса это очень плохо так как непонятно, что он значит? div и span это универсальные блочный и строчный теги и без атрибутов они ничего не значат.
Теперь по CSS
> .price {
> position: absolute;
Такие вещи удобнее делать флоатом, так как он расталкивает текст. Если ты делаешь абсолютом, то протестируй случаи когда длинная цена, длинный заголовок и длинное название города.
Также нужен тест где в блоке есть длинное описание, по высоте больше чем высота картинки. И тест что будет если убрать картинку (не наедет ли цена на город?).
Пока решение требует доработки. Пока все плохо.
А, и еще, бросается в глаза:
> 123$
или $123 или 123 долл.
Всё, что нажито непосильным трудом...
Три скрипта отечественных: один считает три цифры и подставляет "миллионы", второй считает три цифры и подставляет "тысячи", третий считает три цифры и подставляет "рубли".
Столкнулся с тем, что если поставить $number = 012, то число переводится в какую-то другую систему (это вот считает как 10), от этого всё рушится.
В порыве отчаяния закрыл вкладку с Идеоне, где скрипт был для подсчёта миллионов, а остальные сохранились.
Вот для подсчёта с подстановкой "рублей": http://ideone.com/UJLA5U
Вот для подсчёта с подстановкой "тысяч": http://ideone.com/Fx2fbW
Там можно многое вынести в функции, можно расчёт сократить в строчку (я просто делал для наглядности многое) - теперь уже не имеет смысла.
Всё удаляю и забываю.
Начинаю решать эту задачу через деление чисел на 10, 100, 1000 и так далее до 100 миллионов. Всё должно быть в цикле, ориентация на целые числа, в соответствии с чем будут включаться разные условия для вывода числа прописью. Примерный алгоритм мысленно представляю.
Такой вот я тормоз, однако, здравствуйте.
И да: увидевшие скрипт буду или смеяться, или плакать. Первые - опытные, вторые - только ещё начинающие разбираться в РНР.
Ну вы поняли.
Еще одна из ошибок - даю переменным имена как функциям: $findLastNumber и т.п.
ОП об этом сказал, когда я уже начал решать эту задачу, думал потом всё исправить, но такие вот дела.
Это я учту тоже.
Бамп
Во первых, можно в парвила паосинга добавить два параметра. Типа из какой кодировки в какую.
Во вторых, можно прямо из штмл считывать meta encoding тэг.
Класс создает объект пдо один раз, чтобы использовать пдо без этого класса, пришлось бы создавать подключение каждый раз в новом контроллере, как тот быдлошкольник выше.
Не вижу связи. Ты читал этот урок? https://gist.github.com/codedokode/e1d31a31b37d5f635057
Синглтон это плохая вещь, и вообще непонятно зачем писать бесполезный класс когда можно просто передавать ПДО в нужные классы через конструктор.
И не надо тут всех обзывать школьниками если сам плохо разбираешься.
Тебе я написал советы и замечания выше
>>629589
Начни с гугления. Интеграция значит обмен данными между сайтом и системой 1С (например выгрузка данных о товарах из 1С в магазин, и выгрузка данных о заказах из магазина в 1С). Для этого 1С предлагает несколько вариантов, например:
- через ФТП, 1С будет выклаыдвать новые данные, например новые товары, на ФТП сервер и оттуда же забирать обновления с сайта, например заказы.
- через HTTP, 1с будет отправлять запросы с данными на какой-то URL
Подробнее лучше уточнить у ваших 1с-ников. Ведь вполне возможно что используются не стандартные возможности 1С, а что-то самописное.
Ну или ты можкшь поизучать XML файл сам, но мне кажется, спросить быстрее будет. У меня ощущение, судя по картинке, что у вас что-то нестандартное. Для стандартных случаев наверно есть готовые решения.
>>629605
Написал маленькую букву вместо большой в имени переменной.
>>629631
Верно, хотя с массивом бы получилось короче.
>>629732
Неправильно считает если взять сумму кредита = 1000: http://ideone.com/B81a83
Должно быть всего выплачено 2030 (1000 + процент + комиссия)
Также, выражение повторяется 3 раза, избавься от повторов: $creditBalance x $percent + $servicePayment
>>629735
Босюь что никто не станет решать твою задачу, решай сам.
Тебе я написал советы и замечания выше
>>629589
Начни с гугления. Интеграция значит обмен данными между сайтом и системой 1С (например выгрузка данных о товарах из 1С в магазин, и выгрузка данных о заказах из магазина в 1С). Для этого 1С предлагает несколько вариантов, например:
- через ФТП, 1С будет выклаыдвать новые данные, например новые товары, на ФТП сервер и оттуда же забирать обновления с сайта, например заказы.
- через HTTP, 1с будет отправлять запросы с данными на какой-то URL
Подробнее лучше уточнить у ваших 1с-ников. Ведь вполне возможно что используются не стандартные возможности 1С, а что-то самописное.
Ну или ты можкшь поизучать XML файл сам, но мне кажется, спросить быстрее будет. У меня ощущение, судя по картинке, что у вас что-то нестандартное. Для стандартных случаев наверно есть готовые решения.
>>629605
Написал маленькую букву вместо большой в имени переменной.
>>629631
Верно, хотя с массивом бы получилось короче.
>>629732
Неправильно считает если взять сумму кредита = 1000: http://ideone.com/B81a83
Должно быть всего выплачено 2030 (1000 + процент + комиссия)
Также, выражение повторяется 3 раза, избавься от повторов: $creditBalance x $percent + $servicePayment
>>629735
Босюь что никто не станет решать твою задачу, решай сам.
Внедрение зависимостей гугли и не надо будет ничего создавать
Всё отлично.
Через while так-то удобнее её решить. Но ОП предлагает через for - попробуй ещё и через for для верности.
Отлично.
>Также, неприавльно обрабатываются исключения, catch а тем более эхо там не нужны.
Почему? Ведь если это исключение не ловить, пользователю просто покажет белую страницу.
Я про это говорил уже пару тредов назад, что это не очень хорошо в плане SEO, потом ещё хотел сказать, что это не очень удобно и в плане обучения - приходится всё просматривать, весь материал страницы, чтобы найти что-то интересующее, удобнее было бы ввести это в "Поиск" и получить результат.
А теперь для меня очевидно, что это практически идеально: ты каждый раз просматриваешь информацию, в голове откладывается, что верно сделано, а что неверно. Ну или я просто привык изучать всё по книгам, там практически то же самое, тот же эффект.
Я вот уже давно не смотрел на регулярки - отвлёкся на другие сложные задачи, а сейчас решил проверку номера телефона ещё раз написать с нуля и с подстановкой номеров из массивов в пасте ОПа (вот тут её вставлял: >>631698): http://ideone.com/cPUmGT
Сделал без подглядываний (я сто раз смотрел это всё уже, многое успел крепко запомнить).
Также стоит читать ответы ОПа другим братишкам, смотреть на их ошибки и т.п.
Также способствует всему самостоятельный разбор и исправление ошибок в решении задач у братишек - лишний раз всё отпечатывается в голове.
Просто так это пишу всё пока отдыхаю от решения сложной задачи, которую впоследствии надеюсь так же просто и разнообразно решать, как первые задачки
Вообще не всё ещё и пропало!
Можно вот как сделать в этой моей ситуации.
Числа с нулём в самом начале у нас просто и не будет - mt_rand(0,999999999) нам такое число не выдаст. А дальше мы можем просто проверять, нет ли нуля в третьей позиции числа и в шестой - проверять эту строку.
То есть, например, у нас число 50 012.
50 у нас идёт в тот скрипт, где тысячи - выдаёт "50 тысяч".
А далее включается проверка третьего числа с конца. Если оно равно нулю, то берём только последние два числа с конца - это уже есть и оно выдаст "12 рублей".
Так что не всё ещё было потеряно, муахаха!
Но попробую освежить голову и сделать с помощью деления и округления в цикле, посмотрю, как пойдёт.
Взываю к среднелевельным анонам. Выполнил задачу Grammar Nazi v2. Всё получилось, но каждую замену мне пришлось гарантировать индивидуальным условием, выглядит как-то не очень грамотно. Думал прибегнуть к функциям, но не придумал, как, да и не уверен, что так можно в данном случае. Полагаю, есть возможность реализовать это с помощью массивов, немного погуглил, но так и не придумал, как правильно сформулировать запрос. Прокомментируйте, пожалуйста.
http://ideone.com/sLeIRY
Можно сделать два массива - $regexp и $replace: в одном все регулярки с ошибками, которые должны быть разделены круглыми скобками и знаками "или", а в другой исправляемые моменты, который будут нумероваться как $1, $2 и так далее - то, что у нас в регулярках, но с добавлением пробела или с исправлением на другое слово.
Посмотри этот момент на странице с регулярными выражениями - как заменяются регулярки с помощью $1 и так далее.
Тогда потом достаточно будет подставить в foreach с разложением массива с регулярками на ключи и значения, ещё один массив с разложением реплейсмента на ключи и значения, а потом с помощью preg_replace подставлять регулярки из массива и заменяемые места из реплейсмента, ахаха, я поехал уже...
Но всё тогда будет вообще в несколько строк и без условий каких-либо.
Понятно ли объяснил?
Как ты себе это представляешь?
class Mapper {
__construct($db PDO)
$db = new PDO('mysql:host=localhost;dbname=guestbook;charset=utf8', 'root', '');
}
или быть может при каждом создании маппера задавать новый $db = new PDO('mysql:host=localhost;dbname=guestbook;charset=utf8', 'root', '');?
Хуйню несешь короче.
>class Mapper {
>__construct($db PDO)
>$db = new PDO('mysql:host=localhost;dbname=guestbook;charset=utf8', '>root', '');
>}
Вообще-то так и надо делать
лол, долбоеб, зачем тогда в конструктор пдо передавать. иди задачки порешай, тут взрослые люди общаются.
Ну да, предпологается, что в конструктор передается уже готовый объект, а сам конструктор просто присвоит его полю.
http://ideone.com/cnFoMy
А то я в целом не совсем ньюфаг в этом деле, но прохожу.
W2(перевод долларов в рубли) - http://ideone.com/5zHXdu
W3(имитация броска кубика) - http://ideone.com/2QvVvX
W4.1(дописать кубик) - http://ideone.com/ckuYdx
W4.2(рулетка что смотрит последнюю цифру) - http://ideone.com/TKuvUB
Пойду делать дальше.
Задачку W4.1 неправильно написал(был невнимателен и не написал когда победит дружба), вот правильный(как я думаю) вариант - http://ideone.com/hGYwZs
>mb_substr($text, $length, $halfLength);
Щито сие означает? Посмотри, как там у ОПа или в мануале описано, что там должно стоять вместо $length и $halfLength.
Также надо все буквы сделать строчными, ты упустил этот момент с самого начала.
Алгоритм такой, частично он у тебя соблюдён:
1. Делаем все буквы строчными.
2. Убираем регуляркой все пробелы между словами.
3. Подсчитываем количество символов в получившемся тексте.
4. Подсчитываем середину текста.
5. В цикле проходим по буквам от начала текста и до середины. Здесь получше уясни себе, как работает функция mb_substr. Также вспомни, для чего мы используем $i в циклах с for.
6. Если буква с начала строки и конца строки не совпадают - возвращаем результат "Не палиндром" и обрываем цикл.
7. Если буквы с начала и конца и далее совпадают - продолжаем цикл до того момента, когда будет проверена половина текста. Здесь мы можем выводить каждую букву с конца и начала, чтобы сравнивать их.
8. Если у нас цикл был пройден до конца, то возвращаем echo "Палиндром".
Твой код я поправил. Если совсем будет сложно, то буду подсказывать или просто покажу твой же исправленный код.
Ладно, пусть так. Я рассчитывал именно на то, чтобы избавиться от зависимости от библиотеки, плюс может быть использовать код повторно в других проектах.
Но тут пожалуй действительно не тот случай. Библиотеку менять не нужно, и код не такой сложный, чтобы выносить его в отдельный пакет.
Тогда такая реализация: http://ideone.com/wNwIh1
>>632982
Не использовать лишние теги, стараться использовать html5-теги по возможности, или классы с семантичным именем, ок.
> position: absolute;
> Такие вещи удобнее делать флоатом
Да, это не учел, что при очень маленькой ширине экрана (или длинном заголовке) он наезжает на цену.
Только с флотами получается странный порядок "слоев": у меня теперь идет сначала блок с ценой, а за ним заголовок, город и время. Хотя визуально сначала должен идти заголовок, а за ним цена (если смотреть слева направо).
Ну и я слышал, что для сео может быть важным порядок блоков, сначала должен идти основной контент, а затем выносить все меню и сайдбары, даже если они визуально идут выше/слева от главного контента.
По поводу отпозиционированного блока с городом и датой, то просто не знаю, как иначе их прижать к нижнему краю контейнера. В дизайне никакого текста описания вообще нет, но добавил ради эксперимента. Чтобы текст описания не наезжал на город, сделал ему нижний паддинг.
>что будет если убрать картинку (не наедет ли цена на город?).
Добавил min-height внешнему контейнеру. Вообще мне не хватает опыта, чтобы просчитать наперед все "что будет если". Я вижу дизайн и реализовываю. Думаю дальновидность придет с опытом, когда придется такой код поправлять под изменившиеся требования (убрать картинку, добавить текст описания и т.д.)
https://jsfiddle.net/tLwp60qh/6/
Все сбрасывай, оп найдет к чему придраться даже в коде из одной строчки.
>не совсем ньюфаг
Какие фреймворки знаешь? Сколько проектов написал? В каких конторах работал?
>>633443
Нет, так рождается быдлокод. Php за это и не любят, что на нем можно написать неподдерживаемый код, который тем не менее будет работать.
Если работает и вроде все понятно, это не значит, что решено правильно.
Шлюхой ща работать не могу.
получается строка "С меня хватит" будет просто не нужна после исправления ошибки? Ведь идеальным решением задачки есть полный вычет денег без переплаты. А то условие не до конца понял.
И еще вопрос вдогонку - не понял, нужно ли насчитывать проценты когда долг меньше 5000.
Нет, она может остаться и выйти тогда, когда выплачен весь кредит.
Полная выплата кредита с процентами и комиссиями - и далее "С меня хватит!".
А какой тогда вообще смысл?
Вот я что-то запутался с условием задачки.
Под спойлер заглядывал.
Какой смысл проверять больше ли 5000, если потом эта же цифра всё-равно увеличится и чисто теоретически может быть больше чем 5к?
Или проверять надо не просто долг а долг с процентом на следующий месяц?
Такое уж сферическое условие в вакууме, сумма возможных выплат Анончика меньше и больше не может становиться.
>Или проверять надо не просто долг а долг с процентом на следующий месяц?
А как по-другому? Конечно!
Ещё и оплату комиссии за пользование кредитом не забудь!
Чёт я вообще запутался с этим условием, не знаю почему, но очень туго само условие до меня доходит, хотя с циклами давно знаком. Пойду проветрюсь, отвлекусь и чуть позже вернусь к задачке.
Про массивы и циклы слышал что-нибудь?
Создаешь массив, заполняешь его твоими регулярками, прогоняешь цикл n раз.
>mb_substr($text, $length, $halfLength);
из $text, длиной 19 (от последней буквы), до середины, но я понял, что так оно не работает и я понятия не имею, как запустить его с другой стороны.
1. Строчные буквы mb_strtolower($text);
2. Убрать пробелы $text = str_replace(' ', '', $text);
3. Кол-во символов $length = mb_strlen($text);
4. Середина $halfLength = floor($length/ 2);
5. Вот тут я и не знаю, а 6,7,8 нужны только после выполнения 5.
Короче, давай подсказку.
>mb_substr($text, $length, $halfLength);
>из $text, длиной 19 (от последней буквы), до середины, но я понял, что так оно не работает и я понятия не имею, как запустить его с другой стороны.
У нас есть цикл с for и в нём переменная $i - она меняется каждый раз при прохождении цикла.
Если поставить вот так, то переменная каждый раз будет способствовать передвижению по тексту на один символ:
>mb_substr($text, $i, 1)
Чтобы то же самое получить, но с конца текста, надо эту переменную поставить в отрицательном значении: >mb_substr($text, -$i, 1)
Каждый раз делай var_dump($variable), чтобы понять, что там происходит. variable - это конкретное название твоей переменной или массива
>1. Строчные буквы mb_strtolower($text);
Нет, сработает не само по себе, а если ты поставишь вот так, например:
$text = mb_strtolower($text);
2, 3, 4 у тебя правильно сделаны.
5 у тебя получится, если сделаешь с переменной $i в mb_substr().
Давай, пробуй, всё получится.
>твоей переменной или массива
Твоей переменной, в которой строка, число или массив, ну ты понял.
Var_dump просто на каждом шагу делай, смотри, что там получается. Всегда помогает это.
Мне лень.
https://habrahabr.ru/post/210202/ прочитал, но так и не понял, куда копать.
xdebug + phpstorm, для javascript дебагер в firefox
Больше ничего не надо, хватает даже для крупных проектов.
Есть поле формы, в которое можно вести адрес какой-нибудь текстовой информации (пост блога, статья на сайте и т.д.) скрипт спарсевает всю нужную информацию (Заголовок, Текст, Дата и т.д.), заносит её в базу данных и формирует из этого RSS XML. Спарсивать можно не с любого сайта конечно, а только для тех, для каких я напишу парсер, но таких сайтов может быть много.
Есть. Можно плагином настроить работу xDebug в Sublime Text.
Если интересно почитай тут http://www.sitepoint.com/debugging-xdebug-sublime-text-3/
>$new = (-19);
>$symbolRev = mb_substr($text, $new, 1);
Братишка, ну почитай ты, что у ОПа написано про mb_substr, как с конца текста надо получить символ!
Ты же так и разобрался в этом простом моменте!
Почему у тебя $new там сразу -19, она должна точно так же идти в цикле - а буквы будут браться с начала и конца текста и сравниваться друг с другом.
Вот как будет всё выглядеть, если цикл вытянуть и показать его работу ($i заменил на те цифры, которые как раз будут там при изменении этой переменной во время работы цикла):
Первое прохождение цикла.
$symbol = mb_substr($text, 0, 1);
$symbolRev = mb_substr($text, -1, 1);
- берутся "а" с начала текста (текст уже приведён к нижнему регистру) и "а" с конца - первые символы с обеих сторон текста, далее у тебя условия с if и else, в которых эти символы сравниваются.
Второе прохождение цикла.
$symbol = mb_substr($text, 1, 1);
$symbolRev = mb_substr($text, -2, 1);
- берутся "р" с начала текста и "р" с конца - вторые символы с начала и с конца текста, снова сравниваются, равны ли друг другу.
Третье прохождение цикла.
$symbol = mb_substr($text, 2, 1);
$symbolRev = mb_substr($text, -3, 1);
- берутся "о" с начала текста и "о" с конца - третьи символы с одной и другой стороны текста, сравниваются в условиях.
...
Девятнадцатое прохождение цикла.
$symbol = mb_substr($text, 19, 1);
$symbolRev = mb_substr($text, -19, 1);
- берутся "а" в середине текста и "а" в середине (там центральная буква в тексте - это "м" в слове "манит", она не попадает в этот цикл, а вот буквы с обеих сторон проверяются, это как раз обе "а"), сравниваются.
И вот если переменная $i к этому моменту становится равной длине половины текста - то есть цикл работал, а не оборвался сразу, - то срабатывает условие, что это палиндром.
Говорю же - делай var_dump каждый раз - смотри на изменения переменных, чтобы осознать работу скрипта.
У тебя сейчас $symbol = mb_substr($text, $i, 1); даёт букву за буквой с начала текста - если бы цикл вообще работал, а $symbolRev = mb_substr($text, -19, 1); (там же $new у тебя без изменений и всегда равна -19) даст только одну букву из середины текста, как раз букву "а". Поэтому у тебя сейчас случайно показывает верно, что текст палиндром: сравнивает начальную "а" и вот эту 19-ю с конца "а".
Подсказка первая - совсем уже понятная должна быть к этому моменту: В $symbolRev = mb_substr($text, $new, 1); точно так же должна стоять переменная $i. Перед переменной можно ставить минус - всё работает. От переменной можно отнимать или к ней можно прибавлять прямо в функции - всё работает.
Подсказка ещё одна: Числа -0 не бывает.
>$new = (-19);
>$symbolRev = mb_substr($text, $new, 1);
Братишка, ну почитай ты, что у ОПа написано про mb_substr, как с конца текста надо получить символ!
Ты же так и разобрался в этом простом моменте!
Почему у тебя $new там сразу -19, она должна точно так же идти в цикле - а буквы будут браться с начала и конца текста и сравниваться друг с другом.
Вот как будет всё выглядеть, если цикл вытянуть и показать его работу ($i заменил на те цифры, которые как раз будут там при изменении этой переменной во время работы цикла):
Первое прохождение цикла.
$symbol = mb_substr($text, 0, 1);
$symbolRev = mb_substr($text, -1, 1);
- берутся "а" с начала текста (текст уже приведён к нижнему регистру) и "а" с конца - первые символы с обеих сторон текста, далее у тебя условия с if и else, в которых эти символы сравниваются.
Второе прохождение цикла.
$symbol = mb_substr($text, 1, 1);
$symbolRev = mb_substr($text, -2, 1);
- берутся "р" с начала текста и "р" с конца - вторые символы с начала и с конца текста, снова сравниваются, равны ли друг другу.
Третье прохождение цикла.
$symbol = mb_substr($text, 2, 1);
$symbolRev = mb_substr($text, -3, 1);
- берутся "о" с начала текста и "о" с конца - третьи символы с одной и другой стороны текста, сравниваются в условиях.
...
Девятнадцатое прохождение цикла.
$symbol = mb_substr($text, 19, 1);
$symbolRev = mb_substr($text, -19, 1);
- берутся "а" в середине текста и "а" в середине (там центральная буква в тексте - это "м" в слове "манит", она не попадает в этот цикл, а вот буквы с обеих сторон проверяются, это как раз обе "а"), сравниваются.
И вот если переменная $i к этому моменту становится равной длине половины текста - то есть цикл работал, а не оборвался сразу, - то срабатывает условие, что это палиндром.
Говорю же - делай var_dump каждый раз - смотри на изменения переменных, чтобы осознать работу скрипта.
У тебя сейчас $symbol = mb_substr($text, $i, 1); даёт букву за буквой с начала текста - если бы цикл вообще работал, а $symbolRev = mb_substr($text, -19, 1); (там же $new у тебя без изменений и всегда равна -19) даст только одну букву из середины текста, как раз букву "а". Поэтому у тебя сейчас случайно показывает верно, что текст палиндром: сравнивает начальную "а" и вот эту 19-ю с конца "а".
Подсказка первая - совсем уже понятная должна быть к этому моменту: В $symbolRev = mb_substr($text, $new, 1); точно так же должна стоять переменная $i. Перед переменной можно ставить минус - всё работает. От переменной можно отнимать или к ней можно прибавлять прямо в функции - всё работает.
Подсказка ещё одна: Числа -0 не бывает.
*так и не разобрался в этом простом моменте
Я напутал - там не 19 циклов, а восемь будет всего...
19 - это вообще количество букв в этом палиндроме про Аргентину.
Т.е. например приходят неполные данные и мне нет смысла отображать всю верстку данного вида, а отобразить кусочек из него и все.
Можно ли использовать return; ?
Или есть что то от фреймоврка
по типу current_view->хватитВыполнятьДавайУжеГлавныйЛэйаутПоказывай();
$("a").click(function() {
$(this).addClass('active');
});
Класс добавляется, но проблема в том, что он добавляется у всех ссылок, если нажимать по нескольким из них, как сделать так, чтобы класс active был только у одной ссылки, при этом при нажатии на другую ссылку класс ей добавлялся, а у той у которой он был раньше удалялся.
Запоминать предыдущую и ставить ей тоггл на класс актив, при добавлении этого класса к следующей ссылкею
$("a").click(function() {
$("a").not(this).removeClass('active');
$(this).addClass('active');
});
Такая ситуация: есть много .xsls шаблонов, мне нужно выгрузить в них товары.
Не хочу чтобы этим меня заебывали в дальнейшем, поэтому пытаюсь написать такую вещь:
-Выбираешь файл, он загружается.
Из строк в нем только заголовки.
Эти заголовки выводяться на страничке.
Внизу под заголовками селекты со списком полей(там вся инфа о товарах).
Затем можно выбрать соответствующие поля и захуярить файл в который всё это запишется.
воот.
С помощью phpExcell я сделал, чтобы шаблон считывался и отображался в браузере.
Но phpExcell так же убирать все хтмл теги, поэтому в ячейки селекты я записать не могу, а как отключить экранирование я не нашел.
Думаю, что буду писать в ячейки какой-то определенный текст, потом с помощью jquery его парсить, получать номер столбца и заменять на селекты.
Может кто посоветует что получше?
Да, ещё хотел спросить. Можно ли часть страницы отобразить в одной кодировке а вторую часть в другой?
Гладко выходит на бумаге, но натыкаюсь на РНР-овраги, пока не получается реализовать.
Не хотел бы отнимать время у ОПа и братишек на проверку этого алгоритма, но был бы рад замечаниям.
Ну и просто чтобы не потерять.
1. Имеем число, например, 123123.
2. Проверяем, на соответствие числам в массиве $spelling - нельзя ли его сразу вывести прописью. Если можно – выводим его. Если нельзя – идём далее.
3. Проходим по числу циклом с делением на 100000000, 10000000, 1000000, 100000, 10000, 1000, 100 и 10 и округляем результат.
4. Когда результат деления становится равным целому числу (от 1 до 9) – уточняем, на какое число делили, чтобы получился такой результат.
5. Далее всё идёт для уточнённого числа, у нас это 100000. Если основное число было разделено на сто тысяч до целого, то умножаем результат на 100, чтобы получить соответствие с числами в массиве $spelling.
6. Если у нас получившаяся сумма соответствует числу в $spelling (у нас это будет 100), то выводим (она будет соответствовать в любом случае, всё это есть в массиве).
7. Далее проверяем, есть ли другие цифры после 1 в реально имеющемся у нас числе. Для этого 123123 делим на 1000, округляем до целого числа, а затем отнимаем 100. В нашем случае – с 123 тысячами 123-мя - получится 23.
8. Проверяем результат на соответствие массиву $spelling. Если соответствие есть ("11", "12" и так далее) – выводим. Если соответствия нет – раскладываем дальше.
9. Раскладываем 23: делим его на 10, округляем до целого и умножаем на 10 – получается двадцать.
10. Проверяем результат на соответствие массиву $spelling. Соответствие обязательно есть.
11. Далее находим последнее число в 123: от 123 отнимаем сумму первого числа и второго числа (100 + 20). Проверяем результат на соответствие массиву $spelling. Соответствие обязательно есть.
12. Далее проверяем, не является ли последнее число "1" или "2": проводим число по массиву $femaleSpelling. Если соответствует - выводим результат "одна" либо "две". Если не соответствует – выводим предыдущий общий результат.
13. Собираем первое число, второе число и третье число: "сто", "двадцать" и "три". При этом у нас изначально всё связано с тысячами, поэтому выводим строку «сто двадцать три» и проверяем последнее полученное число на соответствие массиву с формами слова «тысяча». Соответствующую форму "тысяч" выводим.
14. Далее находим три оставшихся числа от 123123. У нас имеются три первых числа – 123, также мы знаем, что общее число – 123nnn. Поэтому умножаем 123 на 1000, а затем от начального числа $number отнимаем получившиеся 123000. Получается 123.
15. Раскладываем 123 по такому же алгоритму, как и 123000, только в самом конце не активируем шаг с $femaleSpelling. Последнее готовое число проверяется на соответствие в массиве для вывода правильной формы слова «рубли».
Алгоритм для вывода миллионов соответствующий, полностью повторяет алгоритм для вывода последних 123, только "рубли" меняются на "миллионы".
Большинство действий укладываются в функции, целые куски кода могут быть спрятаны в функции. Поиск от тысячи до 999 тысяч, поиск от 1 до 999, поиск от миллиона до 999 миллионов убираются в функции и подставляются в те условия, когда целое число получилось у нас при делении на соответствующие тысячи, десятки тысяч и так далее.
Когда у нас число, например, 20, или 20000, или 20000000, то выявление чисел идёт по этой же схеме – по сокращённой на поиск первого числа из тройки. Для этого вводим сокращённые функции и подставляем их в соответствующие места.
Вроде бы всё логично.
Буду биться и сражаться с ветряными РНР-мельницами далее.
Me Gusta.
Гладко выходит на бумаге, но натыкаюсь на РНР-овраги, пока не получается реализовать.
Не хотел бы отнимать время у ОПа и братишек на проверку этого алгоритма, но был бы рад замечаниям.
Ну и просто чтобы не потерять.
1. Имеем число, например, 123123.
2. Проверяем, на соответствие числам в массиве $spelling - нельзя ли его сразу вывести прописью. Если можно – выводим его. Если нельзя – идём далее.
3. Проходим по числу циклом с делением на 100000000, 10000000, 1000000, 100000, 10000, 1000, 100 и 10 и округляем результат.
4. Когда результат деления становится равным целому числу (от 1 до 9) – уточняем, на какое число делили, чтобы получился такой результат.
5. Далее всё идёт для уточнённого числа, у нас это 100000. Если основное число было разделено на сто тысяч до целого, то умножаем результат на 100, чтобы получить соответствие с числами в массиве $spelling.
6. Если у нас получившаяся сумма соответствует числу в $spelling (у нас это будет 100), то выводим (она будет соответствовать в любом случае, всё это есть в массиве).
7. Далее проверяем, есть ли другие цифры после 1 в реально имеющемся у нас числе. Для этого 123123 делим на 1000, округляем до целого числа, а затем отнимаем 100. В нашем случае – с 123 тысячами 123-мя - получится 23.
8. Проверяем результат на соответствие массиву $spelling. Если соответствие есть ("11", "12" и так далее) – выводим. Если соответствия нет – раскладываем дальше.
9. Раскладываем 23: делим его на 10, округляем до целого и умножаем на 10 – получается двадцать.
10. Проверяем результат на соответствие массиву $spelling. Соответствие обязательно есть.
11. Далее находим последнее число в 123: от 123 отнимаем сумму первого числа и второго числа (100 + 20). Проверяем результат на соответствие массиву $spelling. Соответствие обязательно есть.
12. Далее проверяем, не является ли последнее число "1" или "2": проводим число по массиву $femaleSpelling. Если соответствует - выводим результат "одна" либо "две". Если не соответствует – выводим предыдущий общий результат.
13. Собираем первое число, второе число и третье число: "сто", "двадцать" и "три". При этом у нас изначально всё связано с тысячами, поэтому выводим строку «сто двадцать три» и проверяем последнее полученное число на соответствие массиву с формами слова «тысяча». Соответствующую форму "тысяч" выводим.
14. Далее находим три оставшихся числа от 123123. У нас имеются три первых числа – 123, также мы знаем, что общее число – 123nnn. Поэтому умножаем 123 на 1000, а затем от начального числа $number отнимаем получившиеся 123000. Получается 123.
15. Раскладываем 123 по такому же алгоритму, как и 123000, только в самом конце не активируем шаг с $femaleSpelling. Последнее готовое число проверяется на соответствие в массиве для вывода правильной формы слова «рубли».
Алгоритм для вывода миллионов соответствующий, полностью повторяет алгоритм для вывода последних 123, только "рубли" меняются на "миллионы".
Большинство действий укладываются в функции, целые куски кода могут быть спрятаны в функции. Поиск от тысячи до 999 тысяч, поиск от 1 до 999, поиск от миллиона до 999 миллионов убираются в функции и подставляются в те условия, когда целое число получилось у нас при делении на соответствующие тысячи, десятки тысяч и так далее.
Когда у нас число, например, 20, или 20000, или 20000000, то выявление чисел идёт по этой же схеме – по сокращённой на поиск первого числа из тройки. Для этого вводим сокращённые функции и подставляем их в соответствующие места.
Вроде бы всё логично.
Буду биться и сражаться с ветряными РНР-мельницами далее.
Me Gusta.
Для чего там цикл? Всё работает и без условия, что $i == 2.
1) математикой разбиваем число на группы по 3 цифры (миллионы, тысячи, рубли)
2) для каждой группы вызываем функцию печати 3-значного числа + функцию склонения слова, получается например "сто пятьдесят миллионов"
3) в этой функции разбиваем число математически на сотни, десятки, единицы.
4) еслит в числе есть сотни, добавляем нужное слово
5) если есть десятки, добавляем их
6) если число заканчивается на 11-19, добавляем слово
7) добавляем слово для единиц
Вот примерно и все, Еще конечно нуль надо обрабьатывать особо.
Собирать слова в фразу удобно через массив, добавляя слова в массив и потом склеивая его.
Спасибо, интересно выглядит.
Я просто не знаком абсолютно с математическими возможностями определения числа, поэтому начал делать через определение числа, на которое делится с целым числом после округления.
Буду искать, как это можно реализовать. Явно как-то проще, чем я расписал.
В массив можно, действительно, спасибо. Через array_push, наверное.
>>634087
Главным редактором в издательстве.
Люблю основательность.
И просто я уже реализовал части этой задачи через перевод числа в строку, вот тут: >>633021.
Хочу сделать более правильно и до конца.
Там так-то тоже можно было бы извратиться и соединить эти части: искать символ "ноль" в строке перед переходом к разложению тройки или складывать три последних числа, чтобы было понятно, нужно ли вообще запускать разложение очередной тройки (если там ноль получается, то не нужно).
Но это совсем уж.
Саму иде берешь на сайте у джетбрейнс, потом идешь сюда http://www.rover12421.com/ и качаешь его кейген (это не вишня, исходники лежали на гитхабе, но их заблочили).
Если китайский обменник по каким-то причинам не даст тебе скачать файл, можешь попробовать взять иде с кряком отсюда (нужна регистрация).
http://nnm-club.me/forum/viewtopic.php?t=974883
Я так понял, качать надо вот по этой ссылочке, да?
Download Jar : http://pan.baidu.com/s/1gdw7T0v
Да вроде бы, я активировал этим кейгеном месяцев 6 назад, еще работает со всеми обновлениями.
Бля, эт говно какое-то, полностью на китайском.
заебался уже систему чистить, хуй знает куда оно полезло
Я скачал сам китайский облачный обменник, как я понял. Вычищать его - отдельный ад)
Подумать головой. Там и делать-то нечего.
Короче, с переводчиком понял, что сайт будет выпрашивать скачать эту Байду.
лучше крякнутую с ннм стяну с регой)
Алсо подскажите как импортировать данные из одной базы в другую (первая называется web, вторая web2). Пробовал CREATE DATABASE web; mysql -uroot web < web2.sql, не работает, как указать консоли расположение второй базы?
>В браузере ошибка Fatal error: Call to undefined function mysqli_connect()
Апач и Пхпсторм один и тот же интерпретатор используют? Создай в корневой директории апача файл с phpinfo() и посмотри, есть ли там расширение mysqli.
>\t
Я видимо даже в математику не могу, потому что совсем не понимаю что там надо сделать, чтобы не переплачивать банку. Даже идей нет никаких.
Как посмотреть это расширение? Так? Алсо в браузере 404ая, у меня так часто бывает с новыми проектами в phpstorm, помогает, если положить их в отдельную папку проектов.
Это странно, но ошибка исчезла сама собой, после создания нового файла, когда я снова открыл проект. Короче я молодой шутливый с ide пока что.
Однако, вопрос про расположение второй базы в консоли остается. Это второй вопрос у меня был.
Создай файл в корневой директории твоего апача, без пхпсторма. Я не знаю где она на винде, должно быть что-то вроде C:\Apache\www.
Потом заходишь в браузере по адресу 127.0.0.1 и видишь там всю информацию о пхп, ищешь на странице расширение mysqli, должно быть что-то вроде пикрелейтед.
https://github.com/disbeliever/php_training/tree/master/students
Что значит не переплачивать банку?
Покажи пробы свои на Идеоне.
Там переплата больше 50% будет так-то.
Почитай, что такое анонимная функция и callback.
Почему защиту от csrf не сделал? Еще некоторые ссылки неправильно работают, если поместить скрипт в какую-нибудь папку, он будет перенаправлять в корень сервера.
Алсо, если редактировать свою информацию, у меня происходит пикрелейтед.
>по айфону в кредит
Надо было покупать Xiaomi. Топовый айфон сосет по железу у китаебогов. Алсо, в айфоне нет божественного MIUI.
csrf надо исправить, но это я думаю, можно сделать попозже, для начала надо баги победить. Ну и ссылки поправить - надо вместо
href="/register.php"
писать просто
href="register.php"
Урок про относ.ссылки есть:
https://github.com/codedokode/pasta/blob/master/network/urls.md
И про CSRF тоже https://github.com/codedokode/pasta/blob/master/security/xsrf.md
>>632567
> $start = false; //Для выхода из цикла
Для этого есть команда break
> if($debt <= $pay){
Этот иф можно заменить на функцию min/max, возможно код станет короче, попробуй-ка.
В условии в уайл лучше написать "пока долг больше нуля"
Эхо лучше писать не через кучу точек, а с подстановкой переменных в строку.
> PHP Notice: Undefined variable: total_pay in /home/krtLNc/prog.php on line 18
Эту ошибку обращения к несуществующей в тот момент переменной надо исправить.
А разве в китайских прошивках нет троянов и штуки которая записывает координаты, названия вайфай точек, ИМЕИ, номер телефона и отсылает в байду?
Давай начнем с теории. Знаешь ли ты зачем придуманы исключения? Читал ли урок https://gist.github.com/codedokode/65d43ca5ac95c762bc1a
Если нет, прочитай.
До исключений мы должны были после каждой функции писать иф и проверять ее результат, не было ли ошибки. Исключения позволили отказаться от этого. Так как исключение автоматически выходит из вложенных вызовов функций наверх, нам достаточно одного-единственного обработчика исключений на самом верху:
try {
$app->run();
} catch (..) {
$app->showErrorPage();
}
Более того, мы можем и этого не делать, так как пхп сам ловит непойманные исключения, логгирует их, выводит пустую страницу в браузер и завершает скрипт.
Ловить исключения где-то еще надо если у нас есть способ обработать их. Ну например мы можем ловить ошибку соединения с удаленным сервером чтобы сделать еще несколько попыток. Очевидно что в этом случае мы ловим не все подряд, а конкретное исключение, отвечающее за ошибку соединения с сервером.
Теперь прочти пасту про то что должно происходить при исключении:
------
Как надо обрабатывать исключения:
- записать информацию в лог
- показать пользователю заглушку
- на заглушке выставить HTTP 503 код ответа для роботов
- на компьютере разработчика (при display_errors = 1) показать подробности и стектрейс
Что получается при catch + echo:
- в лог ничего не фиксируется, ты не узнаешь об ошибках
- пользователь видит непонятную белиберду на английском
- отдается код 200
Как будет если просто не ловить исключение:
- информация пишется в лог (ок)
- на компьютере разработчика выводятся подробности (ок)
- пользователь видит белую страницу (не ок)
- отдается код 200 (не ок)
--------
Теперь посмотри на свой код и попробуй понять, правильно ли в нем сделана работа с исключениями.
Давай начнем с теории. Знаешь ли ты зачем придуманы исключения? Читал ли урок https://gist.github.com/codedokode/65d43ca5ac95c762bc1a
Если нет, прочитай.
До исключений мы должны были после каждой функции писать иф и проверять ее результат, не было ли ошибки. Исключения позволили отказаться от этого. Так как исключение автоматически выходит из вложенных вызовов функций наверх, нам достаточно одного-единственного обработчика исключений на самом верху:
try {
$app->run();
} catch (..) {
$app->showErrorPage();
}
Более того, мы можем и этого не делать, так как пхп сам ловит непойманные исключения, логгирует их, выводит пустую страницу в браузер и завершает скрипт.
Ловить исключения где-то еще надо если у нас есть способ обработать их. Ну например мы можем ловить ошибку соединения с удаленным сервером чтобы сделать еще несколько попыток. Очевидно что в этом случае мы ловим не все подряд, а конкретное исключение, отвечающее за ошибку соединения с сервером.
Теперь прочти пасту про то что должно происходить при исключении:
------
Как надо обрабатывать исключения:
- записать информацию в лог
- показать пользователю заглушку
- на заглушке выставить HTTP 503 код ответа для роботов
- на компьютере разработчика (при display_errors = 1) показать подробности и стектрейс
Что получается при catch + echo:
- в лог ничего не фиксируется, ты не узнаешь об ошибках
- пользователь видит непонятную белиберду на английском
- отдается код 200
Как будет если просто не ловить исключение:
- информация пишется в лог (ок)
- на компьютере разработчика выводятся подробности (ок)
- пользователь видит белую страницу (не ок)
- отдается код 200 (не ок)
--------
Теперь посмотри на свой код и попробуй понять, правильно ли в нем сделана работа с исключениями.
Прочитай еще этот пункт: https://github.com/codedokode/pasta/blob/master/student-list.md#Выносим-код-за-корень-сервера
Сейчас у тебя куча файлов свалена в корне. Это никуда не годится, да еще и небезопасно. Сделай отдельно публичную папку и положи в нее файлы, к которым можно обращаться снаружи. Классы тоже положи в отдельную папку, например app или src.
> Пробовал CREATE DATABASE web; mysql -uroot web < web2.sql, не работает, как указать консоли расположение второй базы?
Где ты это набирал? В командной строке системы или в командной строке майэскуэл? Что пишет?
Чтобы перенести одну базу в другую, надо сделать дамп командой mysqldump и залить его в базу командой mysql ... < dump.sql
Можно даже без промежуточного файла:
mysqldump ... | mysql ....
Зачем так унижаться? Если нет денег, можно попробовать найти EAP версию пхпсторма, она бесплатна, либо поставить бесплатный netbeans.
>$start = true;
>$start = false;
>PHP_EOL
Каков бэкграунд у тебя? Что-то уже изучал?
Про обилие точек и кавычек пояснили.
Считает правильно, что, кстати, бывает достаточно редко - чтобы сразу считал верно.
Парнишка начал изучать РНР в 30+ лет? Как же он дошёл до жизни такой?
31летний новичок, завсегдатай последних нескольких тредов
ОП того треда просто поныть пришёл, и явно ничего делать/менять не собирается. Я же просто мимо проходил и наткнулся там на годные советы от пхп-деда.
Мне тоже скоро 30, я потратил несколько лет на изучение php, работу так и не нашел естественно по этой профе, сейчас ищу в сфере обслуживания. Грустно, конечно, но жизнь она такая.
Я вот работаю 5.2 ну пишу там стандартные штуки стандартными методами. Процесс изучения нового сильно замедлился. К тому же я в довольно ретророградом коллективе работаю.
После работы не так много свободного времени остаётся понятное дело и отдохнуть хоть чуть хочется.
Как жить то? Превозмогать, в сеньерах на том свете отдохнем?
>работу так и не нашел естественно по этой профе
А что естественного, вакансий довольно же много? Зарплаты на среднем уровне по региону даже у джунов. Чому бы не найти?
>>634587
Я после работы всё изучаю. Иногда в перерывах немного посматриваю и пробую.
Всё-таки это личное дело каждого.
У меня знатный САМОПОДДУВ сейчас идёт, поэтому я иногда и до ночи засиживаюсь.
Я например с работы приезжаю и учу. Плюс выходные полностью за задрачиванием фреймворков провожу. Если ты работаешь 12 часов в день, задумайся о том чтобы найти работу получше.
Я тоже так делал, потом понял что теряю очень много времени и удалил все игры с компьютера, до лучших времен. Еще очень помогает отслеживание активности, пик статистика за вчерашний день.
>отслеживание активности
Это через что? Вручную всё забивается?
Чувствую я буду забывать про такое
Нет, ставишь программу и она записывает всю твою активность к ним на сервер. На сайте есть дашборд который показывает сколько времени ты на что тратишь.
Специально для параноиков сделали open source таймтрекер https://habrahabr.ru/post/275447/.
Спасибо. Будем исправляться.
http://ideone.com/kUDIO4
Я не понимаю, как сделать во второй строчке в if $i = -1.
В этой версии она -$++, но она в теле цикла и уже на второй проход становится 0.
Кто такой "лущер"?
А последнюю подсказку ты смотрел?
Я специально для этого и оставил её!
Числа -0 не бывает, а именно так у тебя получается при первом прохождении цикла.
Подсказка, которая всё должна разрешить:
$i изначально надо определить как "1", а в функциях или отнимать единицу, чтобы получился ноль, или просто поставить минус перед $i, чтобы получилась "-1".
>>634587
>>634609
Тоже прокраситериновал и играл то в циву, то просто от усталости сидел на ютубе видео смотрел. Всё надоело, после работы вообще невозможно учить ничего(по крайней мере мне), слишком устаю и скилл постоянно теряю(вот сейчас забыл уже всё почти). Уволился, теперь буду дома 24/7 учить.
Сейчас сел и понял, что почти с начала надо повторять
Также обрати внимание, как ты проверяешь равенство переменных в одном из if.
Там есть ошибка.
if ($i = $halfLength) - это присваивание, а не проверка на равенство
Ну вот и ладненько, молодца!
$i часто будет использоваться и дальше, так что это надо уяснить.
А вот моё первое исправление твоей задачи: http://ideone.com/sL7aTo
мимо админ
Заявлено до 1000 iops, на деле чуть меньше (800), задержка 40 ms.
Скорость чтения - несколько сотен мегабайт/сек.
Для СХД это весьма неплохой показатель.
Это же сколько бабла можно сэкономить если выносить большую часть логики на клиента?
Пёрнул в лужу как боженька. Как ты на своём хипстерском ангуляре планируешь реализовать хранение заказов интернет-магазина?
Для компании, зарабатывающей два лярда в год - 70к за сервер не деньги.
Мы на корпоративные телефоны в месяц тратим в 10-15 раз больше.
Я про angular/магазины и не говорил (я вообще мобильный разработчик).
А вот для сайтов с высокой нагрузкой на сеть, можно было бы сэкономить.
>>634683
Но тут все равно сложно поддерживать отказоустойчивость/балансировку.
Да и код написать который сможет нормально маштабироваться не просто.
Хотя это php, там наверное просто логическая прокладка над бд.
Тебе лучше не знать, как у нас всё работает.
Новый код масштабируется, легаси-говно нет. Постепенно всё, что делает легаси-говно, переносится в новый код.
Полный уход от легаси планируется только в конце этого года.
Нагрузки на сеть там как раз особой нет. Когда гоняли нагрузочное тестирование (siege) - хостер машины с которой запускался сидж, сказал что мы охуели засирать им канал 4 гигабитами трафика.
Бери больше, кидай дальше. Легаси - уже 4 года, и писали его большей частью не мы. После ревью архитектуры стало ясно, что проще выкинуть его нахуй и написать заново, что и делается постепенно.
ОП-пост читай.
Спасибо. Мы вам перезвоним.
Имел в виду, что тебе проще будет всё делать, поэтому лучше с самого начала учебника и пойти - освежить всё в памяти.
Так грустно всё это. Неделю не открывал - открываю и я ВСЁ забыл. Что за хуйня? Даже руки опускаются
За неделю забыл, что такое циклы и массивы, регулярки и тому подобное?
Тогда действительно не весело.
А мелочь разную, функции и подобное - и вообще можно не запоминать, не обязательно помнить.
Да нет, забыл только мелочь разную, но всё равно как-то я раздосадован. Сижу, смотрю и разбираю свои решения старых задач - вроде, восстанавливаю.
>А что естественного, вакансий довольно же много? Зарплаты на среднем уровне по региону даже у джунов. Чому бы не найти?
Не вижу вакансий, в моем городе их всего две и я туда уже ходил. Меня естественно послали.
Туда лететь надо.
http://ideone.com/XuzycW
если убрать
} else {
foreach($paths[$point] as $key => $value){
makeStep($paths, $pathDone, $time, $paths[$key], $target);
}
то будет считать 1 шаг нормально, но я не понимаю, как рекурсию сделать
Накатал скриптец, который разбирает json, приходящий с трекера и сохраняет его, куда мне надо.
1) Как заставить этот скрипт постоянно слушать определенный порт?
2) Два (двадцать два/две тысячи два) трекера одновременно шлют данные на один порт - какие основные моменты мне нужно знать и учитывать, чтобы скрипт корректно обрабатывал входящие данные от многих источников? Это называется многопоточность?
3) Киньте годной инфы по работе с бинарными данными - не получается написать такой же скрипт для трекера, который шлет данные в бинарном режиме.
Исправления по списку студентов.
В ОП-посте есть ссылка на учебник.
В нем есть последняя глава про ООП: http://archive-ipq-co.narod.ru/l1/pasta.html
В ней есть 2 задачи, про Вектор и Кошки-Мышки. Вот их и решай и выкладывай сюда ссылку на код, мы посмотрим.
По задаче Вектор есть дополнительное условие, проверяющее способность твоего кода к изменениям:
------------
### Антикризисные меры
Задание: напиши программу для учета расходов и результатов работы всего дружного коллектива компании «Вектор».
Пока ты решал задачу по выводу отчета о сотрудниках и департаментах, разразился мировой экономический кризис. Доходы компании начали снижаться, и совет директоров поставил перед руководством задачу принять меры. Менеджеры 3-го ранга, блестящие выпускники топовых экономических вузов столицы, быстро смогли разработать три альтернативных антикризисных решения:
1. Сократить в каждом департаменте 40% (округляя в большую сторону) инженеров, преимущественно самого низкого ранга. Если инженер является боссом, вместо него надо уволить другого инженера, не босса.
2. Увеличить в целях стимуляции умственной деятельности базовую ставку аналитика с 800 до 1100 тугриков, а количество выпиваемого им кофе с 50 до 75 литров. В тех департаментах, где руководитель не является аналитиком, заменить его на аналитика самого высшего ранга из этого департамента (а бывшего руководителя вернуть к обычной работе)
3. В каждом департаменте повысить 50% (округляя в большую сторону) менеджеров 1-го и 2-го ранга на один ранг с целью расширить их полномочия.
Совет директоров в затруднении: какой путь выбрать? Помоги им с этим, распечатав прогноз по потреблению и расходам (аналогичный тому что требуется в задаче) после принятия каждой из мер.
--------------
Если запутаешься, покажи код и попроси подсказку - эти задачи для новичка довольно сложные.
В ОП-посте есть ссылка на учебник.
В нем есть последняя глава про ООП: http://archive-ipq-co.narod.ru/l1/pasta.html
В ней есть 2 задачи, про Вектор и Кошки-Мышки. Вот их и решай и выкладывай сюда ссылку на код, мы посмотрим.
По задаче Вектор есть дополнительное условие, проверяющее способность твоего кода к изменениям:
------------
### Антикризисные меры
Задание: напиши программу для учета расходов и результатов работы всего дружного коллектива компании «Вектор».
Пока ты решал задачу по выводу отчета о сотрудниках и департаментах, разразился мировой экономический кризис. Доходы компании начали снижаться, и совет директоров поставил перед руководством задачу принять меры. Менеджеры 3-го ранга, блестящие выпускники топовых экономических вузов столицы, быстро смогли разработать три альтернативных антикризисных решения:
1. Сократить в каждом департаменте 40% (округляя в большую сторону) инженеров, преимущественно самого низкого ранга. Если инженер является боссом, вместо него надо уволить другого инженера, не босса.
2. Увеличить в целях стимуляции умственной деятельности базовую ставку аналитика с 800 до 1100 тугриков, а количество выпиваемого им кофе с 50 до 75 литров. В тех департаментах, где руководитель не является аналитиком, заменить его на аналитика самого высшего ранга из этого департамента (а бывшего руководителя вернуть к обычной работе)
3. В каждом департаменте повысить 50% (округляя в большую сторону) менеджеров 1-го и 2-го ранга на один ранг с целью расширить их полномочия.
Совет директоров в затруднении: какой путь выбрать? Помоги им с этим, распечатав прогноз по потреблению и расходам (аналогичный тому что требуется в задаче) после принятия каждой из мер.
--------------
Если запутаешься, покажи код и попроси подсказку - эти задачи для новичка довольно сложные.
Погугли "алгоритмы поиска пути". Там можно исплоьзовать готовый алгоритм, например алогритм Дейкстры довольно простой.
пробовал, расценки не устраиват.
Рейквестирую инфу. Работа на ПХП. Какой фреймворк учить? И если можно сразу гайдецов.
А можно без выебонов ответить?
Ничего не делать. Те, кто отключают куки, должны быть готовы что авторизация и сохранение настроек может перестать работать. Но может им это просто не нужно?
>Те, кто отключают куки
В последнее время постоянно вижу предупреждения на сайтах, что с выключенными куками многое недоступно, можно вот такое предупреждение выводить.
Все равно таких поехавших не так уж и много, скорее всего, от общего количества пользователей.
Когда кредитбаланс меньше манслипеймент, надо выплатить и оборвать цикл, иначе он закрутится надолго.
Также логика не чувствуется: когда кредитбаланс меньше 5000 - месячная выплата становится кредитбалансом - а дальше-то что?
А дальше её надо бы выплачивать и обрывать цикл как раз, а у тебя всё закручивается.
Я пытался сделать чтоб месячная выплата была столько, сколько осталось кредитбаланса, но не получается ничего.
А зачем именно месячную выплату менять?
Можно просто заплатить столько, сколько осталось - выйти из того круга, где отнимается месячная выплата.
Ты хотел, чтобы она поменялась, а потом цикла заново прошёлся и всё выплатилось, я правильно понял?
Так-то интересный подход, такого пока ещё не встречал.
Ошибка там в том, что цикл надо после этого последнего прохождения уже после изменения манслипеймент оборвать - иначе он снова попадает в условие "если кредитбаланс меньше 5000".
Попробуй разделить на if и else, например.
В else помести это всё, что у тебя до условий, а в if то же, что и есть, плюс вывод последнего echo с окончательной суммой.
в общем получилось как-то так http://ideone.com/9g8R4o Опять же не уверен, что сделал правильно, потому что не могу на 100% понять что делаю. Только в последний месяц он заплатил 5262.
Нет, неверно считает. Должно получиться 61270 и много цифр после точки.
Также неверно считает, если поставить сумму кредита 1000 - http://ideone.com/Ud7IPy
Должно ведь быть 2030 - сумма кредита, тысяча за обслуживание кредита и 30 - проценты от суммы кредита.
Смотрю на сам алгоритм: если осталось выплатить, например, 4000 уже после умножения на проценты и прибавления - у тебя от этого ещё раз отнимается сначала 5000 манслипеймент, уже в минусе попадает в условие, там меняется манслипеймент и ещё раз идёт в цикл.
В какой-то момент, короче, у тебя в минус уходит, этого не должно быть.
Да, скажите правду, какой самый лучший редактор.
Когда-то пробовал Sublime text, было про охуительно, есть ли что лучше?
Эх блин, он платный, воровать не хочется. А из бесплатных редакторов какой лучше?
VIM
atom
netbeans
notepad++
Рубисты в соседнем треде на китайском сервере активируются, может и со штормом заработает:
http://idea.lanyus.com/
>>635353
Ноуп, неправильно - ты и сам видишь.
Совет: введи дополнительную переменную для подсчёта долга без отнимания манслипеймент и проверяй в if, чтобы именно она была меньше 5000. Если именно этот долг (а не с отнятой месячной платой) меньше месячной платы - выплачивай именно его и прибавляй его к пейменттотал.
Все работает.
Папки nbproject и vendor надо убрать из репозитория и добавить в .gitignore.
https://github.com/toppestkek/GuestBook/blob/master/.htaccess
Вот тут я бы убрал <IfModule mod_rewrite.c>. Без него, если модуля нет, то будет ошибка 500. А с ним ошибка будет тихо проигнорирована, хотя приложение работать не будет.
Далее: http://pastebin.ru/98nq0FN7 так как сервер думает что это я его взломать пытаюсь текстом.
> $sentences = explode(PHP_EOL, $text);
Не советую. Надеюсь, ты знаешь что в разных ОС и разных редакторах конец строки кодируется по-разному: как \n или как \r\n (были еще варианты с \r на старых маках, но сейчас это неактуально). PHP_EOL на винде равен \r\n, под линуксом равен \n. Но где гарантия что в твоей программе использован тот же символ конца строки что и на платформе где она запускается? Гарантий нет. Значит, этот код может не сработать.
Правильнее всего бить на строки по символу \n (так как он входит в оба варианта), а потом отрезать \r если он есть, через trim. Либо бить регуляркой которая вырежет любой из вариантов (надо написать выражение "\n, перед которым может быть, а может не быть, \r").
> foreach($sentences as $key => &$value) {
Зачем тут & ? Также, называй переменные нормально, $value ничего не значит и ее надо переименовать.
> '/(?<!^)(?!$)/u'
Сложновато, по моему проще сделать preg_split("//u", $text, null, PREG_SPLIT_NO_EMPTY). //u соответствует границам между буквами, а константа в конце убирает пустые элементы в начале и конце массива.
> /заполняем остальные массивы пробелами, чтобы все стали равны/
Проще при выводе проверять в массиве мы или нет, и если нет то выводить пробел
> for ($c = 0; $c < $max; $c++){
> for ($e = 0; $e < count($letters); $e++ ){
Названия неудачные у переменных, может лучше было x/y?
> $max
maxLength
Вот эти названия, они очень важны, так как от них зависит, понятен твой код или его надо сидеть разбирать построчно. Это далеко не первая задача в учебнике, плохо что ты почти весь учебник прошел, а такую вещь не усвоил.
> $print = "";
Тут наверно проще сразу echo писать.
>>629943
Там есть какие-то программы, которые совмещают в себе редактор, интерпретатор пхп, веб-сервер и браузер для просмотра результата. Название плохо помню, попробуй поискать по словам вроде php editor.
Вот есть такое https://play.google.com/store/apps/details?id=ru.kslabs.ksweb , но это просто сервер (пхп + майэскуэл), без редактора и браузера (то есть нужен сторонний редактор кода и например встроенный браузер для запуска скрипта).
Есть такое https://play.google.com/store/apps/details?id=org.kidinov.awd но это редактор с браузером без сервера (в качестве него можно использовать приложение выше).
В общем, я думаю тебе придется порыться в маркете и потестировать приложения самому, у меня нет опыта кодинга на планшете. Можешь сюда скинуть ссылки на приложения, может кто-то прокомментирует.
В любом случае, тебе надо (по отдельности или в одном приложении):
- редактор кода с подсветкой
- веб-сервер (принимает запрос от браузера и запускает скрипт через интепретатор пхп)
- интерпретатор php, интегрированный с веб-сервером (то есть лучше если это в одном приложении) - выполняет скрипт
- браузер, годится стандартный, но встроенный в ИДЕ может быть удобнее тем что не надо переклюаться, а переключение приложений в андроиде неудобное. Нужен для запуска скрипта и просмотра результата.
- может быть, mysql
Программы могут быть платные или с рекламой, будь внимателен.
>>629949
Этот сайт генерирует только очень простые регулярки. Попробуй например с его помощью решить задачу про граммар наци. Да и если хорошо знать синтаксис, руками ты быстрее напишешь.
>>630081
Слышал звон, да не знаю, где он. Соль сильно замедляет перебор паролей, защищает от использования заранее вычисленных таблиц хешей и скрывает факт наличия одинаковых паролей в базе. Она нужна однозначно.
> $sentences = explode(PHP_EOL, $text);
Не советую. Надеюсь, ты знаешь что в разных ОС и разных редакторах конец строки кодируется по-разному: как \n или как \r\n (были еще варианты с \r на старых маках, но сейчас это неактуально). PHP_EOL на винде равен \r\n, под линуксом равен \n. Но где гарантия что в твоей программе использован тот же символ конца строки что и на платформе где она запускается? Гарантий нет. Значит, этот код может не сработать.
Правильнее всего бить на строки по символу \n (так как он входит в оба варианта), а потом отрезать \r если он есть, через trim. Либо бить регуляркой которая вырежет любой из вариантов (надо написать выражение "\n, перед которым может быть, а может не быть, \r").
> foreach($sentences as $key => &$value) {
Зачем тут & ? Также, называй переменные нормально, $value ничего не значит и ее надо переименовать.
> '/(?<!^)(?!$)/u'
Сложновато, по моему проще сделать preg_split("//u", $text, null, PREG_SPLIT_NO_EMPTY). //u соответствует границам между буквами, а константа в конце убирает пустые элементы в начале и конце массива.
> /заполняем остальные массивы пробелами, чтобы все стали равны/
Проще при выводе проверять в массиве мы или нет, и если нет то выводить пробел
> for ($c = 0; $c < $max; $c++){
> for ($e = 0; $e < count($letters); $e++ ){
Названия неудачные у переменных, может лучше было x/y?
> $max
maxLength
Вот эти названия, они очень важны, так как от них зависит, понятен твой код или его надо сидеть разбирать построчно. Это далеко не первая задача в учебнике, плохо что ты почти весь учебник прошел, а такую вещь не усвоил.
> $print = "";
Тут наверно проще сразу echo писать.
>>629943
Там есть какие-то программы, которые совмещают в себе редактор, интерпретатор пхп, веб-сервер и браузер для просмотра результата. Название плохо помню, попробуй поискать по словам вроде php editor.
Вот есть такое https://play.google.com/store/apps/details?id=ru.kslabs.ksweb , но это просто сервер (пхп + майэскуэл), без редактора и браузера (то есть нужен сторонний редактор кода и например встроенный браузер для запуска скрипта).
Есть такое https://play.google.com/store/apps/details?id=org.kidinov.awd но это редактор с браузером без сервера (в качестве него можно использовать приложение выше).
В общем, я думаю тебе придется порыться в маркете и потестировать приложения самому, у меня нет опыта кодинга на планшете. Можешь сюда скинуть ссылки на приложения, может кто-то прокомментирует.
В любом случае, тебе надо (по отдельности или в одном приложении):
- редактор кода с подсветкой
- веб-сервер (принимает запрос от браузера и запускает скрипт через интепретатор пхп)
- интерпретатор php, интегрированный с веб-сервером (то есть лучше если это в одном приложении) - выполняет скрипт
- браузер, годится стандартный, но встроенный в ИДЕ может быть удобнее тем что не надо переклюаться, а переключение приложений в андроиде неудобное. Нужен для запуска скрипта и просмотра результата.
- может быть, mysql
Программы могут быть платные или с рекламой, будь внимателен.
>>629949
Этот сайт генерирует только очень простые регулярки. Попробуй например с его помощью решить задачу про граммар наци. Да и если хорошо знать синтаксис, руками ты быстрее напишешь.
>>630081
Слышал звон, да не знаю, где он. Соль сильно замедляет перебор паролей, защищает от использования заранее вычисленных таблиц хешей и скрывает факт наличия одинаковых паролей в базе. Она нужна однозначно.
> В аплоадс у меня стоит хтаксесс с таким кодом, поэтому нельзя.
Ты по моему не очень понял как работает htaccess. Загрузка файла идет через скрипт index.php, потому настройки из htaccess вроде uploads_max_size в папке uploads не применяются. Настройки из uploads/.htaccess применяются только если из браузера запустить расположенный в этой папке скрипт. Также, у тебя есть php_flag engine 0 который запрещает выполнение скриптов из этой папки, но это мало:
- злоумышленник может загрузить свой htaccess и перезаписать твой
- на некоторых хостингах настройка php_flag игнорируется и твоя защита отключится
Надежнее переименовывать файлы с безопасным расширением.
>>Непарвильное использование иключений
> А какое правильное?
Правльно не ставить try/catch везде так как исключения были придуманы чтобы жтого не надо было делать. Пасты:
----------
Давай начнем с теории. Знаешь ли ты зачем придуманы исключения? Читал ли урок https://gist.github.com/codedokode/65d43ca5ac95c762bc1a
Если нет, прочитай.
До исключений мы должны были после каждой функции писать иф и проверять ее результат, не было ли ошибки. Исключения позволили отказаться от этого. Так как исключение автоматически выходит из вложенных вызовов функций наверх, нам достаточно одного-единственного обработчика исключений на самом верху:
try {
$app->run();
} catch (..) {
$app->showErrorPage();
}
Более того, мы можем и этого не делать, так как пхп сам ловит непойманные исключения, логгирует их, выводит пустую страницу в браузер и завершает скрипт.
Ловить исключения где-то еще надо если у нас есть способ обработать их. Ну например мы можем ловить ошибку соединения с удаленным сервером чтобы сделать еще несколько попыток. Очевидно что в этом случае мы ловим не все подряд, а конкретное исключение, отвечающее за ошибку соединения с сервером.
----------
Как надо обрабатывать исключения:
- записать информацию в лог
- показать пользователю заглушку
- на заглушке выставить HTTP 503 код ответа для роботов
- на компьютере разработчика (при display_errors = 1) показать подробности и стектрейс
Что будет если использовать catch + echo:
- в лог ничего не фиксируется, ты не узнаешь об ошибках
- пользователь видит непонятную белиберду на английском
- отдается код 200
Как будет если просто не ловить исключение:
- информация пишется в лог (ок)
- на компьютере разработчика выводятся подробности (ок)
- пользователь видит белую страницу (не ок)
- отдается код 200 (не ок)
-----------
> А хз, лень было писать заново мвк, взял из какого-то старого примера, в тестовом условием было не использовать фреймворки, так-то бы я взял нормальный роутер от микрофреймворка.
Значит надо пройти и исправить код на нормальный. Тем более если это тестовое задание - небрежно оформелнный код это хороший повод отказать кандидату так как после такого программиста код будет нечитаемым.
>>Инициализацию всяких объектов лучше вынести из контроллера.
> Куда это их вынести? В новый объект?
В файл где инициализаируется приложение - там можно создать нужные объекты-сервисы один раз и после этого везде их использовать.
> В аплоадс у меня стоит хтаксесс с таким кодом, поэтому нельзя.
Ты по моему не очень понял как работает htaccess. Загрузка файла идет через скрипт index.php, потому настройки из htaccess вроде uploads_max_size в папке uploads не применяются. Настройки из uploads/.htaccess применяются только если из браузера запустить расположенный в этой папке скрипт. Также, у тебя есть php_flag engine 0 который запрещает выполнение скриптов из этой папки, но это мало:
- злоумышленник может загрузить свой htaccess и перезаписать твой
- на некоторых хостингах настройка php_flag игнорируется и твоя защита отключится
Надежнее переименовывать файлы с безопасным расширением.
>>Непарвильное использование иключений
> А какое правильное?
Правльно не ставить try/catch везде так как исключения были придуманы чтобы жтого не надо было делать. Пасты:
----------
Давай начнем с теории. Знаешь ли ты зачем придуманы исключения? Читал ли урок https://gist.github.com/codedokode/65d43ca5ac95c762bc1a
Если нет, прочитай.
До исключений мы должны были после каждой функции писать иф и проверять ее результат, не было ли ошибки. Исключения позволили отказаться от этого. Так как исключение автоматически выходит из вложенных вызовов функций наверх, нам достаточно одного-единственного обработчика исключений на самом верху:
try {
$app->run();
} catch (..) {
$app->showErrorPage();
}
Более того, мы можем и этого не делать, так как пхп сам ловит непойманные исключения, логгирует их, выводит пустую страницу в браузер и завершает скрипт.
Ловить исключения где-то еще надо если у нас есть способ обработать их. Ну например мы можем ловить ошибку соединения с удаленным сервером чтобы сделать еще несколько попыток. Очевидно что в этом случае мы ловим не все подряд, а конкретное исключение, отвечающее за ошибку соединения с сервером.
----------
Как надо обрабатывать исключения:
- записать информацию в лог
- показать пользователю заглушку
- на заглушке выставить HTTP 503 код ответа для роботов
- на компьютере разработчика (при display_errors = 1) показать подробности и стектрейс
Что будет если использовать catch + echo:
- в лог ничего не фиксируется, ты не узнаешь об ошибках
- пользователь видит непонятную белиберду на английском
- отдается код 200
Как будет если просто не ловить исключение:
- информация пишется в лог (ок)
- на компьютере разработчика выводятся подробности (ок)
- пользователь видит белую страницу (не ок)
- отдается код 200 (не ок)
-----------
> А хз, лень было писать заново мвк, взял из какого-то старого примера, в тестовом условием было не использовать фреймворки, так-то бы я взял нормальный роутер от микрофреймворка.
Значит надо пройти и исправить код на нормальный. Тем более если это тестовое задание - небрежно оформелнный код это хороший повод отказать кандидату так как после такого программиста код будет нечитаемым.
>>Инициализацию всяких объектов лучше вынести из контроллера.
> Куда это их вынести? В новый объект?
В файл где инициализаируется приложение - там можно создать нужные объекты-сервисы один раз и после этого везде их использовать.
> 1) Задача про миллион в банке
> $sum <= 1000000;
Неточное условие, если ровно миллион накоплен, продолжать цикл не надо.
И форматирование поплыло, плохо, почитай второй пост треда. Ответ получился правильный.
> 2) Генератор стихов:
> [mt_rand(0,count($word1))]
Тут ошибка, в массиве нет элемента с индексом count(...).
Вот внизу видно это:
> PHP Notice: Undefined offset: 9 in /home/hS3YjN/prog.php on line 17
> PHP Notice: Undefined offset: 7 in /home/hS3YjN/prog.php on line 19
> палиндром
> $lower = mb_strtolower($text);
> $str = str_replace(" ", "", $lower);
Плохие названия переменных, в данном случае можно класть результат в ту же переменную $text.
> $secondHalf = mb_substr($str, -1, 1);
Это берет всегда последнюю букву, а не N-ю с конца.
> if ($i = $halfLenght) {
Неправильно, тут = обозначает присваивание и вместо сравнения в $i записывается значение справа. Надо писать == для сравнения. Ну и сравнив 2 буквы, писать что слово это палиндром - рано, надо сравнить остальные.
Эта задача пока решена неправильно.
>>630116
С такой манерой общаться ты ответа не дождешься.
> 1) Задача про миллион в банке
> $sum <= 1000000;
Неточное условие, если ровно миллион накоплен, продолжать цикл не надо.
И форматирование поплыло, плохо, почитай второй пост треда. Ответ получился правильный.
> 2) Генератор стихов:
> [mt_rand(0,count($word1))]
Тут ошибка, в массиве нет элемента с индексом count(...).
Вот внизу видно это:
> PHP Notice: Undefined offset: 9 in /home/hS3YjN/prog.php on line 17
> PHP Notice: Undefined offset: 7 in /home/hS3YjN/prog.php on line 19
> палиндром
> $lower = mb_strtolower($text);
> $str = str_replace(" ", "", $lower);
Плохие названия переменных, в данном случае можно класть результат в ту же переменную $text.
> $secondHalf = mb_substr($str, -1, 1);
Это берет всегда последнюю букву, а не N-ю с конца.
> if ($i = $halfLenght) {
Неправильно, тут = обозначает присваивание и вместо сравнения в $i записывается значение справа. Надо писать == для сравнения. Ну и сравнив 2 буквы, писать что слово это палиндром - рано, надо сравнить остальные.
Эта задача пока решена неправильно.
>>630116
С такой манерой общаться ты ответа не дождешься.
>PHP
>слушать порт
Дуин ит вронг.
>многопоточность
Можно тредами, можно просто рожать новые процессы (подобный подход в апаче и прогах написанных на erlang), можно poll/epoll/kqueue (так делает nginx).
К слову, в php есть pecl event (обёртка над libevent), а в его доках есть примеры).
http://docs.php.net/manual/en/event.examples.php - третий семпл, Echo server.
Но всё равно, писать сетевые сервисы на похапе - изврат лютый.
Какая-то таблица не существует, соррян, типа, азаза))0)))
>Если вас пропустили, не ответили, не проверили, не дали совет - напомните о себе в этом треде.
Меня пропустили. Анлаки.
Вынести код обработки формы в тот же файл, который отправляет форму.
Или вынести страницу обработки формы за корень сервера (тогда её нужно будет подключать через include).
я понимаю что ты тупая школота и лишь бы ответить, но почему к ней вообще идет запрос - подумай над этим, мидлом станешь базарю.
Чёт я сомневаюсь но всё же, вроде верно. Проверку на меньше ли нуля я убрал так как по идее оно должно(?) тютелька в тютельку забирать весь долг. Но сомнительно.
>$creditBalance = ( $creditBalance * $percent ) + $servicePayment - $creditBalance;
Шта?
Считает абсолютно неправильно, там должно получиться 61270 рублей и много копеек.
>if ($creditBalance >= 5000)
Не вполне правильно основные действия сразу связывать с подобным условием. Ведь $creditBalance у нас к моменту попадания в подобное условие уже должен быть умножен на 1.03 и с прибавленной комиссией за пользование кредитом.
Ок, буду снова думать.
Я писал $creditBalance = ( $creditBalance * $percent ) + $servicePayment - $creditBalance;
с логики мол если остаётся меньше 5000 после всех процентов и прибавлений, то просто отнимаем это всё финальным ходом.
Какая-то дурная задача, ну да ладно, я её-таки решу.
Вообще советую дополнительную переменную ввести для баланса кредита - баланс, умноженный на процент и с прибавленной комиссией, но без отниманий месячной выплаты и тому подобного.
Вот именно когда она становится меньше 5000 - нужно просто её выплатить и прибавить к общим выплатам, оборвать цикл.
У них на сайте нашел только этот http://www.slimframework.com/docs/ юзергайд, но там нет и половины того, что было в документации ко второй версии.
Да, это ко второму, но все равно спасибо.
Просто я невнимательный, уже нашел то что мне нужно тут http://www.slimframework.com/docs/handlers/error.html
Но я уже спрашивал насчёт алгоритмов. Можно ли решить без них(как предполагается по подсказке ОПа), а если нет, то где почитать вообще вводное что-либо про алгоритмы?
Я даже не слышал про них, погуглив - это кромешный ужас и пиздец, НИЧЕГО не понятно
Неправильный ответ, я делаю обычный селект, не стать тебе програмиздом, пиздуй в ашан.
Сделай необычный селект, вдруг поможет
5.1 которая?
Её вроде бы можно решить одним условием, если мне не изменяет память. Подумай каким.
Ну я думал сделать алгоритм, мол стандартный цикл, а в цикле идёт проверка - если долг с процентами и прибавкой за саму услугу больше или равно 5к, то стандартная выплата долга, если меньше, то вместо 5к мы отнимаем тот остаток вместе с процентами и прибавкой 1к. Потом смотрим если долг меньше 0, то значит завершаем брейком цикл и пишем "Хватит". Но что-то не то, надо нарисовать себе.
Это скриншот с ошибкой phpmyadmin. А что?
Если тебя интересует причина, гугли по тексту ошибки.
Из того что я нашел, вроде есть несколько вариантов:
1. Для использования некоторых специальных опций нужно создать дополнительные таблицы (Linked-tables infrastructure). Скрипт для создания этих таблиц лежит где-то в phpmyadmin/scripts/create_tables.sql
2. Баг pma на убунте.
3. Конфликт со сборкой.
Выводы: не пользоваться pma, wamp-сборками и прочими инструментами быдлокодера.
Консолькой.
:(
https://www.mysql.com/products/workbench/ из бесплатного например. Может с ним у тебя проще пойдет.
Ваше мнение очень важно для нас. Оставайтесь на линии.
>если долг с процентами и прибавкой за саму услугу больше или равно 5к, то стандартная выплата долга, если меньше, то вместо 5к мы отнимаем тот остаток вместе с процентами и прибавкой 1к.
>Потом смотрим если долг меньше 0, то значит завершаем брейком цикл и пишем "Хватит".
Всё абсолютно верно. Только если ты тот анон, которому я объяснял выше - у тебя от суммы кредита ещё и месячная выплата каждый раз отнимается, что путает всё, когда ты сравниваешь её с 5000 в одном условии.
Теперь то кажись правильно! http://ideone.com/NUiAXY
Пасибо анону, что посоветовал придумать новую переменную . Сам тогда об этом думал, но казалось что ничего нового не надо. И да, сначала выводило херню, думал ДА ЧТО ЖЕ ЭТО ТАКОЕ, а оказалось что надо в цикл впихнуть обьявление переменной. И то правильно - чтоб оно не 40000 постоянно брало а постоянно менялось.
Алсо, тут может быть небольшая ошибка когда я ставил условие проверки если будет меньше 0. Тупо не нужны эти строки наверное. Но хз.
upd
vim/atom/brackets/ваши приложения
Сублим не понравился.
Блокнот++
>$creditBalance = ($creditBalance * $percent) + $servicePayment - $monthlyPayment;
>$paymentTotal= $paymentTotal + $monthlyPayment;
>echo "{$month} месяц спустя: долг = {$creditBalance} руб, выплачено всего {$paymentTotal} руб. \n";
Ты копипастишь один и тот же код два раза. Я не понимаю зачем это.
Ну там не прям копипаста, один раз добавляет обычные 5к а другой - monthlyPayment.
Алсо, а что ты предлагаешь?
А что такое "нормальный" редактор?
Какой функционал тебе нужен?
Чем "сублим" не понравился?
Попробуй загуглить и проанализировать преимущества и недостатки.
Ну или подождать пока в этом треде проголосует каждый даун, которому понравилась цветовая схема конкретного редактора.
Cool story, bro
Редактировать значение переменной monthlyPayment, вместо того чтобы вводить новую переменную и сравнивать её каждый раз.
Сублим не приятен внешне, темы на него хуёвые, шрифты там говно, больше половины плагинов уёбищный, другая половина ебанутая.
Жрёт как атом (а атом лучше него в разы).
>>635946
Ну молодца! Я каждый раз радуюсь, когда кто-нибудь справляется с этой задачей - как будто я сам снова пережил то, как с ней справился.
Другой анон верно говорит: от копипасты надо избавляться, особенно, когда в цикле всё крутится и несколько раз считает одно и то же.
>$variable = ($creditBalance умножить $percent)
>$creditBalance = ($creditBalance умножить $percent) + $servicePayment - $monthlyPayment;
Это ведь тоже можно сократить.
Вообще всё условие if ($variable >= 5000) не особо и нужно - цикл сам по себе будет работать и всё делать, а должен среагировать только тогда, когда $variable < 5000.
Это можно даже не в else убрать, а просто так оставить в теле цикла.
>>635967
Можно и так, действительно.
Я тоже прям приток мотивации получил, как решил. Весь день думал да что ж не так. Аж с души камень.
Я вот так же сейчас сражаюсь с задачей на числа прописью.
Но у тебя до неё ещё несколько подобных будут: Grammar Nazi с исправлением текста, проверка телефонного номера, клавиша Shift.
Зато потом можно будет не глядя многое раскладывать, приобретается какой-то небольшой опыт.
Можно на пайтоне за пару часов написать скрипт который будет это делать на всех ОС. node.js нужен будет только если ты собираешься к этому парсеру еще и веб-сервер прикручивать.
>if ($creditBalance < 5000)
Это неправильно, тебе нужно в начале цикла посчитать сколько будет оплата за текущий месяц, потом ввести условие
если оплата за текущий месяц меньше переменной monthlyPayment {
monthlyPayment = оплата за текущий месяц
}
Попробуем на таком примере: есть таблица для хранения nested sets.
CREATE TABLE `category` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`lft` int(10) unsigned NOT NULL,
`root` int(10) unsigned NOT NULL,
`level` int(10) unsigned NOT NULL,
...
PRIMARY KEY (`id`),
KEY `ix_level_root_lft` (`level`,`root`,`lft`)
) ENGINE=InnoDB AUTO_INCREMENT=1000001 DEFAULT CHARSET=utf8
В таблице 1 000 000 записей.
Запрос:
SELECT id, lft, root, level FROM category WHERE level IN (1,2) ORDER BY root, lft; // наверное таки лучше between, но не суть важно
Explain:
id: 1
select_type: SIMPLE
table: category
type: range
possible_keys: ix_level_root_lft
key: ix_level_root_lft
key_len: 4
ref: NULL
rows: 39458
Extra: Using where; Using index; Using filesort
Здесь непонятен момент с filesort. Как говорит документация,
>MySQL must do an extra pass to find out how to retrieve the rows in sorted order. The sort is done by going through all rows according to the join type and storing the sort key and pointer to the row for all rows that match the WHERE clause. The keys then are sorted and the rows are retrieved in sorted order.
Если я правильно понял, будет совершен дополнительный проход, чтобы отсортировать данные в нужном порядке. Но зачем? Разве в индексе они не хранятся в отсортированном виде? Судя по key_len = 4, вторая и третья часть индекса вообще не используется.
Хотя судя по времени выполнения запроса, очень даже используется: с индексом только на (level) запрос 0.20с, индекс (level, root, lft) занимает 0.06с.
Что-то я не понимаю, как это работает.
Попробуем на таком примере: есть таблица для хранения nested sets.
CREATE TABLE `category` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`lft` int(10) unsigned NOT NULL,
`root` int(10) unsigned NOT NULL,
`level` int(10) unsigned NOT NULL,
...
PRIMARY KEY (`id`),
KEY `ix_level_root_lft` (`level`,`root`,`lft`)
) ENGINE=InnoDB AUTO_INCREMENT=1000001 DEFAULT CHARSET=utf8
В таблице 1 000 000 записей.
Запрос:
SELECT id, lft, root, level FROM category WHERE level IN (1,2) ORDER BY root, lft; // наверное таки лучше between, но не суть важно
Explain:
id: 1
select_type: SIMPLE
table: category
type: range
possible_keys: ix_level_root_lft
key: ix_level_root_lft
key_len: 4
ref: NULL
rows: 39458
Extra: Using where; Using index; Using filesort
Здесь непонятен момент с filesort. Как говорит документация,
>MySQL must do an extra pass to find out how to retrieve the rows in sorted order. The sort is done by going through all rows according to the join type and storing the sort key and pointer to the row for all rows that match the WHERE clause. The keys then are sorted and the rows are retrieved in sorted order.
Если я правильно понял, будет совершен дополнительный проход, чтобы отсортировать данные в нужном порядке. Но зачем? Разве в индексе они не хранятся в отсортированном виде? Судя по key_len = 4, вторая и третья часть индекса вообще не используется.
Хотя судя по времени выполнения запроса, очень даже используется: с индексом только на (level) запрос 0.20с, индекс (level, root, lft) занимает 0.06с.
Что-то я не понимаю, как это работает.
не траль:(
Кажется, понял (вернее, догадываюсь): чтобы работала сортировка по индексу, нужно поставить колонки из order by в начало (root, lft, level). Но меня это не устраивает, потому что тогда индекс не будет использован для where, вернее мы получим jointype = index вместо range, что означает фуллскан по индексу и увеличение времени в десятки раз (0.93с).
В общем, получается тут по-другому никак, индекс на (level, root, lft) оптимальный. Сортировка будет выполнена вторым проходом, но это не страшно, потому что данные берутся прямо из индекса (using index), к таблице вообще нет обращений.
Если же сделать индекс только на (level), то using index уже не будет, данные браться из таблицы а не индекса, а время увеличится в 3-4 раза.
Совсем хорошо было бы, если бы мне вообще не нужна была сортировка в запросе. В индексе (level, root, lft) данные уже отсортированы в соответствующем порядке. Меня правда этот порядок не очень устраивает, потому что я получу сначала все категории первого уровня, а потом уже все дочерние. Задача состояла именно в получении блоков вида корень+дети.
Или прямо в php отсортировать массив? Черт его знает.
Тебе нужно было сделать одно условие в начале цикла, как я написал тут >>636104
Зачем ты начал велосипеды строить?
>$creditBalance = ( $creditBalance * $percent ) + $servicePayment - $monthlyPayment;
>$paymentTotal = $paymentTotal + $monthlyPayment;
Вот это два раза копипастишь, когда этого делать совсем не нужно.
Просто описывай жизненный процесс в программе.
Один проход цикла это один месяц.
Что происходит вначале месяца? Банк начисляет проценты:
$creditBalance = ( $creditBalance * $percent ) + $servicePayment;
Что потом? Мамка дает школотрону 5000. Он идет в банк и узнает сколько осталось выплатить, если больше его 5000 платит сколько может (т.е. все 5000) если меньше платит сколько нужно и забывает про это все. (Выходит из цикла).
Тут был код, но я его удалил. Нужно все таки самому сделать условие.
>$creditBalance = ( $creditBalance $percent ) + $servicePayment - $monthlyPayment;
Когда у тебя $creditBalance становится, допустим, 3000 - ты отнимаешь от него $monthlyPayment, сумма уходит в минус, так не должно быть.
Тебе надо либо ввести переменную для подсчёта только ( $creditBalance $percent ) + $servicePayment, либо отнимать от$creditBalance эти самые 5000 в $monthlyPayment в основном условии, когда цикл продолжает работу.
А когда именно эта вот сумма ( $creditBalance $percent ) + $servicePayment становится меньше $monthlyPayment - именно тогда надо её выплатить, посчитать $paymentTotal и оборвать цикл.
И это можно сделать как изменением $monthlyPayment, так и простой выплатой вот этого окончательного ( $creditBalance $percent ) + $servicePayment (той самой переменной, о которой я и говорил).
>>636124
Советую помогать братишкам - так сам ещё лучше разберёшься в задаче, я базарю.
:(
W4.2 Сделай рулетку, то есть генерируется 6-значный номер поста, и, в зависимости от последней цифры, что-то пишется (что, придумай сам). Подсказка: чтобы найти последнюю цифру числа, возьми остаток от деления на 10: $lastDigit = $number % 10
Подсказка - случайное число в PHP генирирует функция rand.
http://php.net/manual/en/function.rand.php мануал
Блять, такое ощущение, что игнорируют. Просто игнорируют вопросы про алгоритмы!
В последнем if ошибка: там должно быть равно нулю, а не меньше.
Совет, который всё решит: просто вынеси в else то, что у тебя стоит в условии if ($gg > 5000). Попробуй, базарю - ещё захочешь.
Если хочешь в будущем быть fullstack разработчиком тебе обязательно нужно будет знать HTML и уметь верстать шаблоны любой сложности.
Я просто увяз в ХТМЛ и никак не дойду до главы с ООП и проч. Вот и думаю дропнуть пока этот ХТМЛ и вернуться к нему позже, если потребуется
спасибо няш:*
Можешь и так попробовать, но для задачи на список студентов, например, уже нужно будет уметь сверстать простой шаблон.
Увяз в HTML после Лилички, чисел пропись, калькулятора, ещё кучи сложных задач?..
Я не понимат.
>последние две задачи пропустил, чересчур сложные для меня
Последние две страницы с задачами, наверное?
Куда так торопишься-то? Получай удовольствие от того, что можешь, успеешь ещё во всём разобраться.
А то будешь как многие в треде: уже изучал, но всё забыл, на прошлой неделе писал сложный скрипт, а сейчас не могу вспомнить, как разложить массив в цикле.
Неосновательно как-то.
Я на правильном пути? http://ideone.com/wvluld Просто будет грустно если я опять делаю совсем не то.
Шаблон это визуальное представление в веб-приложении. Т.е. то, что видит и с чем взаимодействует пользователь.
Да нет, именно задачи. Ту, где буквы в круг встают - вообще убил мозг тригонометрией (не моё, сука, не моё).
И последнюю с навигатором. Оче долго пытал и мучал задачу, в итоге тут ОП посоветовал сделать по алгоритмам, а я впервые о них слышу и вообще не имею представления о них. Более внятной помощи не добился (посмотри по треду). Вот так и живу.
Братишка, вот тут правильный путь: >>636281
У тебя там путаница с лишними прохождениями цикла, это всё решит.
Ну и $creditBalance = 0 - это не сравнение, а присваивание.
Не elseif, а просто else - сам по себе будет цикл крутиться, пока не попадёт сначала в условие, что оставшаяся сумма меньше 5000, а потом в условие, что $creditBalance равняется 0.
Я знаю это чувство, бро.
Вторая неделя идёт битвы с числами прописью, хочется сделать по-человечески, а не через задницу.
Буквы в круге - мне бы хоть дойти...
На базовом уровне знаний недостаточно. Учи симфони, юи, ларваель и вордпресс до нормального уровня.
Иди на upwork.com и получай свои $500 в месяц.
Работа там в основном что-нибудь типа: Сверстать шаблон для вордпресса, натянуть шаблон на вордпресс, написать плагин для вордпресса, пофиксить баги в плагине для вордпресса, пофиксить баги в приложении на юи или симфони.
В /wrk/ есть годный тред по апворку, о русскоязычных фриланс-биржах даже не думай, там одно наебалово и зарплата в рублях.
И еще помни что фриланс на подобных сайтах это не сколько твои навыки в программировании, сколько твои социоблядские скиллы и умение себя продать, умение убедить клиента почему он должен нанять именно тебя, а не какого-нибудь индуса, который еще и денег меньше просит.
Щито такое вордпресс?
Можешь зайти и почитать описание заданий в категории web development. Большая половина там это вордпресс или какие-нибудь приложения на модных фреймворках. Бывают и заказчики которые абсолютно ничего не понимают в в вебе, и сами не знают чего они хотят.
Это еще нормально, там есть азиаты которые пытаются по английски писать, но у них это получается еще хуже чем у русских. В итоге уже на стадии описания задачи ты не понимаешь что от тебя нужно.
Cмотри сериалы, читай книжки. Где ты был все 25 лет, живёшь в чайнике?
Я вот смотрю ( не читаю правда, как-то пробовал осилить престолы в оригинале, дропнул после 250 страниц, слишком часто в словарь приходилось заглядывать). Воспринимать текст (ну и речь худо-бедно) и переводить могу, а вот говорить и выражать свои мысли очень туго выходит. Так что тут нужно еще и практиковаться с кем-нибудь или где-нибудь.
Вряд ли мне помогут сериалы, так как английский я не знаю вообще, знаю только на уровне человека, который постоянно сталкивается с английскими словами в рекламе и в интернете, но всё равно ничего не знаю. Есть ли какие-нибудь сервисы, есть ли в языках, вообще какая-то основа, поняв которую можно хоть немного понимать текст на английском? Например как правильно строить предложения и т.д. мне бы вот это узнать, а дальше уже буду каждый день обогащать словарный запас.
и говорю без шуток, там много на эту тему есть инфы
http://lingualeo.com/ тут есть тренировки и словарь. Еще советую поставить их одноименное расширение для браузера, которое по двойному клику на слове на любом сайте переводит его, потом ты можешь добавить его в свой словарь и потом тренировать.
Реквестирую - что надо знать и уметь для джуна.
Забудь об этом, ты слишком тупой, если не можешь додуматься открыть вакансии и посмотреть требования.
Конечно, если ты можешь написать приложение с соблюдением современных стандартов разработки, это похвально. Но от знания фреймворков, если вакансия того требует (а они все требуют), не освобождает.
Задания уровня "поставить вордпресс на хостинг", неудивительно. Ты не должен с ними конкурировать, учи технологии на хорошем уровне и там конкуренции будет меньше. Хотя конечно может стоит где-то в офисе поработать прежде чем на фриланс лезть, не знаю.
>>636297
кодеакадеми очень ознакомительного уровня.
Ну и у нас в ОП посте есть задания по ХТМЛ, тоже неплохие, обрати внимание.
>>636279
> Можно ли решить без них(как предполагается по подсказке ОПа), а если нет, то где почитать вообще вводное что-либо про алгоритмы?
Алгоритм это просто последовательность действий. Он есть в любой программе, даже если ты об этом не догадывался.
По поводу поиска пути, я сказал погуглить, ты гуглил?
Есть такая страница
https://ru.wikipedia.org/wiki/%D0%9F%D0%BE%D0%B8%D1%81%D0%BA_%D0%BF%D1%83%D1%82%D0%B8
И еще такая, интересная и подробная: http://pmg.org.ru/ai/stout.htm
Ты заметишь что там описывается путь по клеточкам, в то время как у нас граф из вершин и путей между ними. Но это одно и то же, так как карту с клеточками можно представить тоже в виде графа где каждая клеточка является вершиной.
Почитай все это. затем смотри сюда:
https://ru.wikipedia.org/wiki/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B5%D0%B9%D0%BA%D1%81%D1%82%D1%80%D1%8B
Святые угодники, это же готовый алгоритм поиска пути! Осталось в нем разобраться и реализовать.
Если что непонятно, задавай уточняющие вопросы. Можно использовтаь и другой алгоритм, можно попытаться понять что написал ОП в подсказках к задаче.
Задания уровня "поставить вордпресс на хостинг", неудивительно. Ты не должен с ними конкурировать, учи технологии на хорошем уровне и там конкуренции будет меньше. Хотя конечно может стоит где-то в офисе поработать прежде чем на фриланс лезть, не знаю.
>>636297
кодеакадеми очень ознакомительного уровня.
Ну и у нас в ОП посте есть задания по ХТМЛ, тоже неплохие, обрати внимание.
>>636279
> Можно ли решить без них(как предполагается по подсказке ОПа), а если нет, то где почитать вообще вводное что-либо про алгоритмы?
Алгоритм это просто последовательность действий. Он есть в любой программе, даже если ты об этом не догадывался.
По поводу поиска пути, я сказал погуглить, ты гуглил?
Есть такая страница
https://ru.wikipedia.org/wiki/%D0%9F%D0%BE%D0%B8%D1%81%D0%BA_%D0%BF%D1%83%D1%82%D0%B8
И еще такая, интересная и подробная: http://pmg.org.ru/ai/stout.htm
Ты заметишь что там описывается путь по клеточкам, в то время как у нас граф из вершин и путей между ними. Но это одно и то же, так как карту с клеточками можно представить тоже в виде графа где каждая клеточка является вершиной.
Почитай все это. затем смотри сюда:
https://ru.wikipedia.org/wiki/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B5%D0%B9%D0%BA%D1%81%D1%82%D1%80%D1%8B
Святые угодники, это же готовый алгоритм поиска пути! Осталось в нем разобраться и реализовать.
Если что непонятно, задавай уточняющие вопросы. Можно использовтаь и другой алгоритм, можно попытаться понять что написал ОП в подсказках к задаче.
Ищи уроки для начинающих, там как раз структуру предложений и разбирают. Английский за пару месяцев не выучить, так что готовься к долгому пути.
А просто интересно, ты пишешь свой магазин, а ты не пробовал в других движках ковыряться? Может интересное что подсмотрел бы.
https://github.com/lexdss/shop/blob/master/dump.sql#L92
> CONSTRAINT `order_product_ibfk_2` FOREIGN KEY (`product_id`) REFERENCES `product` (`id`) ON DELETE CASCADE
Правильно ли это - при удалении продукта удалять его их всех заказов? Я думаю, нет. Нужно запретить удаление продкутов если они использованы в заказе. Для скрытия с сайта сделать в продукте поле, отвечающее за скрытие/показ. Вообще, во многих случаях удаление данных нежелательно, если на эти данные где-то есть ссылки.
https://github.com/lexdss/shop/blob/master/dump.sql#L122
> CONSTRAINT `product_ibfk_1` FOREIGN KEY (`category`) REFERENCES `category` (`code`) ON DELETE CASCADE
Почему ссылка на категорию сделана через код, а не через первичный ключ? Не очень логично по моему. Ну или тогда надо в категориях убрать ид и сделать код первичным ключом.
> `role` enum('user','admin') DEFAULT NULL,
Может логичнее по дефолту ставить user? А нулл запретить?
https://github.com/lexdss/shop/blob/master/dump.sql#L151
> `date` datetime
Непонятно дата чего это. Название поля неудачное.
https://github.com/lexdss/shop/blob/master/app/autoloader.php
Тут унылая копипаста. Надо эти 5 функций объединить в одну. Ну, к примеру, ты можешь сделать массив с именами папок и перебирать их в цикле, ища в них файл. Более того, ты можешь добавить эти 5 папок в include_path ( http://php.net/manual/ru/function.set-include-path.php ) и тогда файл можно будет загрузить обычным require (а найти в какой именно папке файл через http://php.net/manual/ru/function.stream-resolve-include-path.php ). Более того, если у тебя папки включены в include_path и имя файла соответствует определенному шаблону то можно использовать стандартный автозагрузчик в функции spl_autoload. Почитай мануал на все эти темы.
Или ты мог бы освоить неймспейсы из этого урока: https://github.com/codedokode/pasta/blob/master/php/autoload.md и сделать автозагрузку с использованием PSR-4.
https://github.com/lexdss/shop/blob/master/app/config.php
Я думаю, использовать константы для конфига не очень хорошая идея. Константы доступны глобально, зачем нам это? Нам это не нужно. ЛУчше использовать обычные переменные.
Также, в конфиг надо выносить только настройки, что меняются пользователем. Нет смысла туда выносить VIEW_DIR.
https://github.com/lexdss/shop/blob/master/index.php#L10
> include VIEW_DIR.'503page.tpl.php';
Тут не очень понятно какой получается путь к файлу:
/app/view/503page.tpl.php
Это что, файл должен лежать в корне файловой системы? Ты проверял, работает ли это?
https://github.com/lexdss/shop/blob/master/index.php#L8
> error_log($e->getMessage());
Неправильно. Ты записываешь только текст ошибки, а имя файла, строку, где она произошла, стектрейс, УРЛ страницы - не запсиываешь. Какая польза от такого лога, по нему ты не найдешь даже что это за ошибка была. Надо как минимум записывать то что вернет $e->__toString(), там больше подробностей + УРЛ страницы добавить.
Также, непонятно почему ты ловишь только PDOException тут. Что, других видов исключений не бывает? Ловил бы все виды тогда.
https://github.com/lexdss/shop/blob/master/app/controller/FrontController.php
Код не рекомендации PSR отформатирован. После имени класса и функции скобка ставится на новой строке, а не на той же.
Нехорошо что у тебя в конструкторе фронт контроллера вызывается 404 и exit. Ненормально как-то завершать скрипт при попытке создать объект. Я думаю, код разбора надо поместить в метод вроде route(). Свойства controller, action можно выпилить и заменить на обычные переменные.
Далее, насчет сервисов. Сервисами я называю классы вроде PDO, Auth, мапперов. Видно, что они создаются у тебя где попало и как попало, такж видно что у тебя почему-то у всех контроллеров есть зависимость от Db что тоже не очень логично: может база данных ему и не нужна.
Эта проблема решается так: надо сделать класс, например Container или ServiceLocator, который умеет создавать сервисы по требованию, а при повторном вызове возвращать ранее созданный экземпляр. У этого класса будут методы вроде getPdo(), getSomeMapper(), getAuthManager() и тд. Он будет передаваться в конструктор контроллера, и тот из него получает нужные ему сервисы.
Контейнер существует в 1 экземпляре, создается в бутстрапе. Как передать в него настройки из конфига? Можно через конструктор
$container = new Container($settings);
можно через анонимную функцию, так:
$container->setPdoFactory(function () use ($settings) {
$pdo = new Pdo(...);
$pdo->setAttribute...
return $pdo;
});
Почитай про контейнер в Симфони - можно идею брать с него, он тоже там хранит в себе настройки и создает сервисы:
(рус) http://symfony-gu.ru/documentation/ru/html/book/service_container.html
(англ) http://symfony.com/doc/current/book/service_container.html
А просто интересно, ты пишешь свой магазин, а ты не пробовал в других движках ковыряться? Может интересное что подсмотрел бы.
https://github.com/lexdss/shop/blob/master/dump.sql#L92
> CONSTRAINT `order_product_ibfk_2` FOREIGN KEY (`product_id`) REFERENCES `product` (`id`) ON DELETE CASCADE
Правильно ли это - при удалении продукта удалять его их всех заказов? Я думаю, нет. Нужно запретить удаление продкутов если они использованы в заказе. Для скрытия с сайта сделать в продукте поле, отвечающее за скрытие/показ. Вообще, во многих случаях удаление данных нежелательно, если на эти данные где-то есть ссылки.
https://github.com/lexdss/shop/blob/master/dump.sql#L122
> CONSTRAINT `product_ibfk_1` FOREIGN KEY (`category`) REFERENCES `category` (`code`) ON DELETE CASCADE
Почему ссылка на категорию сделана через код, а не через первичный ключ? Не очень логично по моему. Ну или тогда надо в категориях убрать ид и сделать код первичным ключом.
> `role` enum('user','admin') DEFAULT NULL,
Может логичнее по дефолту ставить user? А нулл запретить?
https://github.com/lexdss/shop/blob/master/dump.sql#L151
> `date` datetime
Непонятно дата чего это. Название поля неудачное.
https://github.com/lexdss/shop/blob/master/app/autoloader.php
Тут унылая копипаста. Надо эти 5 функций объединить в одну. Ну, к примеру, ты можешь сделать массив с именами папок и перебирать их в цикле, ища в них файл. Более того, ты можешь добавить эти 5 папок в include_path ( http://php.net/manual/ru/function.set-include-path.php ) и тогда файл можно будет загрузить обычным require (а найти в какой именно папке файл через http://php.net/manual/ru/function.stream-resolve-include-path.php ). Более того, если у тебя папки включены в include_path и имя файла соответствует определенному шаблону то можно использовать стандартный автозагрузчик в функции spl_autoload. Почитай мануал на все эти темы.
Или ты мог бы освоить неймспейсы из этого урока: https://github.com/codedokode/pasta/blob/master/php/autoload.md и сделать автозагрузку с использованием PSR-4.
https://github.com/lexdss/shop/blob/master/app/config.php
Я думаю, использовать константы для конфига не очень хорошая идея. Константы доступны глобально, зачем нам это? Нам это не нужно. ЛУчше использовать обычные переменные.
Также, в конфиг надо выносить только настройки, что меняются пользователем. Нет смысла туда выносить VIEW_DIR.
https://github.com/lexdss/shop/blob/master/index.php#L10
> include VIEW_DIR.'503page.tpl.php';
Тут не очень понятно какой получается путь к файлу:
/app/view/503page.tpl.php
Это что, файл должен лежать в корне файловой системы? Ты проверял, работает ли это?
https://github.com/lexdss/shop/blob/master/index.php#L8
> error_log($e->getMessage());
Неправильно. Ты записываешь только текст ошибки, а имя файла, строку, где она произошла, стектрейс, УРЛ страницы - не запсиываешь. Какая польза от такого лога, по нему ты не найдешь даже что это за ошибка была. Надо как минимум записывать то что вернет $e->__toString(), там больше подробностей + УРЛ страницы добавить.
Также, непонятно почему ты ловишь только PDOException тут. Что, других видов исключений не бывает? Ловил бы все виды тогда.
https://github.com/lexdss/shop/blob/master/app/controller/FrontController.php
Код не рекомендации PSR отформатирован. После имени класса и функции скобка ставится на новой строке, а не на той же.
Нехорошо что у тебя в конструкторе фронт контроллера вызывается 404 и exit. Ненормально как-то завершать скрипт при попытке создать объект. Я думаю, код разбора надо поместить в метод вроде route(). Свойства controller, action можно выпилить и заменить на обычные переменные.
Далее, насчет сервисов. Сервисами я называю классы вроде PDO, Auth, мапперов. Видно, что они создаются у тебя где попало и как попало, такж видно что у тебя почему-то у всех контроллеров есть зависимость от Db что тоже не очень логично: может база данных ему и не нужна.
Эта проблема решается так: надо сделать класс, например Container или ServiceLocator, который умеет создавать сервисы по требованию, а при повторном вызове возвращать ранее созданный экземпляр. У этого класса будут методы вроде getPdo(), getSomeMapper(), getAuthManager() и тд. Он будет передаваться в конструктор контроллера, и тот из него получает нужные ему сервисы.
Контейнер существует в 1 экземпляре, создается в бутстрапе. Как передать в него настройки из конфига? Можно через конструктор
$container = new Container($settings);
можно через анонимную функцию, так:
$container->setPdoFactory(function () use ($settings) {
$pdo = new Pdo(...);
$pdo->setAttribute...
return $pdo;
});
Почитай про контейнер в Симфони - можно идею брать с него, он тоже там хранит в себе настройки и создает сервисы:
(рус) http://symfony-gu.ru/documentation/ru/html/book/service_container.html
(англ) http://symfony.com/doc/current/book/service_container.html
Также, зачем ты используешь сессию? Сессия лишь временное хранилоище и имеет недостатки, например диск замсоривается временными сессиями от ботов (они не сохраняют куки и каждый раз создают новую), сессия умирает через 30 минут неактивности и потому не годится для авторизации и тд. По моему для авторизации надежнее использовать куки, им можно выставить любой срок жизни.
> if(isset($_GET['act']) | $_GET['act'] == 'logout'){
| - это битовый оператор, а тебе нужно логическое или ||
Также, выражение написано неверно. Там явно должно быть И, а не ИЛИ.
> header('Location: '.$_SERVER['HTTP_REFERER']);
Это неправильный код, реферер может быть пуст, может указывать на ту же страницу, может на какой-то левый сайт и тд. Не стоит его вообще использовать. Адрес возврата лучше передавать явно, и следить что он не указывает на посторонний сайт (например, не включать в него имя домена).
Ну и логаут логичнее делать через ПОСТ так как он изменяет состояние залогиненности.
https://github.com/lexdss/shop/blob/master/app/controller/AController.php#L31
> //Перебрасываем на 404 если в контроллерах нет нужного экшена
Абсолютно неправильно. Проверку на отсутствие экшена надо делать в фронт контроллере, а так у тебя при опечатке в названии метода вместо ошибки в логе и ошибки 503 будет просто выдаваться страница 404. Бред же. Я вообще советую не использовать магические методы, от них проблем больше чем пользы.
https://github.com/lexdss/shop/blob/master/app/controller/AController.php#L15
Вот тут видна необходимость в контейнере служб.
> AController{
Название никуда не годится, что такое A?
https://github.com/lexdss/shop/blob/master/app/controller/CatController.php#L11
> //Для каждой категории выполняются одинаковые действия, чтобы не создавать одинаковые методы для каждой категории можно использовать магический метод
> public function __call($name, $args){
Какие-то костыли. По моему, тебе надо либо поменять УРЛ на формат /cat/index/some-category либо переделать роутинг чтобы он умел выделять имя категории как параметр. А не лепить костыли, делая вид как будто у тебя 20 разных экшенов.
> //Вместо categoryAction делаем category
> $this->category_code = str_replace('Action', '', $name);
someCategoryActionActionAction тоже будет тогда работать.
> FrontController::page404();
Имя метода должно начинаться с глагола. Также, мне не нравится тут статисеский метод, почему бы не сделать через $this->showErrorPage(404) или $this->showNotFoundPage()?
> if($_GET['add']){
Непонятно, почему добавление товара сделано методом ГЕТ, а не ПОСТ. Выучи-ка какие есть методы в HTTP и для чего они применяются. Также, непонятно, почему добавление товара делается через контроллер вывода товаров в категории. Это явно должно быть в другом месте.
Редирект обратно надо делать не через реферер, а через УРЛ, указанный в форме добавления в корзину.
Также, если в ГЕТ нет параметра add то тут будет ошибка. Ты ее не видишь скорее всего потмоу, что у тебя отключено отображение ошибок в конфиге пхп - надо его включить. Либо постоянно читать логи.
> //Если пришел параметр, загружаем детальную страницу товара, если нет - страницу категории
> if(!empty($_GET['item_id'])){
Это должно делаться не тут, а в роутере в фронт контроллере. Сделай отдельный УРЛ для товара вида /product/view/1234 либо /cat/guitar/123 и научи роутер его понимать.
> $user_validate->valid($_POST);
Имя функций начинается с глагола
> //В случае не пройденной валидации приходит массив ошибок, если пройдена - объект пользователя
Неудачно выбран тип возвращаемых значений. Функция не должна возвращать значения разных типов, значения должны быть одного типа, + null в некоторых случаях. Иначе легко наделать ошибок, и неудобно работать с такой функцией. Функция валидации может работать так:
$errors = validate(User $user); // Возвр. массив ошибок
$errorList = validate($user); // возвращает объект списка ошибок
$trueOrFalse = validate($user, &$errors); // заполняет массив ошибок
$trueOrFalse = validate($user, ErrorList $errors); // заполняет объект ошибок
Также, функция валидации должна заниматься только валидацией. А у тебя почему-то на нее переложена задача превращения массива в объект.
> $this->view->value = $_POST;
Плохая идея. ты не знаешь какие в этом массиве есть ключи, а какие нет, как ты будешь делать их вывод? Плюс, там может быть например массив вместо строки, это вызовет ошибки при попытке вывести через эхо.
> $this->user_mapper->save($result);
> //Получаем ID нового пользователя и сохраняем его в сессионной переменной
> $user = $this->user_mapper->getUserFromEmail($result->email)
Для получения id только что вставленной записи есть метод lastInsertId(). Получение надо делать сразу после вставки, в методе save, и записывать этот ид в объект пользователя.
Там наверно еще есть замечания, но на сегодня хватит этого, исправишь, будем смотреть дальше.
Также, зачем ты используешь сессию? Сессия лишь временное хранилоище и имеет недостатки, например диск замсоривается временными сессиями от ботов (они не сохраняют куки и каждый раз создают новую), сессия умирает через 30 минут неактивности и потому не годится для авторизации и тд. По моему для авторизации надежнее использовать куки, им можно выставить любой срок жизни.
> if(isset($_GET['act']) | $_GET['act'] == 'logout'){
| - это битовый оператор, а тебе нужно логическое или ||
Также, выражение написано неверно. Там явно должно быть И, а не ИЛИ.
> header('Location: '.$_SERVER['HTTP_REFERER']);
Это неправильный код, реферер может быть пуст, может указывать на ту же страницу, может на какой-то левый сайт и тд. Не стоит его вообще использовать. Адрес возврата лучше передавать явно, и следить что он не указывает на посторонний сайт (например, не включать в него имя домена).
Ну и логаут логичнее делать через ПОСТ так как он изменяет состояние залогиненности.
https://github.com/lexdss/shop/blob/master/app/controller/AController.php#L31
> //Перебрасываем на 404 если в контроллерах нет нужного экшена
Абсолютно неправильно. Проверку на отсутствие экшена надо делать в фронт контроллере, а так у тебя при опечатке в названии метода вместо ошибки в логе и ошибки 503 будет просто выдаваться страница 404. Бред же. Я вообще советую не использовать магические методы, от них проблем больше чем пользы.
https://github.com/lexdss/shop/blob/master/app/controller/AController.php#L15
Вот тут видна необходимость в контейнере служб.
> AController{
Название никуда не годится, что такое A?
https://github.com/lexdss/shop/blob/master/app/controller/CatController.php#L11
> //Для каждой категории выполняются одинаковые действия, чтобы не создавать одинаковые методы для каждой категории можно использовать магический метод
> public function __call($name, $args){
Какие-то костыли. По моему, тебе надо либо поменять УРЛ на формат /cat/index/some-category либо переделать роутинг чтобы он умел выделять имя категории как параметр. А не лепить костыли, делая вид как будто у тебя 20 разных экшенов.
> //Вместо categoryAction делаем category
> $this->category_code = str_replace('Action', '', $name);
someCategoryActionActionAction тоже будет тогда работать.
> FrontController::page404();
Имя метода должно начинаться с глагола. Также, мне не нравится тут статисеский метод, почему бы не сделать через $this->showErrorPage(404) или $this->showNotFoundPage()?
> if($_GET['add']){
Непонятно, почему добавление товара сделано методом ГЕТ, а не ПОСТ. Выучи-ка какие есть методы в HTTP и для чего они применяются. Также, непонятно, почему добавление товара делается через контроллер вывода товаров в категории. Это явно должно быть в другом месте.
Редирект обратно надо делать не через реферер, а через УРЛ, указанный в форме добавления в корзину.
Также, если в ГЕТ нет параметра add то тут будет ошибка. Ты ее не видишь скорее всего потмоу, что у тебя отключено отображение ошибок в конфиге пхп - надо его включить. Либо постоянно читать логи.
> //Если пришел параметр, загружаем детальную страницу товара, если нет - страницу категории
> if(!empty($_GET['item_id'])){
Это должно делаться не тут, а в роутере в фронт контроллере. Сделай отдельный УРЛ для товара вида /product/view/1234 либо /cat/guitar/123 и научи роутер его понимать.
> $user_validate->valid($_POST);
Имя функций начинается с глагола
> //В случае не пройденной валидации приходит массив ошибок, если пройдена - объект пользователя
Неудачно выбран тип возвращаемых значений. Функция не должна возвращать значения разных типов, значения должны быть одного типа, + null в некоторых случаях. Иначе легко наделать ошибок, и неудобно работать с такой функцией. Функция валидации может работать так:
$errors = validate(User $user); // Возвр. массив ошибок
$errorList = validate($user); // возвращает объект списка ошибок
$trueOrFalse = validate($user, &$errors); // заполняет массив ошибок
$trueOrFalse = validate($user, ErrorList $errors); // заполняет объект ошибок
Также, функция валидации должна заниматься только валидацией. А у тебя почему-то на нее переложена задача превращения массива в объект.
> $this->view->value = $_POST;
Плохая идея. ты не знаешь какие в этом массиве есть ключи, а какие нет, как ты будешь делать их вывод? Плюс, там может быть например массив вместо строки, это вызовет ошибки при попытке вывести через эхо.
> $this->user_mapper->save($result);
> //Получаем ID нового пользователя и сохраняем его в сессионной переменной
> $user = $this->user_mapper->getUserFromEmail($result->email)
Для получения id только что вставленной записи есть метод lastInsertId(). Получение надо делать сразу после вставки, в методе save, и записывать этот ид в объект пользователя.
Там наверно еще есть замечания, но на сегодня хватит этого, исправишь, будем смотреть дальше.
Кодировка виндоуз содержит 256 символов, утф-8 - десятки тысяч. Очевидно твоя функция будет терять символы, не входящие в кодировку виндоуз и лучше бы ее не использовать, чем потом разгребать эти проблемы. Если тебе надо перевернуть строку, ты можешь разбить ее на массив символов хаком с preg_split('//u'), перевернуть массив стандартной функцией и склеить обратно.
А про strrev лучше забыть - она безнадежно устарела.
https://github.com/someApprentice/Students/blob/master/app/config.php
В конфиге лучше не использовать DSN, а просто указать в массиве отдельно хост, базу, имя, пароль. Ведь редактировать конфиг может быть будет незнакомый с программированием человек. Еще лучше - вообще сделать конфиг в формате ini напрмиер, он очень простой и читабельный.
https://github.com/someApprentice/Students/blob/master/app/Controller/RegisterAction.php
В контроллерах надо отказаться от статических методов. Код на статических методах - это процедурщина, а не ООП.
https://github.com/someApprentice/Students/blob/master/app/Model/Gateway/TableDataGateway.php#L15
> public function addUser(User $user) {
Непонятно зачем эта функция в базовом классе, а не в UserTableGateway.
> Essence
то обычно назвают Entity
Также, не вижу особого смысла в папке Model, мне кажется папки из нее стоит вынести на один уровень с Controllers. Но можно и оставить.
Также, вот кусок совета предыдущему анону, он тебе тоже пригодится:
----------------
Далее, насчет сервисов. Сервисами я называю классы вроде PDO, Auth, мапперов. Видно, что они создаются у тебя где попало и как попало.
Эта проблема решается так: надо сделать класс, например Container или ServiceLocator, который умеет создавать сервисы по требованию, а при повторном вызове возвращать ранее созданный экземпляр. У этого класса будут методы вроде getPdo(), getSomeMapper(), getAuthManager() и тд. Он будет передаваться в конструктор контроллера, и тот из него получает нужные ему сервисы.
Контейнер существует в 1 экземпляре, создается в бутстрапе (инит.пхп). Как передать в него настройки из конфига? Можно через конструктор
$container = new Container($settings);
можно через анонимную функцию, так:
$container->setPdoFactory(function () use ($settings) {
$pdo = new Pdo(...);
$pdo->setAttribute...
return $pdo;
});
Почитай про контейнер в Симфони - можно идею брать с него, он тоже там хранит в себе настройки и создает сервисы:
(рус) http://symfony-gu.ru/documentation/ru/html/book/service_container.html
(англ) http://symfony.com/doc/current/book/service_container.html
----------------
Ну а продолжать писать код тебе надо в любом случае, не дожидаясь меня.
https://github.com/someApprentice/Students/blob/master/app/config.php
В конфиге лучше не использовать DSN, а просто указать в массиве отдельно хост, базу, имя, пароль. Ведь редактировать конфиг может быть будет незнакомый с программированием человек. Еще лучше - вообще сделать конфиг в формате ini напрмиер, он очень простой и читабельный.
https://github.com/someApprentice/Students/blob/master/app/Controller/RegisterAction.php
В контроллерах надо отказаться от статических методов. Код на статических методах - это процедурщина, а не ООП.
https://github.com/someApprentice/Students/blob/master/app/Model/Gateway/TableDataGateway.php#L15
> public function addUser(User $user) {
Непонятно зачем эта функция в базовом классе, а не в UserTableGateway.
> Essence
то обычно назвают Entity
Также, не вижу особого смысла в папке Model, мне кажется папки из нее стоит вынести на один уровень с Controllers. Но можно и оставить.
Также, вот кусок совета предыдущему анону, он тебе тоже пригодится:
----------------
Далее, насчет сервисов. Сервисами я называю классы вроде PDO, Auth, мапперов. Видно, что они создаются у тебя где попало и как попало.
Эта проблема решается так: надо сделать класс, например Container или ServiceLocator, который умеет создавать сервисы по требованию, а при повторном вызове возвращать ранее созданный экземпляр. У этого класса будут методы вроде getPdo(), getSomeMapper(), getAuthManager() и тд. Он будет передаваться в конструктор контроллера, и тот из него получает нужные ему сервисы.
Контейнер существует в 1 экземпляре, создается в бутстрапе (инит.пхп). Как передать в него настройки из конфига? Можно через конструктор
$container = new Container($settings);
можно через анонимную функцию, так:
$container->setPdoFactory(function () use ($settings) {
$pdo = new Pdo(...);
$pdo->setAttribute...
return $pdo;
});
Почитай про контейнер в Симфони - можно идею брать с него, он тоже там хранит в себе настройки и создает сервисы:
(рус) http://symfony-gu.ru/documentation/ru/html/book/service_container.html
(англ) http://symfony.com/doc/current/book/service_container.html
----------------
Ну а продолжать писать код тебе надо в любом случае, не дожидаясь меня.
> mt_rand(1, count($word1));
Индексы идут от 0 до каунт - 1.
>>630629
Выражение слишком сложное, попробуй записать так:
- +7 или 8, за ними ровно 10 цифр между которыми могут быть пробелы, минусы, скобки в любом порядке и количестве.
Ну и проверь свой код на списке номеров:
Правильные: array('84951234567', '+74951234567', '8-495-1-234-567', ' 8 (8122) 56-56-56', '8-911-1234567', '8 (911) 12 345 67', '8-911 12 345 67', '8 (911) - 123 - 45 - 67', '+ 7 999 123 4567', '8 ( 999 ) 1234567', '8 999 123 4567');
Неправильные: array('02', '84951234567 позвать люсю', '849512345', '849512345678',
'8 (409) 123-123-123', '7900123467', '5005005001', '8888-8888-88',
'84951a234567', '8495123456a',
'+1 234 5678901', // неверный код страны
'+8 234 5678901', // либо 8 либо +7
'7 234 5678901' // нет +
);
Также, есть такой сайт: https://regex101.com/r/qF7vT8/3 - там уже вбиты номера и на нем можно простестировать свою регулярку и проверить что она соответствует правильным и не соответствует неправильным номерам. Помни что на этом сайте надо писать бекслеш один раз, например \s, а не \\s. Флаг m там стоит чтобы ^ и $ в регулярке обозначали «начало и конец любой строки», а не «начало и конец всего текста». Флаг g (его нет в PHP, он только на этом сайте) значит что надо искать все совпадения с регуляркой, а не только первое.
>>630637
Для сложных пхп-заданий понадобится HTML, так что лучше начать с него либо параллельно учить.
>>630765
Всегда есть не требующие высокой квалификации должности.
>>630865
Так нельзя?
function () use ($x) {
echo $x;
}
> mt_rand(1, count($word1));
Индексы идут от 0 до каунт - 1.
>>630629
Выражение слишком сложное, попробуй записать так:
- +7 или 8, за ними ровно 10 цифр между которыми могут быть пробелы, минусы, скобки в любом порядке и количестве.
Ну и проверь свой код на списке номеров:
Правильные: array('84951234567', '+74951234567', '8-495-1-234-567', ' 8 (8122) 56-56-56', '8-911-1234567', '8 (911) 12 345 67', '8-911 12 345 67', '8 (911) - 123 - 45 - 67', '+ 7 999 123 4567', '8 ( 999 ) 1234567', '8 999 123 4567');
Неправильные: array('02', '84951234567 позвать люсю', '849512345', '849512345678',
'8 (409) 123-123-123', '7900123467', '5005005001', '8888-8888-88',
'84951a234567', '8495123456a',
'+1 234 5678901', // неверный код страны
'+8 234 5678901', // либо 8 либо +7
'7 234 5678901' // нет +
);
Также, есть такой сайт: https://regex101.com/r/qF7vT8/3 - там уже вбиты номера и на нем можно простестировать свою регулярку и проверить что она соответствует правильным и не соответствует неправильным номерам. Помни что на этом сайте надо писать бекслеш один раз, например \s, а не \\s. Флаг m там стоит чтобы ^ и $ в регулярке обозначали «начало и конец любой строки», а не «начало и конец всего текста». Флаг g (его нет в PHP, он только на этом сайте) значит что надо искать все совпадения с регуляркой, а не только первое.
>>630637
Для сложных пхп-заданий понадобится HTML, так что лучше начать с него либо параллельно учить.
>>630765
Всегда есть не требующие высокой квалификации должности.
>>630865
Так нельзя?
function () use ($x) {
echo $x;
}
Покажи написанный код, напиши на чем застрял, попроси подсказки. Тяжело в учении, легко в бою.
>>630931
По историческим причинам, в Си расположение элемента массива в памяти получают сложением адреса начала массива и индекса, соответсвтенно первый элемент должен иметь индекс ноль. Привыкай.
Ну и это ведь от задачи зависит, может где-то индекс ноль имеет смысл.
>>630937
Вообще конечно с точки зрения человека первый элемент логичнее обозначать индексом 1.
>>631098
Ну вот, рад что кому-то задачи приносят удовольствие.
>>631079
Держи готовый алгоритм:
- прибавляем проценты и комиссию к остатку долга (!не вычитаем ничего пока!)
- если остаток маленький, выплачиваем сколько осталось и уходим
- иначе платим 5000
«Платим» здесь значит уменьшаем долг и увеличиваем общую сумму выплаченного.
>>631120
> в другой - (id, user_id(кто поставил), like_user(кому поставил))
В качестве первичного ключа можно использовать пару (user_id, like_user), а id выпилить.
> Как тут можно подсчитать одновременно сколько юзер поставил лайков и сколько ему? Если я сгруппирую так GROUP BY user.id (или user_id, неважно), то через COUNT смогу соответственно подсчитать сколько он лайков поставил, но не смогу подсчитать сколько ему поставили потому что COUNT зависит от GROUP BY. А еесли так GROUP BY like_user, то смогу подсчитать сколько пользователю поставили лайков, но теперь не смогу подсчитать сколько он поставил.
Да, верно. Более того, если ты попытаешься к таблице юзеров приджойнить таблицу лакйов 2 раза (полученные и отданные лайки) то ты вообще получишь в COUNT число всех комбинаций отданных и полученных лайков (например для 4 полученных и 5 отданных получится 20 комбинаций).
Казалось бы, выхода нет. Но на деле надо просто внимательно изучить синтаксис функции COUNT:
http://phpclub.ru/mysql/doc/group-by-functions.html
Может что-нибудь придет в голову? И да, задача решается в 2 джойна без подзапросов. Ну иил может ты найдешь еще более короткий способ.
>>631145
напомню загадку, которую я загадал: в дебиане не ставятся пакеты через менеджер пакетов, ошибок не выводится, есть ли идеи почему?
>>631168
Конечно будет, достаточно одной таблицы связи
Покажи написанный код, напиши на чем застрял, попроси подсказки. Тяжело в учении, легко в бою.
>>630931
По историческим причинам, в Си расположение элемента массива в памяти получают сложением адреса начала массива и индекса, соответсвтенно первый элемент должен иметь индекс ноль. Привыкай.
Ну и это ведь от задачи зависит, может где-то индекс ноль имеет смысл.
>>630937
Вообще конечно с точки зрения человека первый элемент логичнее обозначать индексом 1.
>>631098
Ну вот, рад что кому-то задачи приносят удовольствие.
>>631079
Держи готовый алгоритм:
- прибавляем проценты и комиссию к остатку долга (!не вычитаем ничего пока!)
- если остаток маленький, выплачиваем сколько осталось и уходим
- иначе платим 5000
«Платим» здесь значит уменьшаем долг и увеличиваем общую сумму выплаченного.
>>631120
> в другой - (id, user_id(кто поставил), like_user(кому поставил))
В качестве первичного ключа можно использовать пару (user_id, like_user), а id выпилить.
> Как тут можно подсчитать одновременно сколько юзер поставил лайков и сколько ему? Если я сгруппирую так GROUP BY user.id (или user_id, неважно), то через COUNT смогу соответственно подсчитать сколько он лайков поставил, но не смогу подсчитать сколько ему поставили потому что COUNT зависит от GROUP BY. А еесли так GROUP BY like_user, то смогу подсчитать сколько пользователю поставили лайков, но теперь не смогу подсчитать сколько он поставил.
Да, верно. Более того, если ты попытаешься к таблице юзеров приджойнить таблицу лакйов 2 раза (полученные и отданные лайки) то ты вообще получишь в COUNT число всех комбинаций отданных и полученных лайков (например для 4 полученных и 5 отданных получится 20 комбинаций).
Казалось бы, выхода нет. Но на деле надо просто внимательно изучить синтаксис функции COUNT:
http://phpclub.ru/mysql/doc/group-by-functions.html
Может что-нибудь придет в голову? И да, задача решается в 2 джойна без подзапросов. Ну иил может ты найдешь еще более короткий способ.
>>631145
напомню загадку, которую я загадал: в дебиане не ставятся пакеты через менеджер пакетов, ошибок не выводится, есть ли идеи почему?
>>631168
Конечно будет, достаточно одной таблицы связи
У тебя неправильный код, должно быть так:
$app->get("/files/:id", $test);
А ты вместо функции передаешь результат ее вызова, это не то.
https://jsbin.com/pakonaseho/1/edit?js,console
>>631243
> designationSize
Имена функций начинаются с глагола.
try/catch делать не надо, ловить исключение должен тот, кто использует твой класс, а не ты сам. А то исключение до него просто не дойдет. Почитай-ка урок про исключения https://gist.github.com/codedokode/65d43ca5ac95c762bc1a
Твой класс ничего не должен писать в консоль, только возвращать результат или бросать исключение.
> hamburger.addTopping("MAYO");
В задаче написано что обозначать тип добавок должна константа, а не строка. Константы делают код понятным и защищают от ошибок.
В полях объекта не надо хранить цены и прочее, храни только тип гамбургера, а цену можно потом найти по нему.
> for(var key in this.settingsHamburger["topping"]) {
> if(topping === key) {
> this.topping.push(this.settingsHamburger["topping"][topping]);
Проверку правильности и добавление надо сделать отдельно, а не вместе. Также, нет проверки на повторное добавление той же добавки.
> if(this.stuffing === undefined || this.size === undefined) throw new Error("Недостаточно данных");
Надо на уровне конструктора сделать так, чтобы такая ситуация с пустыми полями была невозможна.
> (this.topping[0] ? this.topping[0]["calories"] : 0) +
> (this.topping[1] ? this.topping[1]["calories"] : 0);
Не надо закладывать ограничение на максимум 2 добавки.
>>631637
Гугл даст
>>631735
Такое возможно, но через кликджекинг, то есть надо чтобы ты кликнул на невидимый виджет, например кнопку лайка, которая двигается по странице за курсором.
>>631761
Пока пользователь не кликнул, нельзя получить его аккаунт. Алсо те кто выкладывает о себе инфу вконтакте сами виноваты.
>>631985
Что-то у тебя тут многовато кода. Неужели нельзя это упростить? Конечно, можно.
И считает оно как-то неправильно. Должно получиться - всего выплачено 61270 р. А у тебя там больше почему-то.
Давай начнем с простого примера: анон берет кредит на 1000 р и через месяц выплачивает 2030р с учетом всех накруток: http://ideone.com/7uWggK
Твоя программа ушла куда-то в минус. Правильный алгоритм такой:
- прибавляем проценты и комиссию к остатку долга (!не вычитаем ничего пока!)
- если остаток маленький, выплачиваем сколько осталось и уходим
- иначе платим 5000
«Платим» здесь значит уменьшаем долг и увеличиваем общую сумму выплаченного.
У тебя неправильный код, должно быть так:
$app->get("/files/:id", $test);
А ты вместо функции передаешь результат ее вызова, это не то.
https://jsbin.com/pakonaseho/1/edit?js,console
>>631243
> designationSize
Имена функций начинаются с глагола.
try/catch делать не надо, ловить исключение должен тот, кто использует твой класс, а не ты сам. А то исключение до него просто не дойдет. Почитай-ка урок про исключения https://gist.github.com/codedokode/65d43ca5ac95c762bc1a
Твой класс ничего не должен писать в консоль, только возвращать результат или бросать исключение.
> hamburger.addTopping("MAYO");
В задаче написано что обозначать тип добавок должна константа, а не строка. Константы делают код понятным и защищают от ошибок.
В полях объекта не надо хранить цены и прочее, храни только тип гамбургера, а цену можно потом найти по нему.
> for(var key in this.settingsHamburger["topping"]) {
> if(topping === key) {
> this.topping.push(this.settingsHamburger["topping"][topping]);
Проверку правильности и добавление надо сделать отдельно, а не вместе. Также, нет проверки на повторное добавление той же добавки.
> if(this.stuffing === undefined || this.size === undefined) throw new Error("Недостаточно данных");
Надо на уровне конструктора сделать так, чтобы такая ситуация с пустыми полями была невозможна.
> (this.topping[0] ? this.topping[0]["calories"] : 0) +
> (this.topping[1] ? this.topping[1]["calories"] : 0);
Не надо закладывать ограничение на максимум 2 добавки.
>>631637
Гугл даст
>>631735
Такое возможно, но через кликджекинг, то есть надо чтобы ты кликнул на невидимый виджет, например кнопку лайка, которая двигается по странице за курсором.
>>631761
Пока пользователь не кликнул, нельзя получить его аккаунт. Алсо те кто выкладывает о себе инфу вконтакте сами виноваты.
>>631985
Что-то у тебя тут многовато кода. Неужели нельзя это упростить? Конечно, можно.
И считает оно как-то неправильно. Должно получиться - всего выплачено 61270 р. А у тебя там больше почему-то.
Давай начнем с простого примера: анон берет кредит на 1000 р и через месяц выплачивает 2030р с учетом всех накруток: http://ideone.com/7uWggK
Твоя программа ушла куда-то в минус. Правильный алгоритм такой:
- прибавляем проценты и комиссию к остатку долга (!не вычитаем ничего пока!)
- если остаток маленький, выплачиваем сколько осталось и уходим
- иначе платим 5000
«Платим» здесь значит уменьшаем долг и увеличиваем общую сумму выплаченного.
https://github.com/MindiMakridi/filehosting/blob/master/files.sql#L29
> `upload_time` int(11) NOT NULL,
Почему тип поменял? В БД есть специальный тип для дат, надо использовать его, а не лепить числа. Преобразование типов можно делать в маппере.
https://github.com/MindiMakridi/filehosting/blob/master/public/index.php#L51
> $files = $app->filesMapper;
> $lastUploadedFiles = $files->fetchLastUploadedFiles();
> $app->render("main.html.twig", array(
> 'files' => $lastUploadedFiles,
> 'filesHelper' => $app->filesHelper
Нехорошо что ты тут одинаковые вещи называешь разными именами. Это путает.
> $app->get("/files/:id", $pageFunc);
> $app->post("/files/:id", $pageFunc);
Это можно сделать без вынесения функции в переменную, через $app->map(...)->via(..): http://docs.slimframework.com/routing/custom/
https://github.com/MindiMakridi/filehosting/blob/master/public/index.php#L67
> $file = new Filehosting\File;
> $file->setComment($app->request->post('comment'));
> $file->setToken($app->request->post('token'));
Здесь ты создаешь какой-то неполноценный объект у которого не заполнена часть полей. Это плохо, надо либо загружать из базы полноценный объект и делать правки в нем, либо не использовать тут объект, а использовать обычные переменные.
https://github.com/MindiMakridi/filehosting/blob/master/public/index.php#L79
> if (!$file = $files->fetchFile($id)) {
> $app->notFound();
Это наверно в начале функции, а не в середине должно идти.
https://github.com/MindiMakridi/filehosting/blob/master/public/index.php#L82
> if (!isset($comment)) {
Не должно быть такого, что непонятно, существует переменная или нет. Как писать надежный код в таком случае? Как его читать?
https://github.com/MindiMakridi/filehosting/blob/master/public/index.php#L116
> $app->get("/thumbs/:id/:fileName"
Нужно ли здесь имя в конце? Превьюшка же не предназначена для скачивания. Хотя хорошее имя может помочь роботам проиндексировать картинку, пусть будет тогда.
https://github.com/MindiMakridi/filehosting/blob/master/public/index.php#L119
> $thumbName = "thumb." . $app->filesHelper->getFileExtension($file);
Получение имени превьюшки хорошо бы тоже вынести в метод, а не размазывать по коду несколько раз.
https://github.com/MindiMakridi/filehosting/blob/master/public/index.php#L133
Валидацию файла при загрузке хорошо бы сразу вынести в функцию, чтобы код тут не разрастался. При ошибке надо повторно вывести форму с сообщением.
Обработчик загрузки файла можно объединить с обработчиком вывода главной страницы.
> $files->beginTransaction();
> $id = $files->addFile($file);
> $file->setId($id);
> $tmpName = $_FILES['userfile']['tmp_name'];
> if ($app->filesHelper->saveFile($tmpName, $file)) {
> $files->commit();
> } else {
> $files->rollBack();
Вот это все логично вынести в метод в хелпере. чтобы мы например легко могли загрузить файл откуда-то еще через этот метод.
https://github.com/MindiMakridi/filehosting/blob/master/models/File.php
Я тут подумал, выбрасывать исключение для пустого свойства не очень логично. Может мы хотим проверить, заполнен ли id, а как это сделать? Непонятно.
https://github.com/MindiMakridi/filehosting/blob/master/models/FilesMapper.php#L24
> $id = $this->dbh->lastInsertId();
Логично бы этот ид прямо в объект файла и сохранять.
https://github.com/MindiMakridi/filehosting/tree/master/models/helpers
Нейсмпейсы принято писать с большой буквы, надо переименовать папку. под виндой это придется делать через 2 переименования, так как она не видит разницы между буквами разного регистра.
https://github.com/MindiMakridi/filehosting/blob/master/models/helpers/FilesHelper.php#L48
Тут надо проверять не только является ли он какртинкой, но и можно ли для него сгенерировать превью. Причем проверка поддерживаемых форматов по логике должна быть в классе-генераторе превьюшек.
https://github.com/MindiMakridi/filehosting/blob/master/files.sql#L29
> `upload_time` int(11) NOT NULL,
Почему тип поменял? В БД есть специальный тип для дат, надо использовать его, а не лепить числа. Преобразование типов можно делать в маппере.
https://github.com/MindiMakridi/filehosting/blob/master/public/index.php#L51
> $files = $app->filesMapper;
> $lastUploadedFiles = $files->fetchLastUploadedFiles();
> $app->render("main.html.twig", array(
> 'files' => $lastUploadedFiles,
> 'filesHelper' => $app->filesHelper
Нехорошо что ты тут одинаковые вещи называешь разными именами. Это путает.
> $app->get("/files/:id", $pageFunc);
> $app->post("/files/:id", $pageFunc);
Это можно сделать без вынесения функции в переменную, через $app->map(...)->via(..): http://docs.slimframework.com/routing/custom/
https://github.com/MindiMakridi/filehosting/blob/master/public/index.php#L67
> $file = new Filehosting\File;
> $file->setComment($app->request->post('comment'));
> $file->setToken($app->request->post('token'));
Здесь ты создаешь какой-то неполноценный объект у которого не заполнена часть полей. Это плохо, надо либо загружать из базы полноценный объект и делать правки в нем, либо не использовать тут объект, а использовать обычные переменные.
https://github.com/MindiMakridi/filehosting/blob/master/public/index.php#L79
> if (!$file = $files->fetchFile($id)) {
> $app->notFound();
Это наверно в начале функции, а не в середине должно идти.
https://github.com/MindiMakridi/filehosting/blob/master/public/index.php#L82
> if (!isset($comment)) {
Не должно быть такого, что непонятно, существует переменная или нет. Как писать надежный код в таком случае? Как его читать?
https://github.com/MindiMakridi/filehosting/blob/master/public/index.php#L116
> $app->get("/thumbs/:id/:fileName"
Нужно ли здесь имя в конце? Превьюшка же не предназначена для скачивания. Хотя хорошее имя может помочь роботам проиндексировать картинку, пусть будет тогда.
https://github.com/MindiMakridi/filehosting/blob/master/public/index.php#L119
> $thumbName = "thumb." . $app->filesHelper->getFileExtension($file);
Получение имени превьюшки хорошо бы тоже вынести в метод, а не размазывать по коду несколько раз.
https://github.com/MindiMakridi/filehosting/blob/master/public/index.php#L133
Валидацию файла при загрузке хорошо бы сразу вынести в функцию, чтобы код тут не разрастался. При ошибке надо повторно вывести форму с сообщением.
Обработчик загрузки файла можно объединить с обработчиком вывода главной страницы.
> $files->beginTransaction();
> $id = $files->addFile($file);
> $file->setId($id);
> $tmpName = $_FILES['userfile']['tmp_name'];
> if ($app->filesHelper->saveFile($tmpName, $file)) {
> $files->commit();
> } else {
> $files->rollBack();
Вот это все логично вынести в метод в хелпере. чтобы мы например легко могли загрузить файл откуда-то еще через этот метод.
https://github.com/MindiMakridi/filehosting/blob/master/models/File.php
Я тут подумал, выбрасывать исключение для пустого свойства не очень логично. Может мы хотим проверить, заполнен ли id, а как это сделать? Непонятно.
https://github.com/MindiMakridi/filehosting/blob/master/models/FilesMapper.php#L24
> $id = $this->dbh->lastInsertId();
Логично бы этот ид прямо в объект файла и сохранять.
https://github.com/MindiMakridi/filehosting/tree/master/models/helpers
Нейсмпейсы принято писать с большой буквы, надо переименовать папку. под виндой это придется делать через 2 переименования, так как она не видит разницы между буквами разного регистра.
https://github.com/MindiMakridi/filehosting/blob/master/models/helpers/FilesHelper.php#L48
Тут надо проверять не только является ли он какртинкой, но и можно ли для него сгенерировать превью. Причем проверка поддерживаемых форматов по логике должна быть в классе-генераторе превьюшек.
http://ideone.com/NuO5fo
Надо проверить это на списке номеров, скорее всего работать не будет так как у тебя жестко задано как цифры сгруппированы в номере, лучше этого не делать, а просто разрешить любое число пробелов, минусов, скобок между цифрами.
> регулярка тест на граммар наци
> $regexp1 = '/[+7]/';
Тут неправильно, квадратные скобки значат "любой один из символов, либо + либо 7", а не последовательность 2 символов.
>>632214
От оставшегося, невыплаченного долга.
>>632400
Бессмысленное усложнение, так как очень сложно запрограммированть выполнение всех нужных действий при переходе с страниц разного типа. Аякс полезнее при действиях вроде поставить лайк, добавить комментарий, раскрыть блок, где пользователь делает какое-то действие не уходя со страницы.
>>632510
По моим ощущениям, внешние библиотеки удобнее, а ксс селекторы нагляднее xpath
>>632548
Все верно работает, только в условии в цикле лучше писать $i <= 2, а то можно подумать что цикл 3 раза выполняется.
>>632569
Она в старых версиях пхп принимала аргументы в любом порядке, возможно по этой причине.
>>632704
> if (this._elements.getPowerProduction) {
Не нравится мне что-то это, метод может быть, а может не быть. Нехорошо, лучше сделать чтобы он всегда был, но например возвращал 0 по умолчанию.
> return profit result;
Я думаю, лучше бы сделать функцию, которая бы вычисляла и возвращала в виде словаря:
- избыток ли у нас энергии
- недостаток ли энергии
- величину избытка/недостатка
- цену покупки или прибыль от продажи
- удалось ли закупить или продать
А потом можно сделать вывод этой информации в любом виде.
> if (powerExcess > this._powerCapacity) {
> return this._powerCost (this._powerCapacity / PowerLine.MW);
Тут можно использовать min/max вместо if.
А так, пока получается неплохо, почти все сделано уже.
>>632746
ЧТобы не было копипасты, надо код разбить на функции, например:
- функция записи числа от 0 до 999 слвоами
- функция выбора формы слова (тысяча/тысяч)
- функция которая разобъет число на группы по 3 цифры и запишет словами
>>633021
Код надо разбивать на функции, такая стена текста это перебор.
Определение формы слова не стоит делать так:
> 'рубль' => array(1),
> 'рубля' => array(2, 3, 4),
> 'рублей' => array(0, 5, 6, 7, 8,
Вообще форма слова в русском зависит только от последней цифры, исключение - это если число заканчивается на 11-19. Соответственно надо ифами это проверять. Всего может быть 3 формы слова: 1 рубль, 2 рубля, 5 рублей.
Разбивать число на цифры надо математически, есть такие варианты:
// получить последние 3 цифры числа:
echo 1234567 % 1000; // выведет 567
// получить число миллионов
echo floor(1234678 / 1000000); // выведет 12
Комбинируя их, можно получить что угодно.
Преобразование числа в текст делается примерно так:
- если есть слово для сотен, ставим его
- если есть десятки, ставим
- если число оканчиваетя на 11-19, ставим слово
- если есть единицы, ставим слово для них
>>633167
Решено правильно.
http://ideone.com/NuO5fo
Надо проверить это на списке номеров, скорее всего работать не будет так как у тебя жестко задано как цифры сгруппированы в номере, лучше этого не делать, а просто разрешить любое число пробелов, минусов, скобок между цифрами.
> регулярка тест на граммар наци
> $regexp1 = '/[+7]/';
Тут неправильно, квадратные скобки значат "любой один из символов, либо + либо 7", а не последовательность 2 символов.
>>632214
От оставшегося, невыплаченного долга.
>>632400
Бессмысленное усложнение, так как очень сложно запрограммированть выполнение всех нужных действий при переходе с страниц разного типа. Аякс полезнее при действиях вроде поставить лайк, добавить комментарий, раскрыть блок, где пользователь делает какое-то действие не уходя со страницы.
>>632510
По моим ощущениям, внешние библиотеки удобнее, а ксс селекторы нагляднее xpath
>>632548
Все верно работает, только в условии в цикле лучше писать $i <= 2, а то можно подумать что цикл 3 раза выполняется.
>>632569
Она в старых версиях пхп принимала аргументы в любом порядке, возможно по этой причине.
>>632704
> if (this._elements.getPowerProduction) {
Не нравится мне что-то это, метод может быть, а может не быть. Нехорошо, лучше сделать чтобы он всегда был, но например возвращал 0 по умолчанию.
> return profit result;
Я думаю, лучше бы сделать функцию, которая бы вычисляла и возвращала в виде словаря:
- избыток ли у нас энергии
- недостаток ли энергии
- величину избытка/недостатка
- цену покупки или прибыль от продажи
- удалось ли закупить или продать
А потом можно сделать вывод этой информации в любом виде.
> if (powerExcess > this._powerCapacity) {
> return this._powerCost (this._powerCapacity / PowerLine.MW);
Тут можно использовать min/max вместо if.
А так, пока получается неплохо, почти все сделано уже.
>>632746
ЧТобы не было копипасты, надо код разбить на функции, например:
- функция записи числа от 0 до 999 слвоами
- функция выбора формы слова (тысяча/тысяч)
- функция которая разобъет число на группы по 3 цифры и запишет словами
>>633021
Код надо разбивать на функции, такая стена текста это перебор.
Определение формы слова не стоит делать так:
> 'рубль' => array(1),
> 'рубля' => array(2, 3, 4),
> 'рублей' => array(0, 5, 6, 7, 8,
Вообще форма слова в русском зависит только от последней цифры, исключение - это если число заканчивается на 11-19. Соответственно надо ифами это проверять. Всего может быть 3 формы слова: 1 рубль, 2 рубля, 5 рублей.
Разбивать число на цифры надо математически, есть такие варианты:
// получить последние 3 цифры числа:
echo 1234567 % 1000; // выведет 567
// получить число миллионов
echo floor(1234678 / 1000000); // выведет 12
Комбинируя их, можно получить что угодно.
Преобразование числа в текст делается примерно так:
- если есть слово для сотен, ставим его
- если есть десятки, ставим
- если число оканчиваетя на 11-19, ставим слово
- если есть единицы, ставим слово для них
>>633167
Решено правильно.
С фреймворками разберусь, пробовал YII 2 понял всё то что касается работы с базами данных и некоторые другие вопросы, однако, общей сути всёравно не понял. Что ты имеешь в виду под стандартами современной разработки приложений?
Имена функций должны начинаться с глагола.
Возвращаемые значения должны быть осмысленные, например true/false, а не непонятные строки.
Смысл переменной $a непонятен, что тебе сразу мешало в ифе условие проверить? Проверка сделана неверно, так как ключи в массиве могут идти в любом порядке, а у тебя предполагается определенный порядок.
Ну и наконец задача решается без циклов.
>https://github.com/someApprentice/Students/blob/master/app/Controller/RegisterAction.php
>В контроллерах надо отказаться от статических методов. Код на статических методах - это процедурщина, а не ООП.
А что тогда писать сначала $registeraction = new RegusterAction();? Зачем? Ведь тоже самое будет. Что плохого в такой "процедурщине"? Тем более init тоже процедурно написан. Не понимаю.
>>636495
>https://github.com/someApprentice/Students/blob/master/app/Model/Gateway/TableDataGateway.php#L15
>> public function addUser(User $user) {
>Непонятно зачем эта функция в базовом классе, а не в UserTableGateway.
Просто как пример для самого себя.
А если бы, например, за место студентов у нас были простые юзеры, и, при этом, я бы не хотел наследовать и писать новый класс как бы приходилось писать эту функцию? public function addRecord(Record $record)? Или всегда обязательно писать новый класс?
Накидайте задачек для вхождения. (Учебник смотрел, а войти в ООПне смог)
Если ты помнишь:
Алгоритм такой:
1. Имеем сумму кредита.
2. Прибавляем к ней нужный процент и прибавляем комиссию за обслуживание кредита.
3. Проверяем, получившаяся сумма больше или меньше 5000, которые может выплачивать Анончик в месяц.
4. В соответствии с результатом проверки или продолжаем цикл выплат, или выплачиваем имеющуюся сумму и обрываем цикл (не забывай про пункт 1, что она у нас уже должна быть умножена на процент и к ней уже должна быть прибавлена комиссия за обслуживание кредита).
Всё.
Я опять ебусь с этой задачей. Если в п.1 только считаем сумму, то когда вычитать месячный платёж?
Решил в итоге вот так. По-моему в описанный тобой алгоритм опять не уложился - http://ideone.com/J7rb0R
Считает неправильно. В этой задаче конечный результат будет 61270 рублей с копейками.
>>636639
>>636636
Вот. Теперь не баланс отнимается от баланса, а высчитывается последний платёж - http://ideone.com/J7rb0R
Балять
>Всего выплачено 50000
А должно быть
>61270 рублей с копейками
Зачем ты там $creditBalance делишь на 100? Насколько я помню, там такого делать не нужно.
Чтоб процент узнать. В итоге получается так: имеющаяся сумма + процент + платёж за обслуживание. Нет?
Вот же у тебя переменная $percent, это и будет твой процент. В данном случае это 3%, значит тебе нужно
$creditBalance умножить на $percent + платеж за обслуживание - оплата за месяц
Смотри, у ОПа $percent задан как 1,03 вот на этом скрине. Это опечатка? Должно быть 0,03?
Нет, не опечатка. Так и должно быть.
Таким образом считаются проценты за месяц. Текущая сумма умноженная на 1,03 (03 - 3%). Т.е. каждый месяц к сумме кредита начисляются 3%.
А, я всё понял. Это чтоб лишнее действие не делать, можно сразу умножить на 1,03
Задание 11. Сверстай изображенный на картинке текст. Обрати внимание, размер картинки должен определятся так: большая картинка — ужимается до ширины окна (с учетом полей конечно), маленькая — выводится как есть. HTML-код добрый дядя уже написал и выложил тут: http://pastebin.com/s1P96nVA, тебе надо лишь добавить свой CSS.
Но там только 1 картинка в коде. И что делать с текстом? Не очень ясно
Бери какой-нибудь пайтон, там есть все что тебе нужно для этого. На пхп для такого приложения можно было бы сделать бэкэнд, а фронт на каком-нибудь модном реакте или ангуляре. Но это веб-приложение, если ты хочешь сделать на десктоп, тебе в другой тред.
(то есть, каждый год на счету становится на 10% больше, чем в прошлом году).
Напиши программу, считающую, через сколько лет в банке будет миллион?
Сколько лет будет этому некто? Доживет ли некто до этого дня, если сегодня ему 16 лет?
Что-то я не совсем понял какой тут должен быть цикл.
Можно сделать цикл с годами депозита, т.е. начиная с единички, но при этом непонятно по какой год, т.е. не катит.
Можно сделать с годами вкладчика, но опять же, он может умереть до того момента.
Можно сделать цикл с 10000 и вплоть до ляма, это подойдет? И тут цикл надо обязательно for? While как-то посимпатичнее выглядит для этого.
что я делаю не так в последнем задании (#13)?
мой говнозапрос
http://pastebin.com/Pvfu9h4j
>2. Прибавляем к ней нужный процент и прибавляем комиссию за обслуживание кредита.
>$creditBalance = $creditBalance + ($creditBalance / 100 звёздочка $percent) + $servicePayment - $monthlyPayment;
>По-моему в описанный тобой алгоритм опять не уложился
Yep. Не надо отнимать месячную плату в основном цикле, потому что у нас всё улетит в минус.
В какой-то момент получится, допустим, $creditBalance = 3000, а ты тут же отнимешь от этой суммы 5000 $monthlyPayment - всё уйдёт в минус и в таком виде попадёт в условие if ($creditBalance < $monthlyPayment).
Совет тот же, который я давал другому братишке: попробуй либо ввести дополнительную переменную для проверки $creditBalance без вычета $monthlyPayment, либо ставь в условии, что $monthlyPayment в последний момент становится равной чистому $creditBalance (без отнятой $monthlyPayment!), а потом выплачивается, после чего цикл обрывается.
Первый вариант как-то естественнее.
>>636668
>у ОПа $percent задан как 1,03 вот на этом скрине
Да, это чтобы сразу получить $creditBalance с прибавленными 3%.
>>636753
>Можно сделать цикл с 10000 и вплоть до ляма, это подойдет?
Конечно. Нам же важно узнать, когда именно сумма вклада станет равной 1млн, к этому и стоит привязать цикл.
>И тут цикл надо обязательно for? While как-то посимпатичнее выглядит для этого.
Попробуй сначала, как проще, а потом поменяй циклы, например.
>Вообще форма слова в русском зависит только от последней цифры, исключение - это если число заканчивается на 11-19. Соответственно надо ифами это проверять. Всего может быть 3 формы слова: 1 рубль, 2 рубля, 5 рублей.
Там у меня столько разных if и else получается, что лишнего не хотелось бы.
Спасибо за советы, ОП, постараюсь применить.
Вчера вот только сделал полное разложение трёх чисел с подстановкой "рублей" - уже с помощью деления.
Хороший совет математически разбивать на тройки, я думал опять с помощью перевода числа в строку решить. Попробую и так, и так.
Тот код со стеной текста я просто не стал оптимизировать, там многое можно сократить - махнул рукой, потому что в тот момент не подумал, как можно было продолжить соединение этих частей для разложения.
Кстати, правильно сделал, что так всё наглядно разложил - сколько в какой месяц выплачивается. Я тоже так делал, когда решал.
Но вот поэтому сразу видно, что у тебя в первом же действии ошибка:
>Месяц 1
>Баланс кредита \t36412
А должно быть 37200.
40000 + 3% + 1000 - 5000 = 37200.
Задача 5.2. Делаю цикл - начиная с 10к и вплоть до цифры что больше или равно миллиону(момент когда Некто всё-таки получает нужную сумму) мы выводим на экран цифры переменных и останавливаем цикл. В самом цикле повышение годов(возраст Некто и срок депозита) идёт после проверки, чтоб не добавлять в нулевой год и месяц.
Что не так?
>Почитай про контейнер в Симфони - можно идею брать с него, он тоже там хранит в себе настройки и создает сервисы:
>$container->setDefinition(...);
Вот я не понимаю такие статьи - как я могу понять как настраивать контейнер, если я не знаю что делает эта функция? Дальше просто комом становиться непонятно что написано в статье. ОП, я нормален?
Можно, но пхп не для этого сделан.
Ахаха, бро, ты отжёг!
Я тоже путаю знаки "больше" и "меньше".
Подсказка (сначала сам всё-таки поищи ошибку): цикл и не работает из-за того, что в условии внутри цикла то же выражение стоит, что и в условии для работы самого цикла. Он же должен работать, когда вклад меньше миллиона...
Также каждый раз при прохождении цикла баланс у тебя становится 10000 - это у тебя определяется в самом цикле ведь.
Это надо вынести за пределы цикла, поставить перед ним.
>Я тоже путаю знаки "больше" и "меньше".
Используй хинт: С какой стороны символ больше, с такой и значение больше
min < max
max > min
Также после условий с if ставить изменения переменных - неправильно.
Надо или перед условием, или в else.
Тогда получается что в самом начале прибавляется плюс один год и там и там, но вклад остаёся 10к.
Я почти серьёзен был в тот момент.
Ну, каждый раз представляю первое число и второе, какое больше и какое меньше, чтобы определить, в какую сторону повернуть знак.
Для этого и нужен else.
<?php
$string = 'The quick brown fox jumped over the lazy dog.';
$patterns = array();
$patterns[0] = '/quick/';
$patterns[1] = '/brown/';
$patterns[2] = '/fox/';
$replacements = array();
$replacements[2] = 'bear';
$replacements[1] = 'black';
$replacements[0] = 'slow';
echo preg_replace($patterns, $replacements, $string);
?>
пиздец что за дауны тут сидят. шли бы в 1 цээ что ли.
Чтобы показать, что и в этом случае будет замена идти по порядку ключей, а не расположения.
Или наоборот - я с телефона и не проверю сейчас.
А что делать, если я привык смотреть на "острие" треугольной скобки, а не на "рот"?
Не надо меня путать, пожалуйста!
Я вот пользуют Штормом и сейчас наткнулся на статью, как прикрутить Опен Сервер на него и Хдебаг. Для чего это? Может кто-нибудь как дауну разжевать? Вообще не понимаю
Пиздец я даун, как же худо даётся всё это. А с сервером как? Зачем какой-то Апач или ОпенСервер ставить на Шторм, если и так программы запускает? Зачем?!
А человеку который далек от программирования ты тоже будешь советовать шторм ставить для запуска твоих скриптов? Я вот например не пользуюсь ИДЕ, пишу в редакторе, поэтому мне необходим сервер чтобы тестировать то что получилось. Точно так же сервер будет необходим чтобы запускать твои скрипты для использования.
Помимо IDE, а не на неё. Сервер будет ещё одним диском в "Компьютере".
РНРStorm запускает скрипты без установки сервера? Ох щи, а я думал, что тут как и с другими IDE - устанавливать сервер.
>РНРStorm запускает скрипты без установки сервера? Ох щи, а я думал, что тут как и с другими IDE - устанавливать сервер.
Там у них какой-то свой интерпретатор стоит, который криво работает. Для комфортной работы лучше поставить сервер.
Выложи уже все пасты в виде гист, неудобно же каждый раз клянчить.
p.s. Как на сосаче происходит автообновление? Сижу набираю пост, тут раз, и все подвисает на секунду, потому что очередной дебил что-то запостил.
Джаваскрипт блокирует ввод на время выполнения запроса? Не могу найти это место в коде.
https://2ch.hk/makaba/templates/js/swag.js (М)
> (621) var that = this;
Каков затейник.
> (4949) function updatePosts
Непонятная мешанина колбеков и прочего добра. Я вот не знаю, как буду работать. Скажут пофиксить такой код, буду наверное дня три только сидеть и разбирать последовательность вызовов.
Хм. А зачем люди тогда ставят сервер НА шторм? Это меня больше всего вымораживает
>>637020
Да всё запускается спокойно, жил не тужил и только тут понимаю, что какие-то сервера, малафья есть ещё.
И по поводу дебаггера - вроде поставил его на Шторм. ЗАЧЕМ ОН? Да, статью на вики видел и читал, но зачем? Показывать ошибки в синтаксисе? Так ИДЕ же это исполняет.
>А зачем люди тогда ставят сервер НА шторм?
Чтобы работать удобнее было. Гораздо комфортнее что-нибудь делать, когда ты знаешь что у тебя стоит настроенный тобою же сервер и интерпретатор. Плюс так удобнее тестировать, не нужно ничего заливать по фтп и прочее.
>Да, статью на вики видел и читал, но зачем? Показывать ошибки в синтаксисе?
Чтобы отлаживать программу в процессе её работы. С помощью дебаггера ты сможешь остановить выполнение скрипта в любой момент, и посмотреть текущее значение любой переменной. Так же, с помощью дебаггера можно выполнять программу по шагам и смотреть что происходит в нужных тебе ситуациях. Это очень полезно когда у тебя какая-то ошибка в скрипте и ты не можешь понять почему она возникает.
Cпасибо, хоть что-то проясняется. В итоге у меня как-то криво хдебаг встал на Шторм и теперь он пишет, что нет дебагера, но кое-как его запускает(по крайней мере, перестал ругаться на его отсутствие при запуске). Хуй знает, короче, не понимаю нихуя, сейчас компьютер буду ебашить кулаком
>который криво работает
Помню, аноны просили ОПа установить РНРСторм, чтобы проверить, что в их скриптах всё работает.
А на Идеоне не работало в тот же момент.
>Гораздо комфортнее что-нибудь делать, когда ты знаешь что у тебя стоит настроенный тобою же сервер и интерпретатор.
То есть таки можно на шторм поставить сервер? Я не понимаааат.
Можно, читай
https://www.jetbrains.com/phpstorm/help/creating-a-local-server-configuration.html для локального сервера
https://www.jetbrains.com/phpstorm/help/creating-a-remote-server-configuration.html для удаленного сервера
Алсо, начиная с версии 5.4 в пхп есть встроенный веб-сервер, у JetBrains и это в справке есть.
https://www.jetbrains.com/phpstorm/help/php-built-in-web-server.html
Спасибо, годно, надо вникнуть.
Ну я хочу для практики что-то наподобии форума написать. Хватит или нет?
То есть можно и не ставить? Какие преимущества будут, если поставить?
Всего 500 долларов? А как на такие деньги жить (живу не в СНГ, тут ни в одну контору без образования не берут, уже 5 контор прошёл).
Можно и больше, зависит от твоих скиллов и от того, сколько времени ты этому будешь уделять.
learn.javascript.ru
У меня в стране чтобы не мереть с голода надо хотя бы 2к долларов в месяц зарабатывать. Лол
Что за страна такая?
Тогда это скорее всего не для тебя. Можешь искать в офисах стажировки и превозмогать.
Скорее в вебе платят недостаточно. На каких-нибудь плюсах или шарпе платят побольше, но там вакансий меньше и работа сложнее.
Ребят помогите пожалуйста "W5.1 Исправь и переделай программу, чтобы она работала нормально. Например, эта версия позволяет школьнику переплатить за кредит, так, что банк ему становится должен — это плохо! Подсказка: перед тем, как платить, надо проверять, сколько осталось долга, и если он меньше 5000, то платить только остаток и завершать цикл через break" как заставить его платить остаток ??
>foreach($offers as &$sentence)
Объясни, плиз, как работает такая конструкция?
Что даёт & перед $sentence?
А так очень хорошо решено ОП потом что-нибудь найдёт наверняка - у него дельные замечания обычно.
Но вот массив с регулярками и реплейсментом сразу можно было готовым сделать, а не набивать его после начала работы скрипта.
Вот так:
$regexp = array('/[ ][,][ ]/u', '/[ ][!][ ]/u', '/[ ][?][ ]/u', '/[ ][.][ ]/u');
$replacements = array(', ', '! ', '? ', '. ');
Эффект будет тот же, разумеется.
Едритские звёздочки, всё время забываю.
http://pastebin.com/1iYpcSXF - твои массивы с регулярками и заменами.
Не мог бы ты поподробней ответить каких именно?
>Объясни, плиз, как работает такая конструкция?
>Что даёт & перед $sentence?
foreach ($arr as &$value) == foreach ($arr as $key => $value)
Ясно, неплохо, спасибо, не дошёл ещё до этого, хотя читал уже про & для ссылок внутри скрипта.
Многое проще будет удаваться записывать.
Я по ходу сказочный долбоёб. 4 дня без отрыва решаю задачу с циклом и до сих пор не решил её. Какой пиздец, товарищи...
Я сам решал не меньше, базарю.
При этом я каждый раз с самого начала переписывал скрипт полностью. После седьмого переписывания перестал считать.
У меня там было одно решение, в котором я расписал отдельно в echo, сколько прибавляется процентов именно каждый месяц, как всё отнимается ближе к концу, чтобы понять, где я промахиваюсь.
Но общая плата у меня почти сразу стала верной, не получалось от минуса избавиться, в который всё неизбежно уходило, пока анон не надоумил ввести дополнительную переменную для расчёта кредита без вычета месячной платы.
А сейчас я буквально с закрытыми глазами могу написать решение, при этом до сих пор помню некоторые цифры из решения - типа 262 рублей под конец, общей выплаты в 61270 и т.п.
Цикл как любой проходит - просто с закрытыми глазами вижу, многое стал предугадывать в работе циклов - благодаря ОПу и этой задачке.
Короч надо сделать что-то типо интернет магазина, который не имеет собственного склада, а формирует ассортимент из других магазинов.
Инфу о товарах других магазов можно брать по сути только с их страниц.
Сколько такая хуита обойдётся в деньгах и часах работы?
http://www.youtube.com/watch?v=mnT2zCXunuc
Не такое?
А так, скорее всего, надо будет магазин свой поднять, а дальше подключить парсер. Тысяч около 20 за установку, настройку купленного ContentDownloader'а какого-нибудь.
Только толку от такого будет немного, базарю.
Типо такого, но можно намного проще.
Толк понятно, что никакой, один мудак хочет сделать приложение, которое будет давать инфу по другим магазам, скидкам, хуиткам, понятное дело, что человеку проще в гугле погуглить пол часа, чем платить за какое-то приложение и искать что-то в нём пол часа.
Меня интересовал чисто ценовой вопрос, потому что в вебе не секу.
>один мудак хочет сделать приложение, которое будет давать инфу по другим магазам, скидкам, хуиткам
Идея хорошая, но уже реализована Яндексом.
У него есть какой-то бар, который даже когда ты находишься на магазине Эльдорадо, покажет тебе, что на магазине М.Видео этот товар дешевле на столько-то рублей.
Тогда даже не скажу, сколько бы стоила такая система.
Нужен парсер по основным магазинам, собственная база, на которой будет размещаться информация.
В пределах 20к рублей - по самым скромным подсчётам. Но давно не заказывал ничего, не знаю теперешних цен.
ОП, у меня к тебе важный вопрос. Он не из "стандартных".
В общем, как узнать ширину/длинну и пр. параметры WebM? TinyIB использует mediainfo и ffmpegthumbnailer, с которыми у меня не срослось (точнее, у моего бесплатного хостинга не срослось с shell_exec и установкой ПО)
Если-ли способы узнать как минимум ширину и длину, но без всяких ненужных библиотек и пр.?
В библиотеке getId3 нет парсера заголовков WebM? А вообще, это несерьезно, из-за хостинга переделвать код.
> Если-ли способы узнать как минимум ширину и длину, но без всяких ненужных библиотек и пр.?
Почитать спецификации на формат файла и понять где она хранится. Учти что в видеофайлах часто есть отдельно форма контейнера и формат в котором кодируются видеоданные.
... = "/(\\.[а-я])|(\\,[а-я])|(![а-я])|(\\?[а-я])|(;[а-я])|(:[а-я])/u"
остаток на каждый ход тебе известен, он записан в $creditBalace, как только он стал меньше 5000:
$paymentTotal = $paymentTotal + $creditBalance; //вместо 5000 платишь остаток
$creditBalance = $creditBalance - $creditBalance; //кредит погашен без переплат
break;
все понел спасибо
Там есть подвохи, например надо делать после цикла unset($value) иначе можно получить баги. Не используй ссылки, пока не прочтешь внимательно раздел в мануале про них.
>>637134
Процедурщина так как вызов статических методов не особо отличается от вызовов обычных функций и не используются возможности ООП, создание объектов и тд.
Почему это плохо можно почитать в уроке про зависимости https://gist.github.com/codedokode/e1d31a31b37d5f635057
Статические методы нужны в редких случаях, когда методу не нужны поля объекта, обычно это вспомогательные функции вроде вывода объема файла словами "2,1 Гб". В большинстве случаев нам нужны нормальные объекты с обычными методами. Иначе это не ООП. Так как суть ООП как раз в том что мы создаем классы для описания объектов используемых в программе. А со статическими методами объектов нет.
Например в задаче про студентов студента можно смоделировать в виде объекта, маппер сделать в виде объекта, валидатор в виде объекта и тд.
>>637146
Тебя никто на фриланс не гонит, можешь заняться чем-нибудь другим.
>>637125
Вордпресс это CMS. Погугли.
>>637064
ЧТо значит на шторм? Как я понимаю, он умеет запускать интерпретатор пхп и Апач еси их установить и прописать нужные настройки.
>>637043
пхпсторм не выполняет программы на пхп, он лишь запускает интерпретатор пхп. Потому легко обойтись и без него.
>>637042
Надо разобраться как это все работает, а не следовать вслепую советам с разных формуов. Как минимум, надо установить расширение к пхп, включить его в php.ini, проверить что оно соединяется с ИДЕ, проверить что в браузер или ком. строку передается нужный признак для запуска отладчика.
Там есть подвохи, например надо делать после цикла unset($value) иначе можно получить баги. Не используй ссылки, пока не прочтешь внимательно раздел в мануале про них.
>>637134
Процедурщина так как вызов статических методов не особо отличается от вызовов обычных функций и не используются возможности ООП, создание объектов и тд.
Почему это плохо можно почитать в уроке про зависимости https://gist.github.com/codedokode/e1d31a31b37d5f635057
Статические методы нужны в редких случаях, когда методу не нужны поля объекта, обычно это вспомогательные функции вроде вывода объема файла словами "2,1 Гб". В большинстве случаев нам нужны нормальные объекты с обычными методами. Иначе это не ООП. Так как суть ООП как раз в том что мы создаем классы для описания объектов используемых в программе. А со статическими методами объектов нет.
Например в задаче про студентов студента можно смоделировать в виде объекта, маппер сделать в виде объекта, валидатор в виде объекта и тд.
>>637146
Тебя никто на фриланс не гонит, можешь заняться чем-нибудь другим.
>>637125
Вордпресс это CMS. Погугли.
>>637064
ЧТо значит на шторм? Как я понимаю, он умеет запускать интерпретатор пхп и Апач еси их установить и прописать нужные настройки.
>>637043
пхпсторм не выполняет программы на пхп, он лишь запускает интерпретатор пхп. Потому легко обойтись и без него.
>>637042
Надо разобраться как это все работает, а не следовать вслепую советам с разных формуов. Как минимум, надо установить расширение к пхп, включить его в php.ini, проверить что оно соединяется с ИДЕ, проверить что в браузер или ком. строку передается нужный признак для запуска отладчика.
> Еще по видам джойнов: помню шо имеет значение порядок объединения таблиц, но не помню почему.
Для обычных джойнов не имеет, для LEFT JOIN имеет значение так как он несимметричен и выполняется в определенном порядке.
> Я вот не знаю, как буду работать. Скажут пофиксить такой код, буду наверное дня три только сидеть и разбирать последовательность вызовов.
Отладчик надо освоить, на learn.javascript есть статья.
Паста про иннодб, неформатированная
-----------------
> Как вообще работает транзакция? Можно ли вставить миллион записей одной транзакцией, или оно пишется куда-то (в память, на диск, во временную таблицу), где есть лимит?
Транзакция это изолированный набор изменений, соответствующий принципам ACID:
https://ru.wikipedia.org/wiki/%D0%A2%D1%80%D0%B0%D0%BD%D0%B7%D0%B0%D0%BA%D1%86%D0%B8%D1%8F_(%D0%B8%D0%BD%D1%84%D0%BE%D1%80%D0%BC%D0%B0%D1%82%D0%B8%D0%BA%D0%B0)
https://ru.wikipedia.org/wiki/ACID
Транзакции это важно. В идеале ты должен в своем приложении делать изменения, группируя запросы в транзакции по смыслу (чтобы не могло получиться так что часть изменений запишется, а часть нет). К примеру при вставке объявления и увеличения счетчика объявлений в категории, ты должен объединить это в одну транзакцию. Найди потом время пройтись по своему коду и проверить правильно ли расставлены границы транзакций.
Если этим пренебречь, со временем в базе будут накапливаться несогласованные данные. Например скрипт успел записать часть данных и упал, или сервер перезагрузили, или питание пропало.
В реальном мире частью требований можно жертвовать (менять уровень изоляции транзакций) в пользу производительности: https://ru.wikipedia.org/wiki/%D0%A2%D1%80%D0%B0%D0%BD%D0%B7%D0%B0%D0%BA%D1%86%D0%B8%D1%8F_(%D0%B8%D0%BD%D1%84%D0%BE%D1%80%D0%BC%D0%B0%D1%82%D0%B8%D0%BA%D0%B0)
https://ru.wikipedia.org/wiki/%D0%A3%D1%80%D0%BE%D0%B2%D0%B5%D0%BD%D1%8C_%D0%B8%D0%B7%D0%BE%D0%BB%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%BD%D0%BE%D1%81%D1%82%D0%B8_%D1%82%D1%80%D0%B0%D0%BD%D0%B7%D0%B0%D0%BA%D1%86%D0%B8%D0%B9
http://habrahabr.ru/post/135217/
Вопросы по транзакциям любят задавать на собеседованиях. Я считаю это правильно.
Как реализовать изоляцию транзакций и параллельную их работу с минимумом задержек?
В MySQL в InnoDB используется так назваемая мультиверсионность:
https://en.wikipedia.org/wiki/Multiversion_concurrency_control
https://dev.mysql.com/doc/refman/5.0/en/innodb-multi-versioning.html
Там сложная система, но она позволяет получить высокую производительность при параллельной работе (когда несколько пользователей пишут и несколько читают данные), и за счет этой системы потоки, которые читают данные, почти никогда не блокируются. Если делать все «по-простому» (то есть данные транзакции накапливаются в буфере, а при коммите вносятся в таблицу), то было бы много блокировок в момент коммита и при частой записи в базу все бы лежало.
Также, еще одна вещь, которую надо понимать, это то, что MySQL гарантирует сохранность данных после успешного коммита. То есть перед тем как отчитаться что команда COMMIT завершена успешно, mysql сбрасывает данные (данные таблицы, а также изменившиеся индексы) на диск и дожидается от ОС подтверждения что они физически сохранены. Даже если питание выключится, коммит не пропадет (если оно выключится до коммита, то он пропадет, но база останется в согласованном состоянии которое было до коммита, а такого что половина данных записалась, а половина нет, быть не может. Это называется атомарность транзакции).
Соответственно если ты выполняешь запросы по одному, каждый идет отдельной транзакцией и mysql после каждого должна ждать диск. Это неэффективно. Если ты делаешь 100 запросов одной транзакцией, то mysql имеет право накапливать данные в памяти (или писать на диск без подтверждения и без ожидания), а сбросить на диск только в конце транзакции, и это работает быстрее.
Магнитные диски не могут делать больше пары сотен операций случайной записи в секунду (так как диск крутится с конечной скоростью и ты должен ждать пока сектор окажется под головокой). Потому на магнитных дисках как ты не крутись, появляется ограничение на пару сотен транзакций в секунду. На SSD вроде с этим получше, но там есть свои особенности (там чтобы перезаписать блок данных, надо сначала очистить большой кусок диска, а потом восстановить старые данные).
Возвращаясь к MVCC - там для каждой строчки таблицы добавляется несколько скрытых полей, вроде таймстампа (время добавления) и номера транзакции. При изменениях в таблице (update/delete/insert) исходные данные не удаляются, а просто добавляются новые строчки. При выборке если есть несколько версий строки, по id транзакции и таймстампу выбирается самая новая видимая данному пользователю версия. При коммите новая версия становится видна всем, старая становится неактуальной и специальный фоновый тред очищает такие строки и помечает занимаемое ими место как свободное.
Условно говоря, у нас есть таблица такого вида:
id | text
1 | hello
В InnoDB она хранится с id транзакции которая ее вставила и таймстампом:
txn | timestamp | id | text
1000 | 12:00:00 | 1 | hello
Как мы видим эта строчка вставлена транзакцией 1000, которая (допустим) давно закоммичена.
Допустим 3 пользователя подключенных к базе параллельно открывают 3 транзакции. Первый (транзакция 1001) удаляет строчку (и пока не закоммитил транзакцию), второй (1002) и третий (1003) добавляют вторую строчку.Таблица выглядит так:
txn | timestamp | id | text
1000 | 12:00:00 | 1 | hello
1001 | 13:00:00 | 1 | (deleted)
1002 | 13:00:00 | 2 | world1
1003 | 13:00:00| 3 | world2
Пользователь внутри транзакции видит только закоммиченные чужие изменения, а также все свои. То есть транзакция 1001 видит изменения из закомиченной транзакции 1000 и незакомиченной 1001. Если пользователь сделает SELECT из этой транзакции, то база будет брать только строки транзакций 1000 и 1001, причем если эти строки соответствуют одному id, то база берет самую новую версию.
Транзакция 1001 видит только эти строки:
txn | timestamp | id | text
1000 | 12:00:00 | 1 | hello
1001 | 13:00:00 | 1 | (deleted)
Так как id одинаковый то она берет последнюю версию, которая помечена как удаленная. Больше строк нет потому SELECT вернет 0 строк.
Транзакция 1002 видит только строки от транзакций 1000 и свои, 1002. Транзакция 1003 видит строки от транзакций 1000 и 1003. Что они получат при выборке всех строк, подумай сам.
Допустим теперь транзакции 1002 и 1003 отменяются, а 1001 коммитится. Строки для отмененных транзакций стали неактуальными, и их позже удалит сборщик мусора. А так как 1001 теперь закоммичена то любой пользователь видит эту строку. При выборке он получит такие строки:
txn | timestamp | id | text
1000 | 12:00:00 | 1 | hello
1001 | 13:00:00 | 1 | (deleted)
Так как строки имеют общий id, из них выбирается новейшая, а она удалена, потому пользователь видит пустую таблицу.
Строка транзакции 1000 после коммита тран. 1001 стала неактуальной, и ее позже удалит сборщик мусора. А также строку 1001 которую после этого нет смысла хранить.
На первый взгляд сложно, но смотри какое преимущество имеет эта система: транзакции не меняют существующие данные, а только добавляют новые. Получается нет такой ситуации, что 2 транзакции могут писать в одну строку (или одна пишет, а другая читает). У нас есть либо закомиченные ранее строки, из которых идет только чтение, либо видимые только одной транзакции незакомиченные строки, которые принадлежат только ей. Раз так, нам не надо делать блокировки на эти строки и не надо ждать например пока блокировка освободится (а блокировки нужны именно когда есть 2 писателя или писатель + читатель).
Это позволяет выжать максимум производительности при параллельных операциях с таблицой. А ведь веб приложения как правило много процессные/многопоточные (если ты помнишь), и соответственно параллельно выполняется несколько SQL запросов от разных воркеров. Да и сервера как правило содержат много ядер и чтобы их загрузить нужно много потоков.
В MyISAM например нет мультиверсионности. Любая запись в таблицу блокирует ее так, что работать с ней может только писатель, а все остальные ждут. В myISAM писать в таблицу может только один поток, а читать можно только когда никто в нее не пишет. Какая тут параллельность?
В redis тоже нет, но там однопоточное приложение (асинхронное) и параллельный доступ к данным невозможен. В MongoDB нету, там блокируется вся коллекция (до версии 3 - блокировалась вообще вся база) на время записи, но там и транзакций нет.
.... продолжение далее ...
> Еще по видам джойнов: помню шо имеет значение порядок объединения таблиц, но не помню почему.
Для обычных джойнов не имеет, для LEFT JOIN имеет значение так как он несимметричен и выполняется в определенном порядке.
> Я вот не знаю, как буду работать. Скажут пофиксить такой код, буду наверное дня три только сидеть и разбирать последовательность вызовов.
Отладчик надо освоить, на learn.javascript есть статья.
Паста про иннодб, неформатированная
-----------------
> Как вообще работает транзакция? Можно ли вставить миллион записей одной транзакцией, или оно пишется куда-то (в память, на диск, во временную таблицу), где есть лимит?
Транзакция это изолированный набор изменений, соответствующий принципам ACID:
https://ru.wikipedia.org/wiki/%D0%A2%D1%80%D0%B0%D0%BD%D0%B7%D0%B0%D0%BA%D1%86%D0%B8%D1%8F_(%D0%B8%D0%BD%D1%84%D0%BE%D1%80%D0%BC%D0%B0%D1%82%D0%B8%D0%BA%D0%B0)
https://ru.wikipedia.org/wiki/ACID
Транзакции это важно. В идеале ты должен в своем приложении делать изменения, группируя запросы в транзакции по смыслу (чтобы не могло получиться так что часть изменений запишется, а часть нет). К примеру при вставке объявления и увеличения счетчика объявлений в категории, ты должен объединить это в одну транзакцию. Найди потом время пройтись по своему коду и проверить правильно ли расставлены границы транзакций.
Если этим пренебречь, со временем в базе будут накапливаться несогласованные данные. Например скрипт успел записать часть данных и упал, или сервер перезагрузили, или питание пропало.
В реальном мире частью требований можно жертвовать (менять уровень изоляции транзакций) в пользу производительности: https://ru.wikipedia.org/wiki/%D0%A2%D1%80%D0%B0%D0%BD%D0%B7%D0%B0%D0%BA%D1%86%D0%B8%D1%8F_(%D0%B8%D0%BD%D1%84%D0%BE%D1%80%D0%BC%D0%B0%D1%82%D0%B8%D0%BA%D0%B0)
https://ru.wikipedia.org/wiki/%D0%A3%D1%80%D0%BE%D0%B2%D0%B5%D0%BD%D1%8C_%D0%B8%D0%B7%D0%BE%D0%BB%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%BD%D0%BE%D1%81%D1%82%D0%B8_%D1%82%D1%80%D0%B0%D0%BD%D0%B7%D0%B0%D0%BA%D1%86%D0%B8%D0%B9
http://habrahabr.ru/post/135217/
Вопросы по транзакциям любят задавать на собеседованиях. Я считаю это правильно.
Как реализовать изоляцию транзакций и параллельную их работу с минимумом задержек?
В MySQL в InnoDB используется так назваемая мультиверсионность:
https://en.wikipedia.org/wiki/Multiversion_concurrency_control
https://dev.mysql.com/doc/refman/5.0/en/innodb-multi-versioning.html
Там сложная система, но она позволяет получить высокую производительность при параллельной работе (когда несколько пользователей пишут и несколько читают данные), и за счет этой системы потоки, которые читают данные, почти никогда не блокируются. Если делать все «по-простому» (то есть данные транзакции накапливаются в буфере, а при коммите вносятся в таблицу), то было бы много блокировок в момент коммита и при частой записи в базу все бы лежало.
Также, еще одна вещь, которую надо понимать, это то, что MySQL гарантирует сохранность данных после успешного коммита. То есть перед тем как отчитаться что команда COMMIT завершена успешно, mysql сбрасывает данные (данные таблицы, а также изменившиеся индексы) на диск и дожидается от ОС подтверждения что они физически сохранены. Даже если питание выключится, коммит не пропадет (если оно выключится до коммита, то он пропадет, но база останется в согласованном состоянии которое было до коммита, а такого что половина данных записалась, а половина нет, быть не может. Это называется атомарность транзакции).
Соответственно если ты выполняешь запросы по одному, каждый идет отдельной транзакцией и mysql после каждого должна ждать диск. Это неэффективно. Если ты делаешь 100 запросов одной транзакцией, то mysql имеет право накапливать данные в памяти (или писать на диск без подтверждения и без ожидания), а сбросить на диск только в конце транзакции, и это работает быстрее.
Магнитные диски не могут делать больше пары сотен операций случайной записи в секунду (так как диск крутится с конечной скоростью и ты должен ждать пока сектор окажется под головокой). Потому на магнитных дисках как ты не крутись, появляется ограничение на пару сотен транзакций в секунду. На SSD вроде с этим получше, но там есть свои особенности (там чтобы перезаписать блок данных, надо сначала очистить большой кусок диска, а потом восстановить старые данные).
Возвращаясь к MVCC - там для каждой строчки таблицы добавляется несколько скрытых полей, вроде таймстампа (время добавления) и номера транзакции. При изменениях в таблице (update/delete/insert) исходные данные не удаляются, а просто добавляются новые строчки. При выборке если есть несколько версий строки, по id транзакции и таймстампу выбирается самая новая видимая данному пользователю версия. При коммите новая версия становится видна всем, старая становится неактуальной и специальный фоновый тред очищает такие строки и помечает занимаемое ими место как свободное.
Условно говоря, у нас есть таблица такого вида:
id | text
1 | hello
В InnoDB она хранится с id транзакции которая ее вставила и таймстампом:
txn | timestamp | id | text
1000 | 12:00:00 | 1 | hello
Как мы видим эта строчка вставлена транзакцией 1000, которая (допустим) давно закоммичена.
Допустим 3 пользователя подключенных к базе параллельно открывают 3 транзакции. Первый (транзакция 1001) удаляет строчку (и пока не закоммитил транзакцию), второй (1002) и третий (1003) добавляют вторую строчку.Таблица выглядит так:
txn | timestamp | id | text
1000 | 12:00:00 | 1 | hello
1001 | 13:00:00 | 1 | (deleted)
1002 | 13:00:00 | 2 | world1
1003 | 13:00:00| 3 | world2
Пользователь внутри транзакции видит только закоммиченные чужие изменения, а также все свои. То есть транзакция 1001 видит изменения из закомиченной транзакции 1000 и незакомиченной 1001. Если пользователь сделает SELECT из этой транзакции, то база будет брать только строки транзакций 1000 и 1001, причем если эти строки соответствуют одному id, то база берет самую новую версию.
Транзакция 1001 видит только эти строки:
txn | timestamp | id | text
1000 | 12:00:00 | 1 | hello
1001 | 13:00:00 | 1 | (deleted)
Так как id одинаковый то она берет последнюю версию, которая помечена как удаленная. Больше строк нет потому SELECT вернет 0 строк.
Транзакция 1002 видит только строки от транзакций 1000 и свои, 1002. Транзакция 1003 видит строки от транзакций 1000 и 1003. Что они получат при выборке всех строк, подумай сам.
Допустим теперь транзакции 1002 и 1003 отменяются, а 1001 коммитится. Строки для отмененных транзакций стали неактуальными, и их позже удалит сборщик мусора. А так как 1001 теперь закоммичена то любой пользователь видит эту строку. При выборке он получит такие строки:
txn | timestamp | id | text
1000 | 12:00:00 | 1 | hello
1001 | 13:00:00 | 1 | (deleted)
Так как строки имеют общий id, из них выбирается новейшая, а она удалена, потому пользователь видит пустую таблицу.
Строка транзакции 1000 после коммита тран. 1001 стала неактуальной, и ее позже удалит сборщик мусора. А также строку 1001 которую после этого нет смысла хранить.
На первый взгляд сложно, но смотри какое преимущество имеет эта система: транзакции не меняют существующие данные, а только добавляют новые. Получается нет такой ситуации, что 2 транзакции могут писать в одну строку (или одна пишет, а другая читает). У нас есть либо закомиченные ранее строки, из которых идет только чтение, либо видимые только одной транзакции незакомиченные строки, которые принадлежат только ей. Раз так, нам не надо делать блокировки на эти строки и не надо ждать например пока блокировка освободится (а блокировки нужны именно когда есть 2 писателя или писатель + читатель).
Это позволяет выжать максимум производительности при параллельных операциях с таблицой. А ведь веб приложения как правило много процессные/многопоточные (если ты помнишь), и соответственно параллельно выполняется несколько SQL запросов от разных воркеров. Да и сервера как правило содержат много ядер и чтобы их загрузить нужно много потоков.
В MyISAM например нет мультиверсионности. Любая запись в таблицу блокирует ее так, что работать с ней может только писатель, а все остальные ждут. В myISAM писать в таблицу может только один поток, а читать можно только когда никто в нее не пишет. Какая тут параллельность?
В redis тоже нет, но там однопоточное приложение (асинхронное) и параллельный доступ к данным невозможен. В MongoDB нету, там блокируется вся коллекция (до версии 3 - блокировалась вообще вся база) на время записи, но там и транзакций нет.
.... продолжение далее ...
продолжение пасты
------------------------
.....
В MyISAM например нет мультиверсионности. Любая запись в таблицу блокирует ее так, что работать с ней может только писатель, а все остальные ждут. В myISAM писать в таблицу может только один поток, а читать можно только когда никто в нее не пишет. Какая тут параллельность?
В redis тоже нет, но там однопоточное приложение (асинхронное) и параллельный доступ к данным невозможен. В MongoDB нету, там блокируется вся коллекция (до версии 3 - блокировалась вообще вся база) на время записи, но там и транзакций нет.
Обрати внимание что речь тут шла о блокировках для модификации данных. MVCC (почти) не требует их наличия. Но MySQL все равно блокирует строки, которые изменяются или удаляются. Это делается для того чтобы 2 транзакции не могли сделать противоречащие изменения (например записать разные значения в одну и ту же строку) и нарушить ACID. MySQL делает блокировки как минимум в таких случаях:
- есть 2 писателя (UPDATE/DELETE) для 1 и той же строки
- есть писатель + читатель (SELECT) для 1 и той же строки
В этих случаях доступ к строке получает только первый захвативший блокировку, а второй будет ждать пока она освободится. Блокировки снимаются при коммите транзакции. Если их не делать то нарушается изоляция транзакций.
https://dev.mysql.com/doc/refman/5.0/en/innodb-transaction-model.html
http://webew.ru/articles/1383.webew
В особо тяжелых слуаях можно словить взаимную блокировку - deadlock:
https://ru.wikipedia.org/wiki/%D0%92%D0%B7%D0%B0%D0%B8%D0%BC%D0%BD%D0%B0%D1%8F_%D0%B1%D0%BB%D0%BE%D0%BA%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0
Например транзакция A хочет апдейтить строку 1, за ней строку 2. Транзакия B хочет апдейтить сначала 2, потом 1. Каждая их них захватит блокировку по одной строке и никогда не получит блокировку по второй. MySQL обнаруживает дедлоки и решает их принудительным откатом одной из транзакций.
Выше я написал что MVCC почти не требует блокировок. Но как написал один опытный анон, зашедший к нам в тред, небольшие блокировки там есть. Например при вставке записи надо выделить новый id и на время выделение счетчик автоинкремента блокируется. В момент коммита надо пометить транзакцию как закоммиченную и какая-то внутренняя структура блокируется.
Подробности о работе и состоянии движка InnoDB можно получить запросом (попробуй это сделать):
SHOW ENGINE InnoDB STATUS\G
Увидеть список соединений и выполняющихся запросов можно командой SHOW FULL PROCESSLIST\G. Убить поток-воркер можно командой KILL 123; (принципы ACID и целостность данных это не нарушит).
Наконец, вернемся к этому вопросу:
> Можно ли вставить миллион записей одной транзакцией, или оно пишется куда-то (в память, на диск, во временную таблицу), где есть лимит?
В InnoDB есть пул страниц (InnoDB buffer pool) в памяти: https://dev.mysql.com/doc/refman/5.5/en/innodb-buffer-pool.html
Размер пула задается в конфиге mysql. В нем хранятся страницы (строки таблиц и куски индексов). При выборке данных mysql читает данные с диска в пул (если их там нет) и в нем уже делает выборку. При записи данные пишутся в пул, а при нехватке места сбрасываются на диск, также они надежно сбрасываются на диск при коммите транзакции.
Потому ответ на твой вопрос: данные пишутся в память пока есть место и на диск. Размер базы ограничен местом на диске, настройками конфига и встроенными ограничениями (вроде того что размер строки ограничен 65536 байтами).
Как ты понимаешь, от объема пула зависит часто ли базе придется обращаться к диску, а диск очень медленный. На серверах БД под пул выделяют 80-90% свободной памяти, также есть мнение что размер пула должен быть не меньше чем размер индексов (и «горячих» данных). Не редкость иметь например 100 Гб пула если на сервере много памяти.
А теперь вопросы для проверки.
1) Выше я написал что когда кто-то записывает данные (например изменяет строку) он должен брать эксклюзивную блокировку на эти данные, и другие не могут к ним обращаться, то есть читать или писать. Почему? Почему MyISAM блокирует таблицу на время апдейта одной строки?
Если это важно, то в MyISAM данные хранятся так: для каждой таблицы и каждого индекса делается отдельный файл и в нем хранятся строки таблиц или записи индекса.
2) Почему MVCC позволяет это не делать?
3) Более сложный вопрос, почему InnoDB блокирует строки, хотя MVCC позволяет это не делать? Почему строки блокируются на все время транзакции (а не на время выполнения запроса)? Что будет если не блокировать?
4) И еще, если программа выбирает какие-то данные (SELECT), меняет их и записывает назад в базу (UPDATE), как запретить другим в это время их менять?
продолжение пасты
------------------------
.....
В MyISAM например нет мультиверсионности. Любая запись в таблицу блокирует ее так, что работать с ней может только писатель, а все остальные ждут. В myISAM писать в таблицу может только один поток, а читать можно только когда никто в нее не пишет. Какая тут параллельность?
В redis тоже нет, но там однопоточное приложение (асинхронное) и параллельный доступ к данным невозможен. В MongoDB нету, там блокируется вся коллекция (до версии 3 - блокировалась вообще вся база) на время записи, но там и транзакций нет.
Обрати внимание что речь тут шла о блокировках для модификации данных. MVCC (почти) не требует их наличия. Но MySQL все равно блокирует строки, которые изменяются или удаляются. Это делается для того чтобы 2 транзакции не могли сделать противоречащие изменения (например записать разные значения в одну и ту же строку) и нарушить ACID. MySQL делает блокировки как минимум в таких случаях:
- есть 2 писателя (UPDATE/DELETE) для 1 и той же строки
- есть писатель + читатель (SELECT) для 1 и той же строки
В этих случаях доступ к строке получает только первый захвативший блокировку, а второй будет ждать пока она освободится. Блокировки снимаются при коммите транзакции. Если их не делать то нарушается изоляция транзакций.
https://dev.mysql.com/doc/refman/5.0/en/innodb-transaction-model.html
http://webew.ru/articles/1383.webew
В особо тяжелых слуаях можно словить взаимную блокировку - deadlock:
https://ru.wikipedia.org/wiki/%D0%92%D0%B7%D0%B0%D0%B8%D0%BC%D0%BD%D0%B0%D1%8F_%D0%B1%D0%BB%D0%BE%D0%BA%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0
Например транзакция A хочет апдейтить строку 1, за ней строку 2. Транзакия B хочет апдейтить сначала 2, потом 1. Каждая их них захватит блокировку по одной строке и никогда не получит блокировку по второй. MySQL обнаруживает дедлоки и решает их принудительным откатом одной из транзакций.
Выше я написал что MVCC почти не требует блокировок. Но как написал один опытный анон, зашедший к нам в тред, небольшие блокировки там есть. Например при вставке записи надо выделить новый id и на время выделение счетчик автоинкремента блокируется. В момент коммита надо пометить транзакцию как закоммиченную и какая-то внутренняя структура блокируется.
Подробности о работе и состоянии движка InnoDB можно получить запросом (попробуй это сделать):
SHOW ENGINE InnoDB STATUS\G
Увидеть список соединений и выполняющихся запросов можно командой SHOW FULL PROCESSLIST\G. Убить поток-воркер можно командой KILL 123; (принципы ACID и целостность данных это не нарушит).
Наконец, вернемся к этому вопросу:
> Можно ли вставить миллион записей одной транзакцией, или оно пишется куда-то (в память, на диск, во временную таблицу), где есть лимит?
В InnoDB есть пул страниц (InnoDB buffer pool) в памяти: https://dev.mysql.com/doc/refman/5.5/en/innodb-buffer-pool.html
Размер пула задается в конфиге mysql. В нем хранятся страницы (строки таблиц и куски индексов). При выборке данных mysql читает данные с диска в пул (если их там нет) и в нем уже делает выборку. При записи данные пишутся в пул, а при нехватке места сбрасываются на диск, также они надежно сбрасываются на диск при коммите транзакции.
Потому ответ на твой вопрос: данные пишутся в память пока есть место и на диск. Размер базы ограничен местом на диске, настройками конфига и встроенными ограничениями (вроде того что размер строки ограничен 65536 байтами).
Как ты понимаешь, от объема пула зависит часто ли базе придется обращаться к диску, а диск очень медленный. На серверах БД под пул выделяют 80-90% свободной памяти, также есть мнение что размер пула должен быть не меньше чем размер индексов (и «горячих» данных). Не редкость иметь например 100 Гб пула если на сервере много памяти.
А теперь вопросы для проверки.
1) Выше я написал что когда кто-то записывает данные (например изменяет строку) он должен брать эксклюзивную блокировку на эти данные, и другие не могут к ним обращаться, то есть читать или писать. Почему? Почему MyISAM блокирует таблицу на время апдейта одной строки?
Если это важно, то в MyISAM данные хранятся так: для каждой таблицы и каждого индекса делается отдельный файл и в нем хранятся строки таблиц или записи индекса.
2) Почему MVCC позволяет это не делать?
3) Более сложный вопрос, почему InnoDB блокирует строки, хотя MVCC позволяет это не делать? Почему строки блокируются на все время транзакции (а не на время выполнения запроса)? Что будет если не блокировать?
4) И еще, если программа выбирает какие-то данные (SELECT), меняет их и записывает назад в базу (UPDATE), как запретить другим в это время их менять?
Даже если ты далек от программирования, для запуска скриптов надо разобраться с настройкой Апача и пхп, в ОП посте есть ссылки по теме.
>>637005
Он их в консоли ведь запускает? А с веб-сервером можно через браузер запускать.
>>636981
Про сервер - почитай урок про Апач в ОП посте. Может поможет.
>>636721
>>636961
> Но там только 1 картинка в коде. И что делать с текстом? Не очень ясно
Имеется в виду если ширина страницы меньше чем картинка то картинка ужимается. Если больше - то картинка НЕ увеличивается так как растровые картинки нельзя увеличивать, они мылятся.
С текстом особо ничего и не надо делать.
Можно почитать мануал/погуглить, можно попробовать так понять. Там сделан универальный контейнер, то есть изначально в нем нет никаких сервисов. Соответственно методом setDefinition ты задаешь правила создания сервиса (объекта):
- как создать объект: через new, через вызов метода-фабрики или еще как-то
- объект какого класса создать
- что передать в конструктор
- есть ли зависимость от других сервисов (т.е. надо ли их передать в конструктор)
То есть задумка такая: ты описываешь сервисы либо кодом либо в конфиге. После чего контейнер создает их по описанным тобой правилам.
Но в твоем приложении ты можешь упростить задачу и сделать не универсальный контейнер + конфиг к нему, а заточенный под твою задачу, где все сервисы прописаны в классе и не требуется его настраивать. То есть с методами типа getPdo(), getUserMapper() и тд.
Также есть очень простой и тоже универсальный контейнер pimple
https://habrahabr.ru/post/199296/
http://pimple.sensiolabs.org/
А вот его код, совсем немного: https://github.com/silexphp/Pimple/blob/master/src/Pimple/Container.php
>>636799
Твой запрос выглядит почти как запрос в задании. Я подглядел в правильный ответ (ибо из задачи ничего не понять) и по моему там дело в том что у тебя страны не отсортированы по названию, а в правильном ответе отсортированы.
>>636806
3 формы = 3 ифа, немного
> Тот код со стеной текста я просто не стал оптимизировать, там многое можно сократить - махнул рукой, потому что в тот момент не подумал, как можно было продолжить соединение этих частей для разложения.
На функции надо разбивать.
>>636763
Значит надо идти учить Си++, C#, java.
>>636758
Да. И кстати такой принцип хранения не соответствует принципам нормализации (погугли нормализацию БД), так что страдай теперь. Надо было с самого начала правильно делать.
>>636753
В качесте счетчика удобно использовать либо номер года либо возраст.
>>636714
А ты порешай наши задчки из ОП поста и покажи решения.
>>636684
> function isArrayOk($arr)
Копипаста, почему бы не сделать массив со списком полей и не сравнить их готовой функцией?
> function isArrayOk2($arr)
Это уже лучше, хотя мне кажется проще сделать через 2 вызова array_diff. Ну и не надо число 10 прописывать, надо его вычислять автоматом.
>>636799
Твой запрос выглядит почти как запрос в задании. Я подглядел в правильный ответ (ибо из задачи ничего не понять) и по моему там дело в том что у тебя страны не отсортированы по названию, а в правильном ответе отсортированы.
>>636806
3 формы = 3 ифа, немного
> Тот код со стеной текста я просто не стал оптимизировать, там многое можно сократить - махнул рукой, потому что в тот момент не подумал, как можно было продолжить соединение этих частей для разложения.
На функции надо разбивать.
>>636763
Значит надо идти учить Си++, C#, java.
>>636758
Да. И кстати такой принцип хранения не соответствует принципам нормализации (погугли нормализацию БД), так что страдай теперь. Надо было с самого начала правильно делать.
>>636753
В качесте счетчика удобно использовать либо номер года либо возраст.
>>636714
А ты порешай наши задчки из ОП поста и покажи решения.
>>636684
> function isArrayOk($arr)
Копипаста, почему бы не сделать массив со списком полей и не сравнить их готовой функцией?
> function isArrayOk2($arr)
Это уже лучше, хотя мне кажется проще сделать через 2 вызова array_diff. Ну и не надо число 10 прописывать, надо его вычислять автоматом.
С момента как решишь задачи которые идут перед главой с ООП.
>>636570
Плохо то что не используются возможности ООП, а классы намертво связаны друг с другом. Попробуй почитать урок про DI https://gist.github.com/codedokode/e1d31a31b37d5f635057
Статические вызовы связывают классы намертво и не дают возможности что-то менять.
> А если бы, например, за место студентов у нас были простые юзеры, и, при этом, я бы не хотел наследовать и писать новый класс как бы приходилось писать эту функцию?
Пришлось бы сделать новый класс. Ибо лень это не повод совать функцию туда, где ей не место. Каждый маппер должен работать со своей таблицей иначе будет бардак.
> Или всегда обязательно писать новый класс?
Каждый маппер работает со своей таблицей, так что да. Это делается для того чтобы инкапуслировать все запросы к 1 таблице в 1 классе. И если что-то меняется в этой таблице то в идеале достаточно поменять только этот класс.
>3 формы = 3 ифа, немного
Хм, я думал, что надо больше.
Ведь у нас 1 даёт одну форму, 2, 3, 4 дают другую, а все остальные числа дают третью.
Допустим, у нас первое вот так пойдёт:
if ($lastThousandNum == 1) {
$rouble = 'рубль';
echo $rouble;
} else {
$rouble = 'рублей';
echo $rouble;
}
А дальше я вот не знаю, как можно заставить работать вот такое нечто:
if ($lastThousandNum == 2|3|4) {
$rouble = 'рубля';
echo $rouble;
}
Такое просто не работает! Можно ли как-нибудь этот момент представить? Пробовал по-разному представлять там "или это, или то, или сё". Гуглил-шмуглил - ничего не нашёл.
Иначе можно будет только копипастить:
if ($lastThousandNum == 2) {
$rouble = 'рубля';
echo $rouble;
} elseif ($lastThousandNum == 3) {
$rouble = 'рубля';
echo $rouble;
} elseif ($lastThousandNum == 4) {
$rouble = 'рубля';
echo $rouble;
}
Наверняка же какой-то способ должен быть.
>3 формы = 3 ифа, немного
Хм, я думал, что надо больше.
Ведь у нас 1 даёт одну форму, 2, 3, 4 дают другую, а все остальные числа дают третью.
Допустим, у нас первое вот так пойдёт:
if ($lastThousandNum == 1) {
$rouble = 'рубль';
echo $rouble;
} else {
$rouble = 'рублей';
echo $rouble;
}
А дальше я вот не знаю, как можно заставить работать вот такое нечто:
if ($lastThousandNum == 2|3|4) {
$rouble = 'рубля';
echo $rouble;
}
Такое просто не работает! Можно ли как-нибудь этот момент представить? Пробовал по-разному представлять там "или это, или то, или сё". Гуглил-шмуглил - ничего не нашёл.
Иначе можно будет только копипастить:
if ($lastThousandNum == 2) {
$rouble = 'рубля';
echo $rouble;
} elseif ($lastThousandNum == 3) {
$rouble = 'рубля';
echo $rouble;
} elseif ($lastThousandNum == 4) {
$rouble = 'рубля';
echo $rouble;
}
Наверняка же какой-то способ должен быть.
>$lastThousandNum
*$lastNum
Исправил.
Это я сейчас думаю с тысячами как быть - не получается без костылей исправить момент с женским родом 1 и 2 тысяч.
>"452" - это "четыреста пятьдесят два тысячи"
Я могут просто сделать в этом случае ещё одну функцию именно для тысяч, которая 1 и 2 в последней цифре тройки переведёт в "одна" и "две", либо сделать массив $menSpelling, который будет подставляться в функцию вместо $femaleSpelling - и менять то, что и так должно выходить правильно.
Не получается изменить внутри общей функции, чтобы всё было компактно.
getId3 версии 1.9.4 может давать подробную информацию о всех медиафайлах, включая webm.
А тут надо было по-быстрому одну хуету сделать, и что-то даже с ней обосрался
Есть хтмл форма с одним полем и сабмитом, нужно по сабмиту отправлять мейл с содержимым формы на определённый адресс
Форма:
<form action='form.php' method="post">
<fieldset>
<input id="field" name="field" type="text" placeholder="Координаты" class="form-control input-md" required="">
<button id="submit" name="submit" class="btn btn-primary btn-lg">Отправить</button>
</fieldset>
</form>
Скрипт:
<?php
if(isset($_POST["submit"]) and ($_POST["field"]=="")) {
echo "Пусто";
} else {
$subject = 'New Customer from DoorsLandingPage'
$message = $_POST['field'];
$message = addslashes($message);
$headers = "From: Landing"; // Sender's Email
mail("тут_е_мейл", $subject, $message, $headers);
echo "Отправлено";
sleep(2);
echo "<meta http-equiv=\"refresh\" content=\"0; url=\"адрессайта\"/>";
}
?>
Чому оно всё время мне Еррор 500 даёт?
А тут надо было по-быстрому одну хуету сделать, и что-то даже с ней обосрался
Есть хтмл форма с одним полем и сабмитом, нужно по сабмиту отправлять мейл с содержимым формы на определённый адресс
Форма:
<form action='form.php' method="post">
<fieldset>
<input id="field" name="field" type="text" placeholder="Координаты" class="form-control input-md" required="">
<button id="submit" name="submit" class="btn btn-primary btn-lg">Отправить</button>
</fieldset>
</form>
Скрипт:
<?php
if(isset($_POST["submit"]) and ($_POST["field"]=="")) {
echo "Пусто";
} else {
$subject = 'New Customer from DoorsLandingPage'
$message = $_POST['field'];
$message = addslashes($message);
$headers = "From: Landing"; // Sender's Email
mail("тут_е_мейл", $subject, $message, $headers);
echo "Отправлено";
sleep(2);
echo "<meta http-equiv=\"refresh\" content=\"0; url=\"адрессайта\"/>";
}
?>
Чому оно всё время мне Еррор 500 даёт?
Ох ё! Спасибо тебе огромное, товарищ! Починил и говно это заработало.
Держи дочку Бори Немцова
да и все что я умею это сидеть за компутиром,
это единственное в чем я хоть как-то разбираюсь
наверно просто плохо старался, спасибо тебе теперь я что-то понел.
swag.js:4984
post.comment = post.comment.replace('<script ', '<!--<textarea '); //какой-то УМНИК решил, что будет гениальной идеей в посты вставлять кривой <script> с document.write
post.comment = post.comment.replace('</script>', '</textarea>-->');
swag.js:4984
post.comment = post.comment.replace('<script ', '<!--<textarea ');
document.write
post.comment = post.comment.replace('</script>', '</textarea>-->');
Это не она.
Хром выкидывает ошибку непредвиденного ДАББЛ АРРОУ unexpected T_DOUBLE_ARROW.
Сначала делал по новой схеме:
<?php
$leftMenu = [
['link' => 'Домой', 'href' => 'index.php'],
['link'=>'О нас', 'href'=>'about.php'],
['link'=>'Контакты', 'href'=>'contact.php'],
['link'=>'Таблица умножения', 'href'=>'table.php],
['link'=>'Калькулятор', 'href'=>'calc.php']
];
?>
Потом, задумался, что у меня старая версия ПХП установлена и сделал по-старинке, но все равно та же херня.
<?php
$leftMenu = array(
('link' => 'Домой', 'href' => 'index.php'),
('link'=>'О нас', 'href'=>'about.php'),
('link'=>'Контакты', 'href'=>'contact.php'),
('link'=>'Таблица умножения', 'href'=>'table.php'),
('link'=>'Калькулятор', 'href'=>'calc.php')
);
?>
Где проблема? Кто-нибудь ее видит?
Хром выкидывает ошибку непредвиденного ДАББЛ АРРОУ unexpected T_DOUBLE_ARROW.
Сначала делал по новой схеме:
<?php
$leftMenu = [
['link' => 'Домой', 'href' => 'index.php'],
['link'=>'О нас', 'href'=>'about.php'],
['link'=>'Контакты', 'href'=>'contact.php'],
['link'=>'Таблица умножения', 'href'=>'table.php],
['link'=>'Калькулятор', 'href'=>'calc.php']
];
?>
Потом, задумался, что у меня старая версия ПХП установлена и сделал по-старинке, но все равно та же херня.
<?php
$leftMenu = array(
('link' => 'Домой', 'href' => 'index.php'),
('link'=>'О нас', 'href'=>'about.php'),
('link'=>'Контакты', 'href'=>'contact.php'),
('link'=>'Таблица умножения', 'href'=>'table.php'),
('link'=>'Калькулятор', 'href'=>'calc.php')
);
?>
Где проблема? Кто-нибудь ее видит?
Точнее, даже не так, когда делал по новой схеме, то у меня интерпретатор даже не распознавал массив и показывал анэкпектед "[".
$leftMenu = array(
array('link' => 'Домой', 'href' => 'index.php'),
array('link'=>'О нас', 'href'=>'about.php'),
array('link'=>'Контакты', 'href'=>'contact.php'),
array('link'=>'Таблица умножения', 'href'=>'table.php'),
array('link'=>'Калькулятор', 'href'=>'calc.php')
);
Так в чем проблема-то тогда? У меня сейчас истерика начнется. Программа ни единой ошибки не засекла, сам я их тоже не вижу.
В чём отличие? И стоит ли вообще делать, как говорит ОП - самому поочерёдно ставить апач, настраивать и его тп?
Так у тебя не заработало, что ли?
Вот же ссылку я на Идеоне дал, в которой массив нормально читается: http://ideone.com/RC7NY1
Проблема и была в не закрытой кавычке, разве нет?
В первом варианте не закрыл кавычку, во втором неправильно объявляешь массив в массиве.
У меня пхп версии 5.6, оба варианта работают.
А зачем? Если ты любишь красноглазить и разбираться во всяких штуках низкоуровневых, то пожалуйста. Если любит нажать комбинацию кнопок, и чтобы все работало - ставь опен сервер. Отличие в стабильности, мультиверсионности и удобства интерфейса как такового.
Блин, где вы были два часа назад, когда я муторно возился с каждой ошибкой апача... Его теперь сносить лучше и ставить опен или поверх можно поставить и не будет проблем?
И надо ли ставить опенсервер на phpstorm или нет?
все IDE имеют одинаковые цветовые гаммы, если что
Это Атом с темой One Dark.
Эм, попробуй все снести и поставить опен сервер. Тебе он понравится, гарантирую.
>И надо ли ставить опенсервер на phpstorm или нет?
Не понял вопроса. Пхпшторм это же редактор, да? Как на него можно сервер ставить?
this?
Да не совсем редактор, это IDE полноценная, у него есть свой сервер и интерпретатор и т.п., просто из настроек я вижу, что можно сервер поставить сторонний, но не знаю, надо ли
Задай себе вопрос. У тебя пыха работает во встроенном сервере? Дальше следуй алгоритму: if (true) { echo "Нахуя мне что-то еще?"; } elseif (false) { echo "Поставлю-ка я опен сервер."; } else { echo "Зачем мне вообще программирование? Лучше пойду займусь чем-нибудь интеллектуальным"; }.
Ты даже скопировал неправильно
>>637507
>Отладчик надо освоить, на learn.javascript есть статья.
Распиши подробно, как этим пользоваться. На learn.javascript описано только как
он выглядит, и как ставить точки останова.
Все равно ведь придется ползать по коду и искать, где ставить эти точки останова.
Вот я хочу отследить, как на сосаче происходит обновление треда.
Либо при нажатии на кнопку "обновить", либо по таймеру.
На кнопке "обновить тред" функция updatePosts на строке 4949.
В ней метод объекта Post.download(function(data){...}).
В data приходит объект с массивом постов, полем с ошибкой и т.д.
Дальше на строке 4968 в цикле $.each для каждого элемента в data вызывается
appendPost(tmpost.getJSON())
appendPost объявлена на 5081.
В ней вызывается generatePostBody, объявленная на 4982. В ней на лету склеивается
корявый html из строк, вместо того чтобы использовать шаблон.
Затем пост добавляется через $('#thread').append()
Не знаю почему у меня подвисает ввод во время обновления треда,
вроде никакой явной блокировки не нашлось. Наверное, просто слабый процессор на
нетбуке.
Так все-таки, какая польза от отладчика кроме возможности остановить исполнение
в определенный момент (а этот момент еще надо вычислить) и посмотреть значение переменных?
>Да. И кстати такой принцип хранения не соответствует принципам нормализации (погугли нормализацию БД), так что страдай теперь. Надо было с самого начала правильно делать.
А как осуществить хранение idишников пользователей, которые находятся в данное место в определённом месте сайта (в комнате чата), не создавать же для каждого отдельное поле в таблице. Или надо было создать отдельную таблицу, в которой бы просто хранились айдишники и принадлежость их к той или иной комнате чате?
Второй способ.
У тебя там Успешный статус.
В чем проблема то?
И как двойные кавычки вставить в двойные кавычки, то? Это же 2 пары получится, конечно нужно экранировать.
Какая-то наркомания, какой-то родитель, 10 пикселей всюду разные, 34% - 10 пикселей, что это вообще такое? Вообще ничего не понятно.
Это я нагуглил и понял, но вот что требуется в задании? Сделать эти два прямоугольника?
Да
А, ну, я просто сначала по привычке две в две закинул по принципу js. Потом понял ошибку и изменил на одинарные.
Какому "принципу js"? В яваскрипте все точно так же. Нажми ctrl+j и скопируй в консоль var str = "abc"def"ghi";
>>637796
Что тут может быть непонятно? Желтый блок занимает две трети ширины родительского блока (серый прямоугольник), прижат к левому краю контейнера.
Фиолетовый блок то же самое, прижат вправо.
Между блоками 10px по вертикали. У родительского контейнера (серый прямоугольник) поля по 10px.
В Лисе просто F12.
Я уже сменил на 5.6 и апач 2.4 накатил.
> родительского блока (серый прямоугольник)
в задании сказано, что серые прямоугольники верстать не надо. Что будет родителем в таком случае?
Не благодари за меня.
Если бы ты его внимательно слушал, то понял бы, что он вообще с формочек на делфи начинал.
>но боюсь пхп-макаке о таком и мечтать нельзя
Чего это нельзя? Всякие Epam и Softserve набирают PHP миддлов и синьеров. Да и вакансий на PHP за рубежом не меньше чем в СНГ.
Какая разница сколько там вакансий? Кто возьмет на них простого хуя из другой страны, когда и в своей пхп девелоперов полно?
Лол, точно такое же можно сказать про все остальные ИТ вакансии. Тем не менее очень много людей уезжают по H1B. Да и по L1 тебя так же могут перевести как PHP девелопера.
>Человек без высшего образования может быть нанят по визе H1B в США, если он сможет подтвердить, что является специалистом, эквивалентным дипломированному, на основании опыта двенадцати или более лет в определенной отрасли занятий.
Пиздос
Да, для визы H1B нужно иметь вышку (как минимум бакалавр) которую признают как Computer Science degree. Для визы L1 это требование отсутствует, но её обычно получить сложнее чем H1B.
А вообще если интересно, проследуй в /em/, там есть тред с пояснениями.
Средний возраст иммигранта 28-32 года.
Тебе сейчас 16-20 лет, так что если устроишься на работку в ближайщее время, то вполне впишешься в график.
12 лет это уж слишком, полжизни пройдет, мне уже к земле надо будет готовиться, а не к эмиграции.
Лол, а я думал, что один, кто умрет до 40.
Так опыт 12+ лет обязателен если у тебя нет высшего образования. Если оно у тебя есть, и служба которая выдает визы признает его как Computer Science degree, тогда на опыт работы будет смореть только твой работодатель.
У бОльшей части пхп-треда нет высшего образования в области IT.
Я бы даже сказал, у всех.
>2016
>изучать РНР только ради каких-то денежных вознаграждений в будущем
Свои приложения надо пилить, сервисы, сайты для людей.
А не надеяться на дядю.
Много уже своих приложений запилил, бизнесмен?
https://jsfiddle.net/v699fwb3/1/
Странное позиционирование списка это баг, или так и должно быть?
В 3.5 этой фигни нет.
https://jsfiddle.net/v699fwb3/3/
Ну елки зеленые, как же это утомляет.
inb4: сейчас оп посоветует перечитать пять тысяч строк исходников, чтобы пофиксить эту мелочь.
>inb4: сейчас оп посоветует перечитать пять тысяч строк исходников, чтобы пофиксить эту мелочь.
Таки придется, если ты велосипедов не нагуглил.
Есть тут ещё такие?
Мне скоро 22. Знаю очень мало.
А твой код где увидеть?
Либо кредитбаланс никогда не становится меньше или равен нулю.
Либо ты как те два дебила выше путаешь знаки больше/меньше.
Код выкладывай.
Делаю через сессии.
При старте сессии на каждой из страниц вроде всё нормально. Авторизовался ранее - работаешь. Не авторизовался - редиректит на логин страницу. В качестве значений есть $_SESSION['userlogin'] и $_SESSION['userid']. Отсюда же вопрос. Подсунуть эти значения посетитель как-то может? Надо ли проверять их валидность на каждой из открываемых страниц с сессиями или же достаточно просто проверки на их наличие?
>Подсунуть эти значения посетитель как-то может?
Подсунуть эти значения из ничего никак не выйдет. Подсунуть можно айди сессии другого пользователя, но тут уже нужен доступ к его кукам, который не так-то просто получить. Ну и еще можно будет формы отправлять с других сайтов под именем пользователя, это называется csrf и у ОПа на эту тему есть урок.
https://github.com/codedokode/pasta/blob/master/security/xsrf.md
>>638028
Кстати, чисто в теории можно будет написать скрипт, который сможет угадать чей-то айди сессии, но это уже оверкилл и такого делать никто не будет, я думаю. Если ты делаешь какую-то очень защищенную систему, можешь при логине записывать айпи пользователя и айди сессии, потом на каждой странице проверять, если айпи пользователя поменялся - удалять сессию и отправлять его на страницу логина. Конечно, у этой системы будет недостаток, например если пользователь переподключился к интернету и у него сменился айпи - его перенаправит на страницу логина.
Попробуй в условие поставить именно $pain.
Потому что $creditBalance же у тебя в минус уходит к тому моменту, когда тот-же $pain становится меньше $monthlyPayment (ты же сразу там же от $creditBalance отнимаешь $monthlyPayment), да сколько же можно? Или ты другой анон?
Хм, т.е. xsrf пройдёт в любом случае, если пользователь залогинен и токен хранится в $_SESSION, проверяй я валидность userid (некоторое значение под sha512) или не проверяй?
То есть вариант - тупо вынести из сессии в качестве передаваемого параметра?
>>638039
Не думаю, что ip прямо так часто меняется.
>тот-же
тот же
>т.е. xsrf пройдёт в любом случае, если пользователь залогинен и токен хранится в $_SESSION, проверяй я валидность userid (некоторое значение под sha512) или не проверяй?
Да.
>То есть вариант - тупо вынести из сессии в качестве передаваемого параметра?
Да.
>Не думаю, что ip прямо так часто меняется.
На телефонах может связь с сетью пропасть например. Меня бы раздражали постоянные вылеты на страницу логина из-за плохого интернета или связи.
Я два дня назад спрашивал как решать, просто время за задачу взяться есть только ночью, а вчера вообще не получилось, пытаюсь вот разобрать потихоньку.
Ну, у тебя всё есть же для этого.
Вот какой совет: попробуй добиться правильной работы при первом прохождении скрипта при сумме, меньшей 5000.
Вот чтобы раз - и тут же выплатилась эта сумма.
Вот как бы ты это реализовал с помощью переменной $pain?
А дальше или сам уже всё увидишь, или опять будем вместе думать.
Спасибо.
>На телефонах может связь с сетью пропасть например
Ну у меня на мегафоне том же, как правило, даже при разрывах связи ip тот же самый видится снаружи после переподключения. Меняется, конечно, иногда, но я бы не сказал, что прямо катастрофически часто.
Кстати, а global не прокатит, чтобы не передавать каждый раз? Или global он будет для всех пользователей одинаков?
Также не ставь в условие $creditBalance < 0, там никогда не должно такого получиться при правильном решении!
Ставь $creditBalance <= 0 тогда уж или просто "равняется нулю".
Вообще, ненормально. А зачем запускать ее каждую секунду? И зачем вообще такая скорость обновления? Так конечно есть вебсокет, но интуиция мне подсказывает что тебе не нужно ничего обновлять в реальном времени.
К айпи лучше не привязываться, это неудобно. Ну или как-то предусмотреть возможность смены айпи, например, сохранять все айпи с которых ранее заходил пользователь.
Ну и это все равно не поможет от случая когда например владелец вайфай точки ворует ид сессии и делает что-то от своего имени, так как айпи будет тот же самый. От таких случаев поможет использование https.
Вполне нормальное решение, ответ верный.
>>633236
Тебе в прошлом треде написал:
> private function chooseProfession($post) {
Надо убрать отсюда так как это не позволит добавлять профессии не трогая старые классы. Также, у тебя не проверяется в свитче вариант если указана неправильная профессия, это плохо.
> public function countTotalSalary($qty, $rank, $post, $boss) {
Это не очень правльная функция, должно быть так:
public function countTotalSalary() { ... }
то есть не требюуется указывать никаких аргументов, у нас ведь департамент сам знает кто в нем состоит, какие у них должности и тд.
> abstract class Employee extends Department {
Абсолютно неправильное наследование. Наследование - это создание одного класса на основе другого, когда мы хотим изменить поведение или сделать улучшенную версию чего-то. Ну к примеру мы можем создать класс Транспорт с методом переместиться(), а от него унаследовать Машину, Самолет и Велосипед в которых этот метод реализован по-разному.
У тебя же неправильно: Сотрудник это не разновидност Департамента, значит наследование использовать так нельзя.
> class Manager extends Employee {
> protected function countSalary() {
Ты скопипастил тут код 4 раза.
>>633240
Это не обязательно
Вполне нормальное решение, ответ верный.
>>633236
Тебе в прошлом треде написал:
> private function chooseProfession($post) {
Надо убрать отсюда так как это не позволит добавлять профессии не трогая старые классы. Также, у тебя не проверяется в свитче вариант если указана неправильная профессия, это плохо.
> public function countTotalSalary($qty, $rank, $post, $boss) {
Это не очень правльная функция, должно быть так:
public function countTotalSalary() { ... }
то есть не требюуется указывать никаких аргументов, у нас ведь департамент сам знает кто в нем состоит, какие у них должности и тд.
> abstract class Employee extends Department {
Абсолютно неправильное наследование. Наследование - это создание одного класса на основе другого, когда мы хотим изменить поведение или сделать улучшенную версию чего-то. Ну к примеру мы можем создать класс Транспорт с методом переместиться(), а от него унаследовать Машину, Самолет и Велосипед в которых этот метод реализован по-разному.
У тебя же неправильно: Сотрудник это не разновидност Департамента, значит наследование использовать так нельзя.
> class Manager extends Employee {
> protected function countSalary() {
Ты скопипастил тут код 4 раза.
>>633240
Это не обязательно
В общем верно, но регулярку можно еще упростить, объединив группу из 3 цифр и из 7 цифр в одну группу из 10 цифр.
Ну и круглые скобки тут не нужны:
([\\s-(]*)
>>633278
Эта проблема проявляется только если ты записываешь число в коде, напрмер:
$x = 012;
Тогда оно интерпретируется как восьмеричное из-за ведущего нуля. Но в математических операциях такой проблемы не будет, ты бдудешь получать обычные числа (точнее, в какой они системе счисления, будет неважно). Эта проблема есть только при записи числа в коде.
>>633286
Ошибки:
> /$
$ в начале строки значит символ доллара, это только в самом конце регулярки он значит что тут должен быть конец строки.
> [а-я]
Чтобы указать все русские буквы, надо писать [а-яё] так как ё идет в юникоде отдельно и в диапазон а-я не входит. Ну и хорошо бы помнить, что буквы бывают и не русские.
Далее, у тебя правила заточены только на конкретное сочетание слов, например фразу "а если", а надо сделать чтобы искало "союз а, за ним любое слово без запятой между ними".
Это выражение [ ][,][ ] надо заменить на более универсальное "любое число пробелов, знак препинания, любое число пробелов".
Далее, у тебя там копипаста, в такой ситуации надо сделать массив замен и регулярок и проходить по нему циклом, а не копипастить код. Однотипные действия делаются циклом.
>>633307
Нет, ты уходи.
В общем верно, но регулярку можно еще упростить, объединив группу из 3 цифр и из 7 цифр в одну группу из 10 цифр.
Ну и круглые скобки тут не нужны:
([\\s-(]*)
>>633278
Эта проблема проявляется только если ты записываешь число в коде, напрмер:
$x = 012;
Тогда оно интерпретируется как восьмеричное из-за ведущего нуля. Но в математических операциях такой проблемы не будет, ты бдудешь получать обычные числа (точнее, в какой они системе счисления, будет неважно). Эта проблема есть только при записи числа в коде.
>>633286
Ошибки:
> /$
$ в начале строки значит символ доллара, это только в самом конце регулярки он значит что тут должен быть конец строки.
> [а-я]
Чтобы указать все русские буквы, надо писать [а-яё] так как ё идет в юникоде отдельно и в диапазон а-я не входит. Ну и хорошо бы помнить, что буквы бывают и не русские.
Далее, у тебя правила заточены только на конкретное сочетание слов, например фразу "а если", а надо сделать чтобы искало "союз а, за ним любое слово без запятой между ними".
Это выражение [ ][,][ ] надо заменить на более универсальное "любое число пробелов, знак препинания, любое число пробелов".
Далее, у тебя там копипаста, в такой ситуации надо сделать массив замен и регулярок и проходить по нему циклом, а не копипастить код. Однотипные действия делаются циклом.
>>633307
Нет, ты уходи.
> $symbol = mb_substr($text, $i, $halfLength);
Это непраивльно, ты берешь не первый символ, а первую половину строки и сравниваешь с пустой строкой (так как mb_substr($text, $length, $halfLength) даст пустую строку).
Надо брать за один шаг цикла по одному символу с двух краев строки.
>>633406
> W2(перевод долларов в рубли) - http://ideone.com/5zHXdu
Верно, но строка $roubles = 0; лишняя.
> W3(имитация броска кубика) - http://ideone.com/2QvVvX
Правильно.
> W4.1(дописать кубик) - http://ideone.com/ckuYdx
Не совсем правильно, нет проверки на случай когда число очков одинаковое (ничья).
> W4.2(рулетка что смотрит последнюю цифру) - http://ideone.com/TKuvUB
Тут верно, но exit писать не требуется, так как после блока if/else все равно ничего нет. Ну и форматирование неправильное, скобки и elseif пишутся на одной строке:
} elseif (...) {
..
} else {
..
>>633417
Теперь верно, только exit там ставить не надо, в скрипте все равно после if/else ничего нету.
>>633450
Вроде генератор выглядит верно, но не уверен насчет этих полей:
> private $previewWidth;
> private $previewHeight;
Нужны ли они? Есть ли гарантия что они всегда заданы? Не уверен, нужны ли они как свойства и не лучше ли сделать их просто переменными. Также, функции должны начинаться с глагола: tooSmall -> isTooSmall.
По верстке:
- нехорошо что ты флоатишь влево картинку, а ссылку в которую она вложена, оставляешь - тут не очень понятно какую форму примет она. По идее у инлайн-элементов нет своей формы, они окружают содержимое. Но лучше бы флоатить ссылку.
- ты используешь абс. поз. для прижатия к низу города и времени, но учел ли ты сценарий когда название города переносится на новую строку? С абс. поз. ты не можешь это предусмотреть и оставить нужное количество места. Если говорить про максимально безопасную верстку, то я вижу только один вариант (без использования всяких флексбоксов): сделать таблицу из 2 колонок, слева поместить картинку, правую колонку сделать из 2 строк, сверху описание, снизу город и время. Город и время прижать вниз за счет vertical-align. Таблицу естественно средствами css, через display: table. Изучи-ка эту возможность, помни что там есть свои подвохи: у строк и ячеек таблицы нет маргинов, относительно элементов таблицы нельзя применять абс. позиционирование, для таблиц width/height обозначают min-width/height, а не реальные размеры.
Ну или как вариант, можно просто зарезервировать чуть больше места под город по вертикали.
> time {
надо писать .item time иначе это правило будет действовать на все такие теги на странице. Да и то, не очень хорошая идея, вдруг этот тег будет в описании?
> Думаю дальновидность придет с опытом, когда придется такой код поправлять под изменившиеся требования (убрать картинку, добавить текст описания и т.д.)
Если код семантично сверстан и все стили в css, то поправлять должно быть не очень сложно.
>>что будет если убрать картинку (не наедет ли цена на город?).
> Добавил min-height внешнему контейнеру
Лучше бы просто опираться на содержимое, паддинги и маргины, чтобы высота определялась контентом.
> Ну и я слышал, что для сео может быть важным порядок блоков, сначала должен идти основной контент, а затем выносить все меню и сайдбары, даже если они визуально идут выше/слева от главного контента.
СЕО это темная магия, которую мы не можем проверить, так что опираться на нее особо не стоит.
> Только с флотами получается странный порядок "слоев": у меня теперь идет сначала блок с ценой, а за ним заголовок, город и время. Хотя визуально сначала должен идти заголовок, а за ним цена (если смотреть слева направо).
Контент в HTML не обязан идти в том же порядке что выводится. Просто хорошо бы чтобы HTML код нормально читался.
> $symbol = mb_substr($text, $i, $halfLength);
Это непраивльно, ты берешь не первый символ, а первую половину строки и сравниваешь с пустой строкой (так как mb_substr($text, $length, $halfLength) даст пустую строку).
Надо брать за один шаг цикла по одному символу с двух краев строки.
>>633406
> W2(перевод долларов в рубли) - http://ideone.com/5zHXdu
Верно, но строка $roubles = 0; лишняя.
> W3(имитация броска кубика) - http://ideone.com/2QvVvX
Правильно.
> W4.1(дописать кубик) - http://ideone.com/ckuYdx
Не совсем правильно, нет проверки на случай когда число очков одинаковое (ничья).
> W4.2(рулетка что смотрит последнюю цифру) - http://ideone.com/TKuvUB
Тут верно, но exit писать не требуется, так как после блока if/else все равно ничего нет. Ну и форматирование неправильное, скобки и elseif пишутся на одной строке:
} elseif (...) {
..
} else {
..
>>633417
Теперь верно, только exit там ставить не надо, в скрипте все равно после if/else ничего нету.
>>633450
Вроде генератор выглядит верно, но не уверен насчет этих полей:
> private $previewWidth;
> private $previewHeight;
Нужны ли они? Есть ли гарантия что они всегда заданы? Не уверен, нужны ли они как свойства и не лучше ли сделать их просто переменными. Также, функции должны начинаться с глагола: tooSmall -> isTooSmall.
По верстке:
- нехорошо что ты флоатишь влево картинку, а ссылку в которую она вложена, оставляешь - тут не очень понятно какую форму примет она. По идее у инлайн-элементов нет своей формы, они окружают содержимое. Но лучше бы флоатить ссылку.
- ты используешь абс. поз. для прижатия к низу города и времени, но учел ли ты сценарий когда название города переносится на новую строку? С абс. поз. ты не можешь это предусмотреть и оставить нужное количество места. Если говорить про максимально безопасную верстку, то я вижу только один вариант (без использования всяких флексбоксов): сделать таблицу из 2 колонок, слева поместить картинку, правую колонку сделать из 2 строк, сверху описание, снизу город и время. Город и время прижать вниз за счет vertical-align. Таблицу естественно средствами css, через display: table. Изучи-ка эту возможность, помни что там есть свои подвохи: у строк и ячеек таблицы нет маргинов, относительно элементов таблицы нельзя применять абс. позиционирование, для таблиц width/height обозначают min-width/height, а не реальные размеры.
Ну или как вариант, можно просто зарезервировать чуть больше места под город по вертикали.
> time {
надо писать .item time иначе это правило будет действовать на все такие теги на странице. Да и то, не очень хорошая идея, вдруг этот тег будет в описании?
> Думаю дальновидность придет с опытом, когда придется такой код поправлять под изменившиеся требования (убрать картинку, добавить текст описания и т.д.)
Если код семантично сверстан и все стили в css, то поправлять должно быть не очень сложно.
>>что будет если убрать картинку (не наедет ли цена на город?).
> Добавил min-height внешнему контейнеру
Лучше бы просто опираться на содержимое, паддинги и маргины, чтобы высота определялась контентом.
> Ну и я слышал, что для сео может быть важным порядок блоков, сначала должен идти основной контент, а затем выносить все меню и сайдбары, даже если они визуально идут выше/слева от главного контента.
СЕО это темная магия, которую мы не можем проверить, так что опираться на нее особо не стоит.
> Только с флотами получается странный порядок "слоев": у меня теперь идет сначала блок с ценой, а за ним заголовок, город и время. Хотя визуально сначала должен идти заголовок, а за ним цена (если смотреть слева направо).
Контент в HTML не обязан идти в том же порядке что выводится. Просто хорошо бы чтобы HTML код нормально читался.
Эту строку можно не писать, она там просто как символ того что анон наконец-то выплатил весь кредит.
>>633464
Разумеется нужно.
>>633471
Проверять сумму надо уже после добавления к ней процентов и комиссий, но до выплаты.
> Или проверять надо не просто долг а долг с процентом на следующий месяц?
На текущий, почему на следующий?
>>633648
Дебаг это отладка, то есть выполнение кода по шагам с просмотром значений переменных. Попробуй погуглить по словам отладка, php.
>>633666
Не знаю, мне не нужен. Также, ты быстро устанешь писать парсеры под все сайты.
>>633857
В твоем коде не должно быть isset($var) так как это ненормально если ты сам не знаешь, есть такая переменная или нет. isset надо применять только с элементами массива.
>>634026
Насчет ретурн - надо проверять, а вообще можно все обернуть в большой иф.
>>634030
Можно сохранять ссылку с добавленным классом в переменную.
Эту строку можно не писать, она там просто как символ того что анон наконец-то выплатил весь кредит.
>>633464
Разумеется нужно.
>>633471
Проверять сумму надо уже после добавления к ней процентов и комиссий, но до выплаты.
> Или проверять надо не просто долг а долг с процентом на следующий месяц?
На текущий, почему на следующий?
>>633648
Дебаг это отладка, то есть выполнение кода по шагам с просмотром значений переменных. Попробуй погуглить по словам отладка, php.
>>633666
Не знаю, мне не нужен. Также, ты быстро устанешь писать парсеры под все сайты.
>>633857
В твоем коде не должно быть isset($var) так как это ненормально если ты сам не знаешь, есть такая переменная или нет. isset надо применять только с элементами массива.
>>634026
Насчет ретурн - надо проверять, а вообще можно все обернуть в большой иф.
>>634030
Можно сохранять ссылку с добавленным классом в переменную.
> Но phpExcell так же убирать все хтмл теги, поэтому в ячейки селекты я записать не могу, а как отключить экранирование я не нашел.
Не понимаю, при чем тут phpExcel если селекты ты выводишь самостоятельно и сомневаюсь что он удаляет теги из содержимого ячейки.
> Можно ли часть страницы отобразить в одной кодировке а вторую часть в другой?
Нельзя. Но можно преобразовывать текст в разных кодировках.
>>634217
Возвращаемое значение передается в метод mount, без return там передастся null и работать не будет. От того что ты создал переменную $blog, silex не начнет ее использовать.
>>634238
Алгоритм такой
- прибавляем проценты и комиссию к остатку долга (!не вычитаем ничего пока!)
- если остаток маленький, выплачиваем сколько осталось и уходим
- иначе платим 5000
«Платим» здесь значит уменьшаем долг и увеличиваем общую сумму выплаченного.
восемьсот постов, куда дальше? Я просто задачки свои выгрузить хочу, а в конец старого умирающего треда не хочется. т.к. следить за проверкой опа будет трудней и вообще
В чем выражается "труднее"? Что такое "вообще"?
Чтобы обновлять вывод из базы данных без перезагрузки, который может обновляться очень быстро.
Скинь тест, плиз.
Так и принято.
А почему ты используешь старый слим? В третьей версии появилась возможность передавать все запросы контроллерам, из-за этого роутер будет выглядеть вот так
>$app->get('/file/{id}', 'FileViewController:__invoke');
>$app->get('/file/{id}/delete', '\app\Controller\FileEditController');
>Эта проблема проявляется только если ты записываешь число в коде, напрмер:
>$x = 012;
>Тогда оно интерпретируется как восьмеричное из-за ведущего нуля. Но в математических операциях такой проблемы не будет, ты бдудешь получать обычные числа (точнее, в какой они системе счисления, будет неважно). Эта проблема есть только при записи числа в коде.
Да, я потом уже сообразил, что можно это обойти и при переводе числа в строку, и тем более при делении, как я доделываю сейчас. При делении оказывается проще, но у меня снова всё попадает в череду условий. Очень много условий, просто очень много условий. Я даже не знаю, как лучше сделать это всё. У меня сейчас на десятках миллионов скрипт, скоро надеюсь доделать и показать. Несколько несомненных костылей поставил, неприятно осознавать, что по-другому не могу придумать. Сократить многое не получается.
>>638394
Что ты имеешь в виду под "писать хорошо"?
Голуб и Розенталь - для правописания, стилистики, речевой грамотности (хотя последние два раздела там обзорно даются). Желательно периодически восстанавливать в памяти правила языка.
Начинать писать что-то более-менее серьёзное лучше после чтения хороших книг: художественных, научно-популярных. При этом во время чтения желателен анализ прочитанного, языковых конструкций, отслеживание речевых оборотов и общей стилистики написанного.
"Слово живое и мёртвое" Норы Галь - одна из лучших книг для того, кто хочет орудовать словом и вызывать отклик в читателях.
Для начинающих писателей, журналистов, блогеров такое было бы полезным.
>"Слово живое и мёртвое" Норы Галь - одна из лучших книг для того, кто хочет орудовать словом и вызывать отклик в читателях.
Для начинающих писателей, журналистов, блогеров такое было бы полезным.
Вот это я имел ввиду, спасибо большое.
Не за что, самому приятно хоть как-то помогать братишкам в хороших стремлениях.
Чтобы поля желтым подсвечивались
Двойные кавычки смотрятся гармоничнее, одинарные у меня ассоциируются с апострофами.
мимо-лягушатник
>Плохо то что не используются возможности ООП, а классы намертво связаны друг с другом. Попробуй почитать урок про DI https://gist.github.com/codedokode/e1d31a31b37d5f635057
Наверно этот урок самый сложный для меня. Я не первый раз его уже перечитываю и все равно не могу понять к каким случаям это применимо Его нужно применять чтобы классы как бы не пересекались с друг другом, а как бы первый класс передавался на вход другого, верно же?. Точнее сказать, не могу понять как применить это к конкретно моей проблеме со статическими методами >>636495
В моей голове представляется такое решение:
https://github.com/someApprentice/Students/blob/master/app/Controller/RegisterAction.php
В этом классе делать метод setRegistrationHelper(RegistrationHelper $reghelper) и вызывать его далее:
СТОП НЕТ
Мне все равно придется писать где-то в начале $reghelper = new RegistrationHelper()
Я не хочу так делать, я хочу чтобы я вызвал одну единственную функцию и все было готово как я это сделал здесь https://github.com/someApprentice/Students/blob/master/public/index.php#L6
ОП, я многого хочу? Это вообще входит в рамки задачи? И правильно ли будет так делать? Неужели я обречен всегда пользоваться инъекциями и забыть про статические методы? Зачем их тогда вообще сделали, будут ли от них избавляться(или уже избавились)?
Извиняюсь что так много вопросов, просто я совсем не понимаю это.
> То есть с методами типа getPdo(), getUserMapper() и тд.
Здесь мне тоже нужно будет пользоваться инъекциями зависимостей?
public function addStudent(Student $student, Container $container) {
$connect = $container->getPdo();
...
}
Естественно, в идеале, контейнер должен будет внедрятся через конструктор __construct(Container $container) {$this->container = $container;}
А я использую одинарные чтобы написать что-то понимает только машина, например названия ключей массива или регулярные выражения, а двойные какой-нибудь текст на вывод который понимает человек, например echo "Hello World";
>Можно почитать мануал/погуглить, можно попробовать так понять.
Мне просто кажется что все что ты кидаешь должно быть обязательно к прочтению, видит б-г я согласен с этим на 150%, но мне сложно читать много сразу. И так сложно все понять за раз. Просто не люблю растягивать что-то на долго - проще все за раз понять.
http://stackoverflow.com/questions/10856397/associative-arrays-and-java
У тебя в 15 строке точка с запятой лишняя.
Еще у тебя небольшие проблемы с форматированием кода. Старайся не ставить лишних пробелов и переносов на новую строку. Вот так код выглядит читабельнее https://ideone.com/3jI4yW
>PHP Notice: Undefined variable: mothlyPayment in /home/xcylPL/prog.php on line 21
Букву n пропустил в слове moNthly, наверно
и опять не в этом дело, что-то с самим кодом не так, я не могу понять что я делаю не так, теперь он нечего не выводит :Успешно\ttime: 0.02 memory: 52472 signal:0
нууу не платит этот школьник остаток
что с ним не так 12 месяц спустя: долг = 262.31722768997 руб, выплачено всего 60000 руб.
Еще ты должен исправить условие в 27 строке чтобы и при нулевом значении долга программа останавливалась, а не только при отрицательном.
>>638557
Даже со своим знанием php я не могу понять что не так. Натыкай echo после каждого изменения переменной и смотри где ошибка.
Ну и ну, даже простую задачу не могу понять. Я никогда не смогу заработать деньги умственным трудом. Зачем я живу(((
>вопрос к джавистам
>PHP тред
Ты делаешь это неправильно.
jad это мидлет отдельным файлом, нигде не видел кроме устаревшей платформы j2me.
http://ideone.com/BmD8eV видимо все дело в первом условии, которое выполняется на первом же шаге, сам посмотри. Перед ним эхо показывается, после - нет. Лень разбирать, сам смотри, что не так с твоим условием.
Он там точку с запятой поставил зачем-то. Условие нормальное, но считает неправильно.
http://ideone.com/2TF12j
Потому что ты завершаешь цикл если условие выполняется, таким образом скрипт не выводит данные за последний месяц.
Считает правильно, но ты скопипастил одинаковый код два раза. Так делать не желательно, ОПу бы не понравилось. Эту задачу можно решить по другому, в форме покороче. Подумай как.
я все сломал
Пытаюсь свести концы с концами в вопросе об уровнях изоляции транзакций и их
реализациям в движках mysql, в частности виды блокировок и мультиверсионность.
Поправь если что не так.
Все движки ставят неявную блокировку на чтение. То есть пока запись не будет
прочитана, другие клиенты не имеют права на ее изменение. Это понятно, было бы
странно, если бы один клиент начал читать запись, ее в тот же момент переписывал
другой, в результате нам вернулась бы полу-перезаписанная запись.
В myisam блокировка идет на уровне таблицы, то есть не только эту строку нельзя
изменять пока ее читает другой клиент, вообще нет доступа на запись в таблицу.
В innodb блокировка на уровне строк благодаря мультиверсионности.
Аналогично блокировка на запись. Пока один клиент осуществляет запись, другие не
могут читать и писать. Либо только эту запись в случае InnoDB, либо всю таблицу
в случае MyISAM.
Это блокировки только на время одного запроса. Чтобы объединить несколько
запросов в транзакцию в myisam используется явная блокировка таблиц LOCK
TABLE.
В InnoDB все сложнее.
Из-за отсутствия блокировок на всю таблицу операции выборки производятся в
режиме согласованного чтения. Это значит что выбираться будут только данные,
актуальные на момент начала данной транзакции. Если параллельная транзакция
закоммитила изменения, например добавила новые строки, то в рамках текущей
транзакции мы никогда не увидим эти новые строки. Нужно сначала закоммитить эту
транзакцию, после этого селекты станут актуальными.
Можно запретить другим транзакциям перезаписывать те строки, которые охватывает
условие данной выборки.
SELECT ... LOCK IN SHARE MODE
Можно запретить другим транзакциям читать строки, выбранные данной транзакцией,
пока она не будет закоммичена. Например если мы собираемся выбрать данные и
сразу их обновить.
SELECT ... FOR UPDATE
От потерянного обновления innodb защищен благодаря мультиверсинности. Строки не
перезаписываются, каждая транзакция создает новую запись.
От грязного чтения защищает тот же механизм mvcc, потому что каждая транзакция
не видит "грязных", незакоммиченных данных других транзакций.
Чтобы защититься от неповторяющегося чтения, придется явно использовать LOCK IN
SHARE MODE.
Для борьбы с фантомным чтением используется алгоритм Next-key locking.
http://dev.mysql.com/doc/refman/5.7/en/innodb-next-key-locking.html
Если я правильно понял, при использовании FOR UPDATE вызывается блокировка всего
промежутка (gap):
SELECT cols FROM tbl WHERE id > 100 FOR UPDATE;
Будет наложена next-key блокировка на все ключи с id > 100, в том числе на те,
которые еще не существуют. Ну то есть если у нас 110 записей в базе, и селект
вернет соответственно 10, то другие транзакции не могут вставить 111 запись.
Короче какое-то мутное место.
>Почему MyISAM блокирует таблицу на время апдейта одной строки?
Потому что там нет мультиверсионности, при апдейте не создается новая версия, а
идет перезапись. Короче, без блокировки будет потерянное обновление. Или даже
хуже: если две транзакции попытаются одновременно писать в одно место файла с
таблицей, то получится каша, часть символов из одной транзакции, часть из
другой.
>Почему MVCC позволяет это не делать?
При обновлении строки не перезаписываются старые данные, а добавляется в конец
файла с таблицей новая строка. Идет запись в разные места файла.
>почему InnoDB блокирует строки, хотя MVCC позволяет это не делать?
Нарушится согласованность данных. Например одна транзакция выполнит
SET field = field + 10 (видит закоммиченное значение 100)
вторая
SET field = field + 20 (видит то же самое закоммиченное значение 100)
Затем обе транзакции коммитятся, первая запишет 110, а вторая 120, хотя мы
ожидали 130. Похоже на потерянное обновление.
>если программа выбирает какие-то данные (SELECT), меняет их и записывает назад
>в базу (UPDATE), как запретить другим в это время их менять?
LOCK IN SHARE MODE. Если нужно блокировать и на чтение, то SELECT ... FOR UPDATE.
Пытаюсь свести концы с концами в вопросе об уровнях изоляции транзакций и их
реализациям в движках mysql, в частности виды блокировок и мультиверсионность.
Поправь если что не так.
Все движки ставят неявную блокировку на чтение. То есть пока запись не будет
прочитана, другие клиенты не имеют права на ее изменение. Это понятно, было бы
странно, если бы один клиент начал читать запись, ее в тот же момент переписывал
другой, в результате нам вернулась бы полу-перезаписанная запись.
В myisam блокировка идет на уровне таблицы, то есть не только эту строку нельзя
изменять пока ее читает другой клиент, вообще нет доступа на запись в таблицу.
В innodb блокировка на уровне строк благодаря мультиверсионности.
Аналогично блокировка на запись. Пока один клиент осуществляет запись, другие не
могут читать и писать. Либо только эту запись в случае InnoDB, либо всю таблицу
в случае MyISAM.
Это блокировки только на время одного запроса. Чтобы объединить несколько
запросов в транзакцию в myisam используется явная блокировка таблиц LOCK
TABLE.
В InnoDB все сложнее.
Из-за отсутствия блокировок на всю таблицу операции выборки производятся в
режиме согласованного чтения. Это значит что выбираться будут только данные,
актуальные на момент начала данной транзакции. Если параллельная транзакция
закоммитила изменения, например добавила новые строки, то в рамках текущей
транзакции мы никогда не увидим эти новые строки. Нужно сначала закоммитить эту
транзакцию, после этого селекты станут актуальными.
Можно запретить другим транзакциям перезаписывать те строки, которые охватывает
условие данной выборки.
SELECT ... LOCK IN SHARE MODE
Можно запретить другим транзакциям читать строки, выбранные данной транзакцией,
пока она не будет закоммичена. Например если мы собираемся выбрать данные и
сразу их обновить.
SELECT ... FOR UPDATE
От потерянного обновления innodb защищен благодаря мультиверсинности. Строки не
перезаписываются, каждая транзакция создает новую запись.
От грязного чтения защищает тот же механизм mvcc, потому что каждая транзакция
не видит "грязных", незакоммиченных данных других транзакций.
Чтобы защититься от неповторяющегося чтения, придется явно использовать LOCK IN
SHARE MODE.
Для борьбы с фантомным чтением используется алгоритм Next-key locking.
http://dev.mysql.com/doc/refman/5.7/en/innodb-next-key-locking.html
Если я правильно понял, при использовании FOR UPDATE вызывается блокировка всего
промежутка (gap):
SELECT cols FROM tbl WHERE id > 100 FOR UPDATE;
Будет наложена next-key блокировка на все ключи с id > 100, в том числе на те,
которые еще не существуют. Ну то есть если у нас 110 записей в базе, и селект
вернет соответственно 10, то другие транзакции не могут вставить 111 запись.
Короче какое-то мутное место.
>Почему MyISAM блокирует таблицу на время апдейта одной строки?
Потому что там нет мультиверсионности, при апдейте не создается новая версия, а
идет перезапись. Короче, без блокировки будет потерянное обновление. Или даже
хуже: если две транзакции попытаются одновременно писать в одно место файла с
таблицей, то получится каша, часть символов из одной транзакции, часть из
другой.
>Почему MVCC позволяет это не делать?
При обновлении строки не перезаписываются старые данные, а добавляется в конец
файла с таблицей новая строка. Идет запись в разные места файла.
>почему InnoDB блокирует строки, хотя MVCC позволяет это не делать?
Нарушится согласованность данных. Например одна транзакция выполнит
SET field = field + 10 (видит закоммиченное значение 100)
вторая
SET field = field + 20 (видит то же самое закоммиченное значение 100)
Затем обе транзакции коммитятся, первая запишет 110, а вторая 120, хотя мы
ожидали 130. Похоже на потерянное обновление.
>если программа выбирает какие-то данные (SELECT), меняет их и записывает назад
>в базу (UPDATE), как запретить другим в это время их менять?
LOCK IN SHARE MODE. Если нужно блокировать и на чтение, то SELECT ... FOR UPDATE.
Не знаю, я просто не верю что у меня что-то получится. Я сейчас писал большую стену текста, но потом понял что не хочу говорить об этом, просто не хочу чтобы твой интерес оставался не удовлетворенным.
Обсуждение на анонимных бордах личных проблем не помогут решить их!
Убери первый break, а вот это
$creditBalance = $creditBalance - $monthlyPayment;
\t$paymentTotal = $paymentTotal + $monthlyPayment;
\techo "{$month} месяц спустя: долг = {$creditBalance} руб, выплачено всего {$paymentTotal} руб. \n";
засунь в else
если не отнимать 2868, то ответ не правильный получится, а я и не понимаю почему ответ не правильный. А без if($creditBalance < 5000) я вообще не знаю как обойтись.
Ну и ещё echo в этот if добавь, чтобы окончательный результат выводился
>если не отнимать 2868, то ответ не правильный получится
Ну это уже костыль какой-то, все должно работать и без этого.
Вообще эту задачу можно решить двумя строками.
вот я и пытаюсь выяснить из чего прибавляется 2868, что приходится это отнимать
http://ideone.com/SKdNSl
http://ideone.com/GaB9k4
12 месяц спустя: долг = 262.31722768997 руб, выплачено всего 60000 руб.
С меня хватит
Чувак, я сначала тоже все путал и не мог разобраться, но сейчас уже почти решил, борись до конца.
ниичесии
http://ideone.com/GaB9k4
13 месяц спустя: долг = 0 руб, выплачено всего 61270.186744521 руб.
С меня хватит!
Спасибо всем кто помог мне в это не простом сражении.
W5.2 Некто кладет в банк 10000 р. Банк начисляет 10% годовых (то есть, каждый год на счету становится на 10% больше, чем в прошлом году). Напиши программу, считающую, через сколько лет в банке будет миллион? Сколько лет будет этому некто? Доживет ли некто до этого дня, если сегодня ему 16 лет?
Поздравляю, сколько времени ушло не решение?
Ну как бы у тебя цикл работает пока баланс меньше некоторой суммы, а условие внутри рассчитано на то, что он будет больше. Очевидно, что оно никогда не сработает.
А каким должен быть тогда алгоритм? Я вообще эту задачку понять не могу.
да я сделал только с помощью великих анонов, но еще много чего не понял.
Но, тем не менее, ты неймфажишь. Выпиливайся, если хочешь, чем черт не шутит. Я не из-за интереса спросил, если б ты хотел выпилиться, ты бы это уже сделал, а не спрашивал тут разрешение на это.
Ты просто истеричка. Обсуждение проблем их не решит вообще, а не только на бордах. Но у тебя ведь нет проблем или они не настолько тебя волнуют, чтобы как-то решить или избавиться от них. У тебя нет проблем. И я это говорю не потому что ты ребенок или потому что я хочу тебя сравнить себя с тобой. Я хочу, чтобы ты понял, что программирование это не панацея и оно не озолотит тебя и не возвысит в глазах твоей девушки или мамки.
Программирование на php, создание сайтов - это бесполезное дело. Как, к примеру, каллиграфия. Мне очень нравится писать красиво пером. Курсивом или старым готическим. Но это бесполезно, оно греет только мой интерес. Так же и с программированием, мне интересно было создать нечто, куда я буду выкладывать свои рецепты. Я повар в среднем ресторане. Но сделать так, чтобы это было не какой-то книженцией или блокнотом, я решил в свободное время создавать свой сайт с собранием рецептом приготовления различной пищи. Я тщательно продумывал все: какие разделы там будут, дизайн, стиль написания, как преподнести фотографии с собственной кухни и прочее и прочее.
Не буду вдаваться в подробности, что и как я учил. Это было долго и с перерывами, но у меня не было какой-то жажды получить со своего сайта деньги. Я делал это как свое хобби. И, вот, сейчас, я нахожусь в некотором смятении от тебя.
Я позволю себе задать тебе пару вопросов. Программирование на php твоя мечта? Или ты просто ничего, кроме этого не умеешь? Почему ты не поступил в технический вуз? Ты не слишком ленив, чтобы каждый день учить php?
Когда меня отчислили из двух вузов подряд, я сначала отчаялся, но потом нашел в себе силы сделать себе распорядок дня какой был во время моего обучения. Напридумывал себе предметов, которые учил как в вузе и даже усерднее! и сейчас продолжаю, потому что в вузике было ламповое время, как не крути.
На этой ноте я прерываю свою короткую речь и даю право высказаться тебе.
Но, тем не менее, ты неймфажишь. Выпиливайся, если хочешь, чем черт не шутит. Я не из-за интереса спросил, если б ты хотел выпилиться, ты бы это уже сделал, а не спрашивал тут разрешение на это.
Ты просто истеричка. Обсуждение проблем их не решит вообще, а не только на бордах. Но у тебя ведь нет проблем или они не настолько тебя волнуют, чтобы как-то решить или избавиться от них. У тебя нет проблем. И я это говорю не потому что ты ребенок или потому что я хочу тебя сравнить себя с тобой. Я хочу, чтобы ты понял, что программирование это не панацея и оно не озолотит тебя и не возвысит в глазах твоей девушки или мамки.
Программирование на php, создание сайтов - это бесполезное дело. Как, к примеру, каллиграфия. Мне очень нравится писать красиво пером. Курсивом или старым готическим. Но это бесполезно, оно греет только мой интерес. Так же и с программированием, мне интересно было создать нечто, куда я буду выкладывать свои рецепты. Я повар в среднем ресторане. Но сделать так, чтобы это было не какой-то книженцией или блокнотом, я решил в свободное время создавать свой сайт с собранием рецептом приготовления различной пищи. Я тщательно продумывал все: какие разделы там будут, дизайн, стиль написания, как преподнести фотографии с собственной кухни и прочее и прочее.
Не буду вдаваться в подробности, что и как я учил. Это было долго и с перерывами, но у меня не было какой-то жажды получить со своего сайта деньги. Я делал это как свое хобби. И, вот, сейчас, я нахожусь в некотором смятении от тебя.
Я позволю себе задать тебе пару вопросов. Программирование на php твоя мечта? Или ты просто ничего, кроме этого не умеешь? Почему ты не поступил в технический вуз? Ты не слишком ленив, чтобы каждый день учить php?
Когда меня отчислили из двух вузов подряд, я сначала отчаялся, но потом нашел в себе силы сделать себе распорядок дня какой был во время моего обучения. Напридумывал себе предметов, которые учил как в вузе и даже усерднее! и сейчас продолжаю, потому что в вузике было ламповое время, как не крути.
На этой ноте я прерываю свою короткую речь и даю право высказаться тебе.
я пока что не могу понять
http://ideone.com/fjJUwP
Смотри.
У тебя деньги лежат на депозите под 10%. Очевидно, что ты должен увеличивать денежную сумму раз в год, умножая на 1.1.
А ты умножаешь на 0.1. Т.е. получается, что у тебя от суммы остаётся 10% а не выходит 110%
Может сравнение ставится вот так - "== "а не "=". = это присвоение, попробуй исправить.
error-reporting не поставил, это да.
блин я был на верном пути
>return new $c['session_storage_class']($c['cookie_name']);
А что это за способ записи такой? Первый раз вижу чтобы при создании объекта что-то писалось в квадратных скобках перед передачей аргументов.
Так это обращение по индексу массива, чтобы достать оттуда имя класса.
http://ideone.com/OAbxeE
Принято писать что изменено, например "добавлена возможность комментировать файлы" или "fixed bug with uploading large files". По идее каждая фича или исправленный баг - это отдельный коммит. В этом случае история коммитов смотрится хорошо.
>>638419
А зачем контроллеры в микрофреймворке? На то он и микрофреймворк чтобы код контроллеров был в index.php
Нет, это не она, это подпункт это задачи, но это не она.
Блин, бро, ты не читаk предыдущие разъясняющие сообщения?
>>638062
>Вот какой совет: попробуй добиться правильной работы при первом прохождении скрипта при сумме, меньшей 5000.
>Вот чтобы раз - и тут же выплатилась эта сумма.
>Вот как бы ты это реализовал с помощью переменной $pain?
>А дальше или сам уже всё увидишь, или опять будем вместе думать.
Попробуй добиться выплаты сразу, чтобы попала в цикл сумма меньше 5000 (уже после умножения кредитбаланс на персент и с прибавлением кредитсервис) и тут же выплатилась.
Давай-давай, пробуй. Дальше только цикл надо будет заставить работать с суммой 40к.
Он должен каждый год просчитывать, или ничего что он сразу все посчитал?
Главное, что посчитал всё верно.
Так-то просто echo внутрь цикла помести - выдаст при каждом проходе цикла сумму за каждый год.
Несколько способов, как не топтаться на месте с этой задачей.
1. Ввести переменную для подсчёта $creditBalance с $percent и $servicePayment. Не отнимать от неё никакие $monthlyPayment.
2. Заставить программу выплатить $creditBalance с $percent и $servicePayment (или введённую переменную) при первом же прохождении цикла. Для этого $creditBalance или введённая для этого переменная должны быть сразу меньше 5000 и должны уже содержать умножение $creditBalance на проценты и с прибавленной комиссией за обслуживание кредита. Итоговая цифра должна быть меньше 5000.
3. Обрывать цикл при сумме, равной нулю, а не меньшей нуля. Отрицательного $creditBalance не должно получиться при верном решении этой задачи.
>Подсказка: перед тем, как платить, надо проверять, сколько осталось долга, и если он меньше 5000, то платить только остаток и завершать цикл через break.
Оп по моему разжевал уже дальше некуда.
А что сейчас в школах/универах по убирали информатику? Просто я это все на турбо паскале в школе делал в до двачевскую эпоху.
Вдогонку к этому, я только сейчас понимаю (спустя месяц после начала занятий по учебнику ОПа), что я до сих пор не совсем представляю себе роль ПХП в работе сайтов, что вообще мне предстоит делать и как использовать пхп. Я тут один такой даун?
Если в рамках работы страницы по какому-то условию останавливаю работу кода через exit(), то надо ли ручками переменные подчищать вида unset($thesisid, $usrdoc). Так делаю постоянно, но задумался, а надо ли?
При попытке заходе пользователя на страницу сайта браузер отправляет запрос ("а дай-ка мне страницу http://example.com/page") на сервер, там запускается пхп скрипт, который достает нужные данные из базы и формирует HTML код, который отправляется назад в браузер и отображается там. Так что без знания php никак.
>>639032
Ты занимаешь глупостью. В PHP автоматическое управление памятью и ест сборка мусора. Ты лишь усложняешь чтение и поддержку твоего скрипта.
>на сервер, там запускается пхп скрипт, который достает нужные данные из базы и формирует HTML код
но что всё это означает? После учебника ты получаешь общие сведения о языке и о том, как делать кредитные калькуляторы, я в глаза не видел вордпрессы, сервера и прочее, я даже не знаю, пишешь ли программу отдельным файлом или внутри хтмл-кода. Как всё это постичь? Ничего не понятно, честное слово, я в агонии
После учебника освоишь основы HTML, установишь Апач и будешь запускать код там. Все равно без самого PHP ничего не сделать. Ну а скорость изучения уже от тебя зависит.
Если тебе интересно, в ОП посте есть паста по установке Апача и интерпретатора PHP, а в офиц. мануале в начале есть про то, как вставлять php в html код. Можешь попробовать.
http://ideone.com/QAkV91
https://github.com/disbeliever/php_training/blob/master/students/db.sql
В postgres есть интересная возможность - можно с помощью ограничения CHECK ставить проверки для вставляемых в колонку значений. Ну например, можно ограничить символы, которые разрешено использовать в имени и фамилии, или макс. и мин. число баллов за ЕГЭ, указав допустимые значения для года рождения. Это защищает базу от вставки неправильных данных. Продемонстрируй знание этой особенности, добавив ограничения в соответствие с логикой задачи.
Число баллов стоит сделать неотрицательным (unsigned).
https://github.com/disbeliever/php_training/blob/master/students/src/init.php#L9
> if ($config['debug']) {
> error_reporting(-1);
А зачем это? error_reporting отвечает за игнорирование ошибок и предупреждений, и не очень понятно почему ты их хочешь игнорировать при отключенном дебаге?
> $STG = new StudentTableGateway($PDO, $config['studentsPerPage']);
переменные пишутся с маленькой буквы, большими буквами пишутся константы.
https://github.com/disbeliever/php_training/blob/master/students/public/index.php
Плохо, что у тебя прямо в index.php какие-то посторонние функции. Зачем они тут? Лучше всего сделать класс вроде UrlHelper и поместить их туда. Таким образом ты вынесешь все, что относится к формрованию УРЛ в отдельный класс.
Также, не используй глобальные переменные, тем более через global $x. Все, что нужно функции, можно передать через аргументы.
Также, лучше не использовать при формировании URL конструкции вроде {$_SERVER['SCRIPT_NAME']} - надежнее просто прописать конкретное название скрипта. Ведь лучше когда результат вызова функции возвращает один и тот же URL, а не надеется на то, что скрипт называется определенным образом.
Также, я думаю, в маппер лучше передавать не номер страницы, а offset + limit. Ведь по идее мы можем в выводить записи с разным числом записей на страницу, лучше не закладывать разбиение на страницы в маппер, а сделать универсальный код, получающий любое число записей.
https://github.com/disbeliever/php_training/blob/master/students/public/index.php#L49
Строки длиннее 80 символов надо переносить. В рекомендации PSR-3 написано как разбить вызов функции на несколько строк.
https://github.com/disbeliever/php_training/blob/master/students/public/ControllerStudent.php
Немного странное название, не лучше ли назвать скрипт вроде profile.php или register.php? Впрочем, это не ошибка, можно и так оставить.
https://github.com/disbeliever/php_training/blob/master/students/src/autoloader.php#L2
Эта функция давно устарела, переделывай на spl_autoload_register, погугли, есть статья на хабре + есть мануал. Функцию canClassBeAutloaded мне кажется можно выпилить, так как проверить наличие класса можно через class_exists.
https://github.com/disbeliever/php_training/blob/master/students/src/config.php
В конфиг должны идти только параметры, которые меняет пользователь. Я думаю, AUTH_LENGTH сюда явно не относится, и эта константа должна быть в классе или функции, отвечающей за авторизацию.
https://github.com/disbeliever/php_training/blob/master/students/src/registerHelpers.php
И тут функции! Давай-ка переделывать на ООП. Функции, которые не относятся ни к одному объекту, можно сделать статическими методами в классе Util или Helper. Функции, относящиеся к регистрации студента, помещаем в обычный класс StudentHelper, StudentService, как-то так. Функции отвечающие за авторизацию и проверку токенов, можно либо засунуть туда же, либо в отдельный класс, отвечающий за авторизацию.
https://github.com/disbeliever/php_training/blob/master/students/src/registerHelpers.php#L21
> foreach (array_keys(get_object_vars($student))
Это ненадежно. ЧТо если кто-то добавит в объект поле isAdmin, получается его можно будет перезаписать? Надо сделать явный массив или функцию, возвращающую список разрешенных для изменения полей. Между прочим, по похожей причине в свое время взломали гитхаб, там тоже не было задано явного списка полей, доступных для изменения.
> ["class" => "danger", "text" => "Ошибка CSRF токена"];
Как по твоему обычный человек поймет, что здесь написано? Надо написать что-то понятное. Обычно ошибка сравнения токена происходит из-за того что форма долго не отправлялась и кука умерла. Значит, надо написать об этом и попросить отправить форму повторно.
> isCSRFTokenSet() && isFormTokenSet() && $_COOKIE['csrf'] == $_POST['csrfToken']
Это хорошо бы заменить на вызов одной функции проверки токена. Ну логично, должна быть функция генерации токена и функция проверки.
https://github.com/disbeliever/php_training/blob/master/students/public/ControllerStudent.php#L44
> catch (PDOException $e) {
Ну что же вы все делаете эту ошибку с catch? Ты обрабатываешь исключения неправильно, держи пасту:
----------
Как надо обрабатывать исключения:
- записать информацию в лог
- показать пользователю заглушку
- на заглушке выставить HTTP 503 код ответа для роботов
- на компьютере разработчика (при display_errors = 1) показать подробности и стектрейс
Что будет если использовать catch + echo:
- в лог ничего не фиксируется, ты не узнаешь об ошибках
- пользователь видит непонятную белиберду на английском
- отдается код 200
Как будет если просто не ловить исключение:
- информация пишется в лог (ок)
- на компьютере разработчика выводятся подробности (ок)
- пользователь видит белую страницу (не ок)
- отдается код 200 (не ок)
Почитай также урок https://gist.github.com/codedokode/65d43ca5ac95c762bc1a
----------
До исключений мы должны были после каждой функции писать иф и проверять ее результат, не было ли ошибки. Исключения позволили отказаться от этого. Так как исключение автоматически выходит из вложенных вызовов функций наверх, нам достаточно одного-единственного обработчика исключений на самом верху:
try {
$app->run();
} catch (..) {
$app->showErrorPage();
}
Более того, мы можем и этого не делать, так как пхп сам ловит непойманные исключения, логгирует их, выводит пустую страницу в браузер и завершает скрипт.
Ловить исключения где-то еще надо если у нас есть способ обработать их. Ну например мы можем ловить ошибку соединения с удаленным сервером чтобы сделать еще несколько попыток. Очевидно что в этом случае мы ловим не все подряд, а конкретное исключение, отвечающее за ошибку соединения с сервером.
----------
В общем, надо либо сделать нормальный обработчик исключений, охватывающий весь контроллер, либо не ловить их и положиться на php (который завершит скрипт и покажет белую страницу с кодом 200). Оборачивать большой скрипт в try/catch неудобно, потому код контроллера может понадобиться вынести в функцию или класс.
> else if ($_SERVER['REQUEST_METHOD'] == "GET") {
Я думаю лучше просто else
Также, редактирование студента лучше делать так: загрузить студента из БД и после этого из POST обновить ему поля. Так получается надежнее, и например если из формы позже удалят какое-то поле то старые данные не потеряются.
Также, есть ли у тебя проверка права редактировать данного студента? Вижу впрочем, что обновление делается по auth.
https://github.com/disbeliever/php_training/blob/master/students/public/ControllerStudent.php#L55
> if ($id > 0) {
> $student = $STG->getStudent($id);
Это позволяет загрузить данные любого студента в форму? Уверен, что это правильно? Мне кажется там должна быть проверка auth куки.
https://github.com/disbeliever/php_training/blob/master/students/public/ControllerStudent.php#L67
> if ((isset($student->id) && $student->id > 0) || isset($_COOKIE['auth'])) {
Условие неправильное: кука может быть не пуста, но не соответствовать никому в базе.
https://github.com/disbeliever/php_training/blob/master/students/src/StudentTableGateway.php#L48
> if (is_string($key) && strlen($key) == CONFIG_AUTH_LENGTH) {
Вот это плохая идея, обозначать одной переменной 2 разные вещи. Это ведет к ошибкам и уязвимостям. Надо сделать либо 2 разных функции, либо 2 разных параметра для ид и токена. То есть что мы передаем, должно указываться явно.
https://github.com/disbeliever/php_training/blob/master/students/src/StudentTableGateway.php#L69
Странный алгроритм, не лучше тут in_array использовать? Или комментарий написать как это работает.
> return Student::fromRow($row);
Если подумать, то маппингом данных из базы данных на объект должен заниматься маппер, а не модель студента. Однако, в модели студента можно конечно сделать метод fromArray, не привязанный явно к базе данных.
> $arr[] = Student::fromRow($row);
$arr -> $students или $result
...продолжение далее ...
https://github.com/disbeliever/php_training/blob/master/students/db.sql
В postgres есть интересная возможность - можно с помощью ограничения CHECK ставить проверки для вставляемых в колонку значений. Ну например, можно ограничить символы, которые разрешено использовать в имени и фамилии, или макс. и мин. число баллов за ЕГЭ, указав допустимые значения для года рождения. Это защищает базу от вставки неправильных данных. Продемонстрируй знание этой особенности, добавив ограничения в соответствие с логикой задачи.
Число баллов стоит сделать неотрицательным (unsigned).
https://github.com/disbeliever/php_training/blob/master/students/src/init.php#L9
> if ($config['debug']) {
> error_reporting(-1);
А зачем это? error_reporting отвечает за игнорирование ошибок и предупреждений, и не очень понятно почему ты их хочешь игнорировать при отключенном дебаге?
> $STG = new StudentTableGateway($PDO, $config['studentsPerPage']);
переменные пишутся с маленькой буквы, большими буквами пишутся константы.
https://github.com/disbeliever/php_training/blob/master/students/public/index.php
Плохо, что у тебя прямо в index.php какие-то посторонние функции. Зачем они тут? Лучше всего сделать класс вроде UrlHelper и поместить их туда. Таким образом ты вынесешь все, что относится к формрованию УРЛ в отдельный класс.
Также, не используй глобальные переменные, тем более через global $x. Все, что нужно функции, можно передать через аргументы.
Также, лучше не использовать при формировании URL конструкции вроде {$_SERVER['SCRIPT_NAME']} - надежнее просто прописать конкретное название скрипта. Ведь лучше когда результат вызова функции возвращает один и тот же URL, а не надеется на то, что скрипт называется определенным образом.
Также, я думаю, в маппер лучше передавать не номер страницы, а offset + limit. Ведь по идее мы можем в выводить записи с разным числом записей на страницу, лучше не закладывать разбиение на страницы в маппер, а сделать универсальный код, получающий любое число записей.
https://github.com/disbeliever/php_training/blob/master/students/public/index.php#L49
Строки длиннее 80 символов надо переносить. В рекомендации PSR-3 написано как разбить вызов функции на несколько строк.
https://github.com/disbeliever/php_training/blob/master/students/public/ControllerStudent.php
Немного странное название, не лучше ли назвать скрипт вроде profile.php или register.php? Впрочем, это не ошибка, можно и так оставить.
https://github.com/disbeliever/php_training/blob/master/students/src/autoloader.php#L2
Эта функция давно устарела, переделывай на spl_autoload_register, погугли, есть статья на хабре + есть мануал. Функцию canClassBeAutloaded мне кажется можно выпилить, так как проверить наличие класса можно через class_exists.
https://github.com/disbeliever/php_training/blob/master/students/src/config.php
В конфиг должны идти только параметры, которые меняет пользователь. Я думаю, AUTH_LENGTH сюда явно не относится, и эта константа должна быть в классе или функции, отвечающей за авторизацию.
https://github.com/disbeliever/php_training/blob/master/students/src/registerHelpers.php
И тут функции! Давай-ка переделывать на ООП. Функции, которые не относятся ни к одному объекту, можно сделать статическими методами в классе Util или Helper. Функции, относящиеся к регистрации студента, помещаем в обычный класс StudentHelper, StudentService, как-то так. Функции отвечающие за авторизацию и проверку токенов, можно либо засунуть туда же, либо в отдельный класс, отвечающий за авторизацию.
https://github.com/disbeliever/php_training/blob/master/students/src/registerHelpers.php#L21
> foreach (array_keys(get_object_vars($student))
Это ненадежно. ЧТо если кто-то добавит в объект поле isAdmin, получается его можно будет перезаписать? Надо сделать явный массив или функцию, возвращающую список разрешенных для изменения полей. Между прочим, по похожей причине в свое время взломали гитхаб, там тоже не было задано явного списка полей, доступных для изменения.
> ["class" => "danger", "text" => "Ошибка CSRF токена"];
Как по твоему обычный человек поймет, что здесь написано? Надо написать что-то понятное. Обычно ошибка сравнения токена происходит из-за того что форма долго не отправлялась и кука умерла. Значит, надо написать об этом и попросить отправить форму повторно.
> isCSRFTokenSet() && isFormTokenSet() && $_COOKIE['csrf'] == $_POST['csrfToken']
Это хорошо бы заменить на вызов одной функции проверки токена. Ну логично, должна быть функция генерации токена и функция проверки.
https://github.com/disbeliever/php_training/blob/master/students/public/ControllerStudent.php#L44
> catch (PDOException $e) {
Ну что же вы все делаете эту ошибку с catch? Ты обрабатываешь исключения неправильно, держи пасту:
----------
Как надо обрабатывать исключения:
- записать информацию в лог
- показать пользователю заглушку
- на заглушке выставить HTTP 503 код ответа для роботов
- на компьютере разработчика (при display_errors = 1) показать подробности и стектрейс
Что будет если использовать catch + echo:
- в лог ничего не фиксируется, ты не узнаешь об ошибках
- пользователь видит непонятную белиберду на английском
- отдается код 200
Как будет если просто не ловить исключение:
- информация пишется в лог (ок)
- на компьютере разработчика выводятся подробности (ок)
- пользователь видит белую страницу (не ок)
- отдается код 200 (не ок)
Почитай также урок https://gist.github.com/codedokode/65d43ca5ac95c762bc1a
----------
До исключений мы должны были после каждой функции писать иф и проверять ее результат, не было ли ошибки. Исключения позволили отказаться от этого. Так как исключение автоматически выходит из вложенных вызовов функций наверх, нам достаточно одного-единственного обработчика исключений на самом верху:
try {
$app->run();
} catch (..) {
$app->showErrorPage();
}
Более того, мы можем и этого не делать, так как пхп сам ловит непойманные исключения, логгирует их, выводит пустую страницу в браузер и завершает скрипт.
Ловить исключения где-то еще надо если у нас есть способ обработать их. Ну например мы можем ловить ошибку соединения с удаленным сервером чтобы сделать еще несколько попыток. Очевидно что в этом случае мы ловим не все подряд, а конкретное исключение, отвечающее за ошибку соединения с сервером.
----------
В общем, надо либо сделать нормальный обработчик исключений, охватывающий весь контроллер, либо не ловить их и положиться на php (который завершит скрипт и покажет белую страницу с кодом 200). Оборачивать большой скрипт в try/catch неудобно, потому код контроллера может понадобиться вынести в функцию или класс.
> else if ($_SERVER['REQUEST_METHOD'] == "GET") {
Я думаю лучше просто else
Также, редактирование студента лучше делать так: загрузить студента из БД и после этого из POST обновить ему поля. Так получается надежнее, и например если из формы позже удалят какое-то поле то старые данные не потеряются.
Также, есть ли у тебя проверка права редактировать данного студента? Вижу впрочем, что обновление делается по auth.
https://github.com/disbeliever/php_training/blob/master/students/public/ControllerStudent.php#L55
> if ($id > 0) {
> $student = $STG->getStudent($id);
Это позволяет загрузить данные любого студента в форму? Уверен, что это правильно? Мне кажется там должна быть проверка auth куки.
https://github.com/disbeliever/php_training/blob/master/students/public/ControllerStudent.php#L67
> if ((isset($student->id) && $student->id > 0) || isset($_COOKIE['auth'])) {
Условие неправильное: кука может быть не пуста, но не соответствовать никому в базе.
https://github.com/disbeliever/php_training/blob/master/students/src/StudentTableGateway.php#L48
> if (is_string($key) && strlen($key) == CONFIG_AUTH_LENGTH) {
Вот это плохая идея, обозначать одной переменной 2 разные вещи. Это ведет к ошибкам и уязвимостям. Надо сделать либо 2 разных функции, либо 2 разных параметра для ид и токена. То есть что мы передаем, должно указываться явно.
https://github.com/disbeliever/php_training/blob/master/students/src/StudentTableGateway.php#L69
Странный алгроритм, не лучше тут in_array использовать? Или комментарий написать как это работает.
> return Student::fromRow($row);
Если подумать, то маппингом данных из базы данных на объект должен заниматься маппер, а не модель студента. Однако, в модели студента можно конечно сделать метод fromArray, не привязанный явно к базе данных.
> $arr[] = Student::fromRow($row);
$arr -> $students или $result
...продолжение далее ...
https://github.com/disbeliever/php_training/blob/master/students/src/StudentValidator.php#L15
> if (($length = mb_strlen($fieldValue)) > $maxLength) {
Присваивание стоит вынести из ифа, не надо городить такие сложные выражения, так как тут явно 2 отдельных действия (присваивание и иф).
> !ctype_alnum($fieldValue)
Я могу ошибаться, но по моему это не позволит ввести русские буквы. Тут нужна регулярка.
https://github.com/disbeliever/php_training/blob/master/students/src/StudentValidator.php#L32
> mb_strlen($fieldValue) > 5
Не используется переменная maxLength
https://github.com/disbeliever/php_training/blob/master/students/src/StudentValidator.php#L39
> if (!($fieldValue == "male" || $fieldValue == "female"))
Надо сделать обозначения пола константами в модели студента, Student::GENDER_MALE, а то это магические строки и это плохо (а, они уже даже сделаны).
Для имени и фамилии надо сделать проверку на допустимые символы, как указано в задании.
https://github.com/disbeliever/php_training/blob/master/students/src/Pager.php#L21
> str_replace("_page_",
Эта конструкция с подчеркиванием может встретиться в УРЛ (show_page_list.php), лучше исплоьзовать другие символы-ограничители.
https://github.com/disbeliever/php_training/blob/master/students/src/registerHelpers.php#L15
> md5(rand());
В чем смысл от мд5 здесь? Она не увеличивает число вариантов (около 4 млрд), оно только увеличивает длину токена не добавляя защищенности. Делай честный случайный токен, а не видимость защиты.
Даже если у пользователя стоит CSRF кука, надо ее продлевать - иначе она может умереть.
https://github.com/disbeliever/php_training/blob/master/students/src/views/ViewStudent.php#L21
> />
В HTML не ставится слеш в конце тега.
В пагинации надо выделять текущую страницу. Не показывать пагинацию если всего 1 страница.
https://github.com/disbeliever/php_training/blob/master/students/src/StudentValidator.php#L15
> if (($length = mb_strlen($fieldValue)) > $maxLength) {
Присваивание стоит вынести из ифа, не надо городить такие сложные выражения, так как тут явно 2 отдельных действия (присваивание и иф).
> !ctype_alnum($fieldValue)
Я могу ошибаться, но по моему это не позволит ввести русские буквы. Тут нужна регулярка.
https://github.com/disbeliever/php_training/blob/master/students/src/StudentValidator.php#L32
> mb_strlen($fieldValue) > 5
Не используется переменная maxLength
https://github.com/disbeliever/php_training/blob/master/students/src/StudentValidator.php#L39
> if (!($fieldValue == "male" || $fieldValue == "female"))
Надо сделать обозначения пола константами в модели студента, Student::GENDER_MALE, а то это магические строки и это плохо (а, они уже даже сделаны).
Для имени и фамилии надо сделать проверку на допустимые символы, как указано в задании.
https://github.com/disbeliever/php_training/blob/master/students/src/Pager.php#L21
> str_replace("_page_",
Эта конструкция с подчеркиванием может встретиться в УРЛ (show_page_list.php), лучше исплоьзовать другие символы-ограничители.
https://github.com/disbeliever/php_training/blob/master/students/src/registerHelpers.php#L15
> md5(rand());
В чем смысл от мд5 здесь? Она не увеличивает число вариантов (около 4 млрд), оно только увеличивает длину токена не добавляя защищенности. Делай честный случайный токен, а не видимость защиты.
Даже если у пользователя стоит CSRF кука, надо ее продлевать - иначе она может умереть.
https://github.com/disbeliever/php_training/blob/master/students/src/views/ViewStudent.php#L21
> />
В HTML не ставится слеш в конце тега.
В пагинации надо выделять текущую страницу. Не показывать пагинацию если всего 1 страница.
Имеется в виду в последний месяц платить не 5000, а сколько осталось.
>>634580
В чем это проявляется? Какая-то ошибка показывается?
>>634607
А кстати, если у вас есть читалка или планшет, можно еще и по дороге что-то полезное читать. Или в обед.
>>634628
> if ($i == $halfLength) {
> echo $result;
Это проще после цикла поставить. Сделать переменную, которая показывает палиндром слово или нет, и после цикла ее выводить. А в цикле ставить ей нужное значение.
>>634679
Можно больше потерять на разработке, исправлении багов и на случаях когда клиент ломается.
>>634689
Большинство данных нужны именно на сервере, так что вряд ли.
> Но тут все равно сложно поддерживать отказоустойчивость/балансировку
А качетвенно написать и поддерживать сложный клиент еще сложнее. Обычно получается что-то глючное и тормозное.
>>634863
Надо больше писать код, тогда не забудешь.
>>634964
Если ты находишься в одном шаге до финиша, надо взять ту точку, добавить в путь и вернуть его. А если нет - надо рекурсивно вызвать ту же функцию поиска для каждой соседней точки (это у тебя сделано), сравнить возвращенные ими пути и выбрать кратчайший (это не сделано) и вернуть его.
>>634989
> Как заставить этот скрипт постоянно слушать определенный порт?
Запускать из консоли.
Если они шлют не одновременно,то можно просто обрабатывать соединения по очереди, если одновременно то нужно городить асинхронный сервер, например на основе фреймворка reactPHP.
> Киньте годной инфы по работе с бинарными данными
В пхп строка содержит любые байты, так что тебе нужны функции работы со строками (strlen, substr и тд). Получить код байта или строку по коду можно функциями ord, chr. Для более сложных случаев есть pack/unpack.
Имеется в виду в последний месяц платить не 5000, а сколько осталось.
>>634580
В чем это проявляется? Какая-то ошибка показывается?
>>634607
А кстати, если у вас есть читалка или планшет, можно еще и по дороге что-то полезное читать. Или в обед.
>>634628
> if ($i == $halfLength) {
> echo $result;
Это проще после цикла поставить. Сделать переменную, которая показывает палиндром слово или нет, и после цикла ее выводить. А в цикле ставить ей нужное значение.
>>634679
Можно больше потерять на разработке, исправлении багов и на случаях когда клиент ломается.
>>634689
Большинство данных нужны именно на сервере, так что вряд ли.
> Но тут все равно сложно поддерживать отказоустойчивость/балансировку
А качетвенно написать и поддерживать сложный клиент еще сложнее. Обычно получается что-то глючное и тормозное.
>>634863
Надо больше писать код, тогда не забудешь.
>>634964
Если ты находишься в одном шаге до финиша, надо взять ту точку, добавить в путь и вернуть его. А если нет - надо рекурсивно вызвать ту же функцию поиска для каждой соседней точки (это у тебя сделано), сравнить возвращенные ими пути и выбрать кратчайший (это не сделано) и вернуть его.
>>634989
> Как заставить этот скрипт постоянно слушать определенный порт?
Запускать из консоли.
Если они шлют не одновременно,то можно просто обрабатывать соединения по очереди, если одновременно то нужно городить асинхронный сервер, например на основе фреймворка reactPHP.
> Киньте годной инфы по работе с бинарными данными
В пхп строка содержит любые байты, так что тебе нужны функции работы со строками (strlen, substr и тд). Получить код байта или строку по коду можно функциями ord, chr. Для более сложных случаев есть pack/unpack.
> CHECK (((rating > 0) AND (rating < 151)))
А больше 151 что нельзя набрать? Алсо, есть же оператор BETWEEN для этого.
Также, добавь ограничение что емайл должен быть уникален. И ограничение на допустимые символы в имени/фамилии.
Алсо, глянь-ка дамп другого анона, может что полезное найдешь https://github.com/disbeliever/php_training/blob/master/students/db.sql
https://github.com/foobar1643/student-list/blob/master/app/Config.php
При отсутсвии ключа в конфиге лучше бросать исключение. И еще, я тут подумал, лучше сделать так: сделать для каждой настройки поле в классе (вместо массива), так будет лучше так как можно задать значения по умолчанию и сразу видно какие есть настройки. Можно сделать эти поля публичными, можно нет.
https://github.com/foobar1643/student-list/blob/master/app/ExceptionHandler.php
Нет логгирования исключений в лог PHP. Как ты о них узнаешь? Используй error_log().
Насчет класса Bootstrap, я думаю, тут лучше обойтись без статических методов: в скрипте инициализации приложения создать объект конфига, загрузить в него конфиг, создать объект bootstrap, и его уже можно передавать в контроллеры:
$config = new ...
$config->loadFromFile...
$container = new Container($config);
Это позволит нам отвязать контроллеры от жестко прописанной завязки на конкретный класс. Плюс, методы bootstrap должны при втором вызове возвращать ранее созданный объект. Ну и назвать его логичнее будет тогда ServiceLocator или Container.
А сейчас у тебя объект конфига создается и перечитвается по много раз. Причем все это жестко заложено и нельзя например подсунуть другие настройки без переписывания кода. Не то чтобы это нам нужно, но код так будет лучше разделен. Ну и тестировать его проще будет, если что.
Соответвенно StudentDataGateway должен создаваться через контейнер.
Что-то у тебя контроллер index большой. Это значит что ты туда засунул код который лучше разместить в другом месте.
https://github.com/foobar1643/student-list/blob/master/app/Controller/ControllerIndex.php#L23
> if($_GET) {
Думаю это условие не нужно.
Насчет генерации URL: может проще сделать просто функцию типа getListUrl($serach, $page, $order) чем долго заполнять свойства объекта? Ну хотя можно и так оставить конечно.
https://github.com/foobar1643/student-list/blob/master/app/Controller/ControllerIndex.php#L42
> $viewSettings["totalPages"] = $pager->get_total_pages();
В данном случае проще во вью передать сам объект пейджера, а не кучу полученных из него переменных.
> if($viewSettings['currentPage'] > $viewSettings['totalPages']) $viewSettings['currentPage'] = 1;
Это лучше перенести в пейджер.
> foreach(array_keys(get_object_vars($viewSettings["students"][$i])) as $key) {
> $viewSettings["students"][$i]->$key = htmlspecialchars($viewSettings["students"][$i]->$key
Вот это очень неправильно. Во-первых, ты заменяешь данные в объектах так что у тебя половину программы там неэкранированные данные, а половину - экранированные. Это ведет к ошибкам, если попытаться использовать такой объект. Во-вторых, экранирование должно быть в шаблоне, а не в контроллере.
> include_once("../templates/header.html");
> include_once("../templates/index.html");
Почему once? Не вижу логики. Также, первый инклюд лучше поместить в шаблон.
https://github.com/foobar1643/student-list/blob/master/app/Controller/ControllerForm.php#L17
> if(!isset($_POST['csrf_field']) && !isset($_COOKIE['token']) && $_POST['csrf_field'] != $_COOKIE['token']) {
Лучше сделать единую функцию проверки csrf токена.
https://github.com/foobar1643/student-list/blob/master/app/Controller/ControllerForm.php#L58
выставление токена надо вынести в функцию. Наверно надо сделать просто отдельный класс, отвечающий за CSRF, или отдельные методы.
https://github.com/foobar1643/student-list/blob/master/app/Controller/ControllerForm.php#L22
> foreach(array_keys(get_object_vars($student))
Должен быть явно заданный список разрешенных для изменения полей, иначе завтра в объект добавят поле isAdmin и можно будет его менять снаружи.
> $errors = $formValidator->validateForm($_POST);
Не лучше ли валидировать модель, а не массив непонятного вида?
https://github.com/foobar1643/student-list/blob/master/app/Database/StudentDataGateway.php#L30
> $result = $query->fetch();
> return $result['id'];
Есть метод чтобы прочитать одно значение, по моему какой-то параметр надо в fetch передать.
> $query->bindValue(':byear_bind', $student->byear, \PDO::PARAM_STR);
Почему строка?
> SE LE CT CO UNT(*) FR OM students WH ERE CON CAT(name, ' ', surname)
Там еще по моему по номеру группы поиск должен работать, посмотри условие задачи. Более того, в другой функции исплоьзуется другой набор полей - результаты могут разойтись.
https://github.com/foobar1643/student-list/blob/master/app/Database/StudentDataGateway.php#L58
> public function select_students($offset, $sorting_pattern, $sorting_type, $search_pattern) {
В функции аргументы без проверки вставляются прямо в SQL запрос, это ведь SQL инъекция получается?
> public function selectToken($token) {
А почему тут не объект возвращается?
> $row = $query->fetchAll(\PDO::FETCH_CLASS, "\App\Model\Student");
> return $row[0];
Есть метод чтобы прочитать одну запись.
https://github.com/foobar1643/student-list/tree/master/app/Model/Helper
Я бы вынес эту папку из Model вверх.
https://github.com/foobar1643/student-list/blob/master/app/Model/Helper/FormHelper.php#L10
В фамилии-имени могут быть символы дефиса, пробела и апострофа. Д`Артаньян например.
> if($data['gender_field'] != "male" && $data['gender_field'] != "female")
Эти строки надо сделать константами в модели студента.
Ошибки надо бы сделать более информативными. Не "неправильно заполнено поле" и не подкрасить красным цветом, а написать например "Имя может содержать не более X символов, вы ввели Y".
> if(!preg_match("/[А-ЯЁA-Z]{1}[а-яёa-z]{1,15}$/u"
> preg_match("/[1][9][0-9]{2}$/",
Нету привязки к началу строки
https://github.com/foobar1643/student-list/blob/master/app/Model/Helper/LinkHelper.php#L34
> $link .= "&search=" . $this->search_pattern;
Не кодируются вставляемые в параметр спецсимволы.
https://github.com/foobar1643/student-list/blob/master/app/Model/Helper/TokenHelper.php#L11
> $source[rand(0, count($source))];
В массиве нет элемента с индексом count(...).
https://github.com/foobar1643/student-list/blob/master/templates/index.html#L24
> for($i = 0; $i < count($viewSettings['students']); $i++): ?>
Нужен foreach
> <?php if($viewSettings['totalPages'] > 1): ?>
Я думаю дописывание везде $viewSettings замусоривает код. Попробуй обойтись без него. Либо как $totalPages либо $this->totalPages.
https://github.com/foobar1643/student-list/blob/master/templates/index.html#L9
Поле поиска наверно надо пометить обязательным к заполнению.
> <?php print
лучше <?=
Добавь также HTML5 валидацию в форму регистрации.
> CHECK (((rating > 0) AND (rating < 151)))
А больше 151 что нельзя набрать? Алсо, есть же оператор BETWEEN для этого.
Также, добавь ограничение что емайл должен быть уникален. И ограничение на допустимые символы в имени/фамилии.
Алсо, глянь-ка дамп другого анона, может что полезное найдешь https://github.com/disbeliever/php_training/blob/master/students/db.sql
https://github.com/foobar1643/student-list/blob/master/app/Config.php
При отсутсвии ключа в конфиге лучше бросать исключение. И еще, я тут подумал, лучше сделать так: сделать для каждой настройки поле в классе (вместо массива), так будет лучше так как можно задать значения по умолчанию и сразу видно какие есть настройки. Можно сделать эти поля публичными, можно нет.
https://github.com/foobar1643/student-list/blob/master/app/ExceptionHandler.php
Нет логгирования исключений в лог PHP. Как ты о них узнаешь? Используй error_log().
Насчет класса Bootstrap, я думаю, тут лучше обойтись без статических методов: в скрипте инициализации приложения создать объект конфига, загрузить в него конфиг, создать объект bootstrap, и его уже можно передавать в контроллеры:
$config = new ...
$config->loadFromFile...
$container = new Container($config);
Это позволит нам отвязать контроллеры от жестко прописанной завязки на конкретный класс. Плюс, методы bootstrap должны при втором вызове возвращать ранее созданный объект. Ну и назвать его логичнее будет тогда ServiceLocator или Container.
А сейчас у тебя объект конфига создается и перечитвается по много раз. Причем все это жестко заложено и нельзя например подсунуть другие настройки без переписывания кода. Не то чтобы это нам нужно, но код так будет лучше разделен. Ну и тестировать его проще будет, если что.
Соответвенно StudentDataGateway должен создаваться через контейнер.
Что-то у тебя контроллер index большой. Это значит что ты туда засунул код который лучше разместить в другом месте.
https://github.com/foobar1643/student-list/blob/master/app/Controller/ControllerIndex.php#L23
> if($_GET) {
Думаю это условие не нужно.
Насчет генерации URL: может проще сделать просто функцию типа getListUrl($serach, $page, $order) чем долго заполнять свойства объекта? Ну хотя можно и так оставить конечно.
https://github.com/foobar1643/student-list/blob/master/app/Controller/ControllerIndex.php#L42
> $viewSettings["totalPages"] = $pager->get_total_pages();
В данном случае проще во вью передать сам объект пейджера, а не кучу полученных из него переменных.
> if($viewSettings['currentPage'] > $viewSettings['totalPages']) $viewSettings['currentPage'] = 1;
Это лучше перенести в пейджер.
> foreach(array_keys(get_object_vars($viewSettings["students"][$i])) as $key) {
> $viewSettings["students"][$i]->$key = htmlspecialchars($viewSettings["students"][$i]->$key
Вот это очень неправильно. Во-первых, ты заменяешь данные в объектах так что у тебя половину программы там неэкранированные данные, а половину - экранированные. Это ведет к ошибкам, если попытаться использовать такой объект. Во-вторых, экранирование должно быть в шаблоне, а не в контроллере.
> include_once("../templates/header.html");
> include_once("../templates/index.html");
Почему once? Не вижу логики. Также, первый инклюд лучше поместить в шаблон.
https://github.com/foobar1643/student-list/blob/master/app/Controller/ControllerForm.php#L17
> if(!isset($_POST['csrf_field']) && !isset($_COOKIE['token']) && $_POST['csrf_field'] != $_COOKIE['token']) {
Лучше сделать единую функцию проверки csrf токена.
https://github.com/foobar1643/student-list/blob/master/app/Controller/ControllerForm.php#L58
выставление токена надо вынести в функцию. Наверно надо сделать просто отдельный класс, отвечающий за CSRF, или отдельные методы.
https://github.com/foobar1643/student-list/blob/master/app/Controller/ControllerForm.php#L22
> foreach(array_keys(get_object_vars($student))
Должен быть явно заданный список разрешенных для изменения полей, иначе завтра в объект добавят поле isAdmin и можно будет его менять снаружи.
> $errors = $formValidator->validateForm($_POST);
Не лучше ли валидировать модель, а не массив непонятного вида?
https://github.com/foobar1643/student-list/blob/master/app/Database/StudentDataGateway.php#L30
> $result = $query->fetch();
> return $result['id'];
Есть метод чтобы прочитать одно значение, по моему какой-то параметр надо в fetch передать.
> $query->bindValue(':byear_bind', $student->byear, \PDO::PARAM_STR);
Почему строка?
> SE LE CT CO UNT(*) FR OM students WH ERE CON CAT(name, ' ', surname)
Там еще по моему по номеру группы поиск должен работать, посмотри условие задачи. Более того, в другой функции исплоьзуется другой набор полей - результаты могут разойтись.
https://github.com/foobar1643/student-list/blob/master/app/Database/StudentDataGateway.php#L58
> public function select_students($offset, $sorting_pattern, $sorting_type, $search_pattern) {
В функции аргументы без проверки вставляются прямо в SQL запрос, это ведь SQL инъекция получается?
> public function selectToken($token) {
А почему тут не объект возвращается?
> $row = $query->fetchAll(\PDO::FETCH_CLASS, "\App\Model\Student");
> return $row[0];
Есть метод чтобы прочитать одну запись.
https://github.com/foobar1643/student-list/tree/master/app/Model/Helper
Я бы вынес эту папку из Model вверх.
https://github.com/foobar1643/student-list/blob/master/app/Model/Helper/FormHelper.php#L10
В фамилии-имени могут быть символы дефиса, пробела и апострофа. Д`Артаньян например.
> if($data['gender_field'] != "male" && $data['gender_field'] != "female")
Эти строки надо сделать константами в модели студента.
Ошибки надо бы сделать более информативными. Не "неправильно заполнено поле" и не подкрасить красным цветом, а написать например "Имя может содержать не более X символов, вы ввели Y".
> if(!preg_match("/[А-ЯЁA-Z]{1}[а-яёa-z]{1,15}$/u"
> preg_match("/[1][9][0-9]{2}$/",
Нету привязки к началу строки
https://github.com/foobar1643/student-list/blob/master/app/Model/Helper/LinkHelper.php#L34
> $link .= "&search=" . $this->search_pattern;
Не кодируются вставляемые в параметр спецсимволы.
https://github.com/foobar1643/student-list/blob/master/app/Model/Helper/TokenHelper.php#L11
> $source[rand(0, count($source))];
В массиве нет элемента с индексом count(...).
https://github.com/foobar1643/student-list/blob/master/templates/index.html#L24
> for($i = 0; $i < count($viewSettings['students']); $i++): ?>
Нужен foreach
> <?php if($viewSettings['totalPages'] > 1): ?>
Я думаю дописывание везде $viewSettings замусоривает код. Попробуй обойтись без него. Либо как $totalPages либо $this->totalPages.
https://github.com/foobar1643/student-list/blob/master/templates/index.html#L9
Поле поиска наверно надо пометить обязательным к заполнению.
> <?php print
лучше <?=
Добавь также HTML5 валидацию в форму регистрации.
Наверно можно, изучи строковые функции mysql. Но вообще это неправильно так хранить данные и противоречит принципам нормализации. Лучше сделать нормально.
>>635131
Slim/Silex, Yii2, Symfony 2. Это от простых к сложным.
>>635259
Названия переменных никуда не годятся. Названия должны обозначать то, что в них хранится, а не представлять бессмысленный набор букв. Пееремнные называются с маленькой буквы. Названия вроде "массив", "строка" и названия из 1-2 букв тоже не годятся. Хорошие названия: $words, $sentences, $firstLetter и так далее. Пока читать код очень тяжело, так как ничего не понятно.
Имена функций начинаются с глагола: сделайЧтоТо(). Названия типа commas не годятся.
Для удаления пробелов вокруг запятых лучше применить регулярку. Цикл там не нужен.
> $i = 0;
> foreach($part as $num){
в таких случаях лучше писать foreach ($parts as $key => $part)
> $last = mb_substr($string, 1, $nums);
можно просто mb_substr($string, 1);
В общем, код надо переделывать.
> $result = mb_substr($result, 0, -3);
Откуда магическое число -3? Это что-то странное.
>>635296
> Только в последний месяц он заплатил 5262.
У него нет столько денег.
>>635306
Оп не очень в них рабирается и не считает это принципиально важным вопросом.
>>635616
Ответил где-то выше, смотри по ссылкам с поста.
>>635746
>>635877
Вот какой у меня получился алгоритм решения:
- прибавляем проценты и комиссию к остатку долга (!не вычитаем ничего пока!)
- если остаток маленький, выплачиваем сколько осталось и уходим
- иначе платим 5000
«Платим» здесь значит уменьшаем долг и увеличиваем общую сумму выплаченного.
Наверно можно, изучи строковые функции mysql. Но вообще это неправильно так хранить данные и противоречит принципам нормализации. Лучше сделать нормально.
>>635131
Slim/Silex, Yii2, Symfony 2. Это от простых к сложным.
>>635259
Названия переменных никуда не годятся. Названия должны обозначать то, что в них хранится, а не представлять бессмысленный набор букв. Пееремнные называются с маленькой буквы. Названия вроде "массив", "строка" и названия из 1-2 букв тоже не годятся. Хорошие названия: $words, $sentences, $firstLetter и так далее. Пока читать код очень тяжело, так как ничего не понятно.
Имена функций начинаются с глагола: сделайЧтоТо(). Названия типа commas не годятся.
Для удаления пробелов вокруг запятых лучше применить регулярку. Цикл там не нужен.
> $i = 0;
> foreach($part as $num){
в таких случаях лучше писать foreach ($parts as $key => $part)
> $last = mb_substr($string, 1, $nums);
можно просто mb_substr($string, 1);
В общем, код надо переделывать.
> $result = mb_substr($result, 0, -3);
Откуда магическое число -3? Это что-то странное.
>>635296
> Только в последний месяц он заплатил 5262.
У него нет столько денег.
>>635306
Оп не очень в них рабирается и не считает это принципиально важным вопросом.
>>635616
Ответил где-то выше, смотри по ссылкам с поста.
>>635746
>>635877
Вот какой у меня получился алгоритм решения:
- прибавляем проценты и комиссию к остатку долга (!не вычитаем ничего пока!)
- если остаток маленький, выплачиваем сколько осталось и уходим
- иначе платим 5000
«Платим» здесь значит уменьшаем долг и увеличиваем общую сумму выплаченного.
Названия переменных должны быть осмысленные, а не абстрактные.
Выражение ($creditBalance * $percent) + $servicePayment повторяется 3 раза, попробуй убрать повторы и сократить код.
>>635980
Саблайм не может есть столько же ресурсов сколько Атом, так как он на Си/питоне, а Атом на HTML. Но конечно если много плагинов поставить, все может поменяться. Попробуй редактор без плагинов.
>>635588
В PHP есть и асинхроннсть (reactPHP), и многопоточность.
>>636102
Проверку баланса надо делать не в начале месяца а после прибавления процентов и комиссии.
Составной индекс работает как обычный, просто он хранит отсортированные значения из нескольких колонок. И этим определяется где он может помочь, а где нет. Выглядит он примерно так:
a | b
-----------
Андрей | 1
Андрей | 5
Иван | 1
Иван | 1
Иван | 2
Иван | 20
Юрий | 7
> SELECT id, lft, root, level FROM category WHERE level IN (1,2) ORDER BY root, lft;
По видимому из-за IN здесь используется только начало индекса, чтобы найти все записи с level = 1 или 2. Конец индекса не используется для сортировки, вместо этого записи выбираются и сортируются в памяти.
Это можно увидеть по этой записи:
> key: ix_level_root_lft
> key_len: 4
Видишь, из индекса используются только первые 4 байта, то есть одно поле типа int. Если бы он использовался весь, там бы было большее число. Проверь, заменив IN на WHERE level = 1.
> Но зачем? Разве в индексе они не хранятся в отсортированном виде? Судя по key_len = 4, вторая и третья часть индекса вообще не используется.
Видимо из-за IN. Ведь записи отсортированы по 2 и 3 полю только там где первое поле одинаково, смотри рисунок выше. Если мы сделаем выборку WHERE a IN ('Иван', 'Юрий'), значения колонки b не отсортированы. А если сделать WHERE a = 'Иван' ORDER BY b то можно использовать индекс целиком.
> Разве в индексе они не хранятся в отсортированном виде?
В индексе они отсортированы по ORDER BY level, root, lft.
> наверное таки лучше between
Не должно помочь.
> Хотя судя по времени выполнения запроса, очень даже используется: с индексом только на (level) запрос 0.20с, индекс (level, root, lft) занимает 0.06с.
Странно, маленький индекс по идее должен быть быстрее. Может это из-за того что записи частично отсортированы как надо в большом индексе и сортировка проходит быстрее? Ты SQL_NO_CACHE не забыл?
>>636122
Открой сайт вакансий.
>>636172
> Совсем хорошо было бы, если бы мне вообще не нужна была сортировка в запросе.
Да, хорошо бы переписать запрос. Ну например зачем тебе могут понадобиться данные из всех деревьев сразу? Да еще и миллионы записей. Не странно ли это?
Ну и еще есть такая хитрость. Можно ввести поле isLevelBelow3 куда записать 1 для записей где level < 3 и сделать индекс по (isLevelBelow3, root, lft). Но не уверен что стоит с этим заморачиваться.
> Или прямо в php отсортировать массив? Черт его знает.
Я бы сортировал в SQL. Оно ведь закеширует запрос, если тебя беспокоит производительнсоть. И если таблица нечасто меняется.
>>636285
Решай параллельно c php. Или попроси подсказку по HTML.
>>636292
Написать HTML и CSS код.
>>636306
Я же вроде что-то выше подсказал. Если непонятно, задавай уточняющие вопросы.
Составной индекс работает как обычный, просто он хранит отсортированные значения из нескольких колонок. И этим определяется где он может помочь, а где нет. Выглядит он примерно так:
a | b
-----------
Андрей | 1
Андрей | 5
Иван | 1
Иван | 1
Иван | 2
Иван | 20
Юрий | 7
> SELECT id, lft, root, level FROM category WHERE level IN (1,2) ORDER BY root, lft;
По видимому из-за IN здесь используется только начало индекса, чтобы найти все записи с level = 1 или 2. Конец индекса не используется для сортировки, вместо этого записи выбираются и сортируются в памяти.
Это можно увидеть по этой записи:
> key: ix_level_root_lft
> key_len: 4
Видишь, из индекса используются только первые 4 байта, то есть одно поле типа int. Если бы он использовался весь, там бы было большее число. Проверь, заменив IN на WHERE level = 1.
> Но зачем? Разве в индексе они не хранятся в отсортированном виде? Судя по key_len = 4, вторая и третья часть индекса вообще не используется.
Видимо из-за IN. Ведь записи отсортированы по 2 и 3 полю только там где первое поле одинаково, смотри рисунок выше. Если мы сделаем выборку WHERE a IN ('Иван', 'Юрий'), значения колонки b не отсортированы. А если сделать WHERE a = 'Иван' ORDER BY b то можно использовать индекс целиком.
> Разве в индексе они не хранятся в отсортированном виде?
В индексе они отсортированы по ORDER BY level, root, lft.
> наверное таки лучше between
Не должно помочь.
> Хотя судя по времени выполнения запроса, очень даже используется: с индексом только на (level) запрос 0.20с, индекс (level, root, lft) занимает 0.06с.
Странно, маленький индекс по идее должен быть быстрее. Может это из-за того что записи частично отсортированы как надо в большом индексе и сортировка проходит быстрее? Ты SQL_NO_CACHE не забыл?
>>636122
Открой сайт вакансий.
>>636172
> Совсем хорошо было бы, если бы мне вообще не нужна была сортировка в запросе.
Да, хорошо бы переписать запрос. Ну например зачем тебе могут понадобиться данные из всех деревьев сразу? Да еще и миллионы записей. Не странно ли это?
Ну и еще есть такая хитрость. Можно ввести поле isLevelBelow3 куда записать 1 для записей где level < 3 и сделать индекс по (isLevelBelow3, root, lft). Но не уверен что стоит с этим заморачиваться.
> Или прямо в php отсортировать массив? Черт его знает.
Я бы сортировал в SQL. Оно ведь закеширует запрос, если тебя беспокоит производительнсоть. И если таблица нечасто меняется.
>>636285
Решай параллельно c php. Или попроси подсказку по HTML.
>>636292
Написать HTML и CSS код.
>>636306
Я же вроде что-то выше подсказал. Если непонятно, задавай уточняющие вопросы.
-----------
Попробуй переписать код внутри цикла примерно так:
- прибавляем проценты и комиссию к остатку долга (!не вычитаем ничего пока!)
- если остаток маленький, выплачиваем сколько осталось и уходим
- иначе платим 5000
«Платим» здесь значит уменьшаем долг и увеличиваем общую сумму выплаченного.
------------
Ответы на старые посты с 28 по 31 января наверно буду постить сюда, а в новом треде ставить ссылку. В общем, заглядывайте сюда периодически, но больше здесь ничего не пишите.
Я думаю, сегодня-завтра проверю оставшиеся посты и закроем этот тред окончательно.
Здесь ничего не пишите, идите в новый тред >>639138 (OP)
Если вас забыли, пропустили - напомните о себе в новом треде.
> Не знаю почему у меня подвисает ввод во время обновления треда,
> вроде никакой явной блокировки не нашлось
Яваскрипт однопоточный и блокирует интерфейс браузера на время работы. Возможно дело в этом. Что подвисает - можно посмотреть профайлером в Хроме на вкладке Timeline и Profiles. Можешь попробовать. Включи автообновление, запись и набирай текст. После первого же подвисания можешь оставновить запись.
> Вот я хочу отследить, как на сосаче происходит обновление треда.
Ставишь точку останова на обработчик кнопки и далее смотришь и выполняешь код. Кроме перехода по шагам, там есть еще функция "выполнить до текущей строки"
> Так все-таки, какая польза от отладчика кроме возможности остановить исполнение
в определенный момент (а этот момент еще надо вычислить) и посмотреть значение переменных?
В этом и польза что можно посмотреть и например увидеть что в переменной что-то не то.
> Все движки ставят неявную блокировку на чтение. То есть пока запись не будет
прочитана, другие клиенты не имеют права на ее изменение.
Архитектура MVCC как раз позволяет избежать необходимости блокировать так как там не меняются старые записи, а только добавляются новые, значит блокировать незачем.
> В innodb блокировка на уровне строк благодаря мультиверсионности.
MVCC позволяет работать без блокировок, блокировки там добавлены ради соблюдения требований к транзакциям. А вот MyISAM требует блокировок (а транзакции вообще не поддерживает).
> Чтобы объединить несколько
запросов в транзакцию в myisam используется явная блокировка таблиц LOCK
> TABLE.
И это сомнительное решение так как все другие процессы теперь ждут освобождения блокировки.
> Это значит что выбираться будут только данные,
актуальные на момент начала данной транзакции. Если параллельная транзакция
> закоммитила изменения, например добавила новые строки, то в рамках текущей
> транзакции мы никогда не увидим эти новые строки.
Так и должно быть. Пока изменения не закоммичены, их нет.
> От потерянного обновления innodb защищен благодаря мультиверсинности.
Не уверен, что правильно. Мультиверсионность нужна только для того чтобы реализовать обновление данных без блокировок (так как вместо обновления старых данных мы фактически дописываем строку с новой версией данных). А с блокировками борются так как при параллеьной работе они снижают производительность, потоки проставивают в ожидании освобождения блокировок.
То есть все требования транзакций можно реализовать и без мультиверсионности, даже наверно в MyISAM, только работать будет медленнее (ну например каждая транзакция записывает измненения в отдельный файл, потом при коммите мы блокируем таблицу и переносим в нее эти изменения - но блокировка убьет производительность при параллельной работе с базой).
> Будет наложена next-key блокировка на все ключи с id > 100, в том числе на те,
которые еще не существуют. Ну то есть если у нас 110 записей в базе, и селект
> вернет соответственно 10, то другие транзакции не могут вставить 111 запись.
> Короче какое-то мутное место.
Нет. Там блокируется диапазон в индексе. Вот допустим у нас есть индекс по id и там идут записи (в индексе они отсортированы):
10
20
90
105
130
Допустим мы делаем запрос SELECT cols FROM tbl WHERE id > 100 FOR UPDATE;
innodb пройдется по индексу, найдет записи > 100 (105 и 130) и поставит на них блокировку. А также, на промежутки рядом с ними, то есть на промежуток между 90 и 105, между 105 и 130 и между 130 и концом индекса. Таким образом, другие транзакции при потытке вставить запись с id > 90 попадут в эти промежутки, будут заблокированы и будут ждать освобождения этой блокировки.
Таким образом избегается фантомное чтение.
То есть суть в том что она блокирует не только записи в индексе но и промежутки перед и после них.
ЗАметь что это работает только про использовании индекса и только на некоторых уровнях изоляции транзакций.
> Потому что там нет мультиверсионности, при апдейте не создается новая версия, а
> идет перезапись. Короче, без блокировки будет потерянное обновление. Или даже
> хуже: если две транзакции попытаются одновременно писать в одно место файла с
> таблицей, то получится каша, часть символов из одной транзакции, часть из
другой.
Верно.
> При обновлении строки не перезаписываются старые данные, а добавляется в конец
> файла с таблицей новая строка. Идет запись в разные места файла.
Верно
> Затем обе транзакции коммитятся, первая запишет 110, а вторая 120, хотя мы
> ожидали 130. Похоже на потерянное обновление.
Верно.
> LOCK IN SHARE MODE. Если нужно блокировать и на чтение, то SELECT ... FOR UPDATE.
Верно.
> Все движки ставят неявную блокировку на чтение. То есть пока запись не будет
прочитана, другие клиенты не имеют права на ее изменение.
Архитектура MVCC как раз позволяет избежать необходимости блокировать так как там не меняются старые записи, а только добавляются новые, значит блокировать незачем.
> В innodb блокировка на уровне строк благодаря мультиверсионности.
MVCC позволяет работать без блокировок, блокировки там добавлены ради соблюдения требований к транзакциям. А вот MyISAM требует блокировок (а транзакции вообще не поддерживает).
> Чтобы объединить несколько
запросов в транзакцию в myisam используется явная блокировка таблиц LOCK
> TABLE.
И это сомнительное решение так как все другие процессы теперь ждут освобождения блокировки.
> Это значит что выбираться будут только данные,
актуальные на момент начала данной транзакции. Если параллельная транзакция
> закоммитила изменения, например добавила новые строки, то в рамках текущей
> транзакции мы никогда не увидим эти новые строки.
Так и должно быть. Пока изменения не закоммичены, их нет.
> От потерянного обновления innodb защищен благодаря мультиверсинности.
Не уверен, что правильно. Мультиверсионность нужна только для того чтобы реализовать обновление данных без блокировок (так как вместо обновления старых данных мы фактически дописываем строку с новой версией данных). А с блокировками борются так как при параллеьной работе они снижают производительность, потоки проставивают в ожидании освобождения блокировок.
То есть все требования транзакций можно реализовать и без мультиверсионности, даже наверно в MyISAM, только работать будет медленнее (ну например каждая транзакция записывает измненения в отдельный файл, потом при коммите мы блокируем таблицу и переносим в нее эти изменения - но блокировка убьет производительность при параллельной работе с базой).
> Будет наложена next-key блокировка на все ключи с id > 100, в том числе на те,
которые еще не существуют. Ну то есть если у нас 110 записей в базе, и селект
> вернет соответственно 10, то другие транзакции не могут вставить 111 запись.
> Короче какое-то мутное место.
Нет. Там блокируется диапазон в индексе. Вот допустим у нас есть индекс по id и там идут записи (в индексе они отсортированы):
10
20
90
105
130
Допустим мы делаем запрос SELECT cols FROM tbl WHERE id > 100 FOR UPDATE;
innodb пройдется по индексу, найдет записи > 100 (105 и 130) и поставит на них блокировку. А также, на промежутки рядом с ними, то есть на промежуток между 90 и 105, между 105 и 130 и между 130 и концом индекса. Таким образом, другие транзакции при потытке вставить запись с id > 90 попадут в эти промежутки, будут заблокированы и будут ждать освобождения этой блокировки.
Таким образом избегается фантомное чтение.
То есть суть в том что она блокирует не только записи в индексе но и промежутки перед и после них.
ЗАметь что это работает только про использовании индекса и только на некоторых уровнях изоляции транзакций.
> Потому что там нет мультиверсионности, при апдейте не создается новая версия, а
> идет перезапись. Короче, без блокировки будет потерянное обновление. Или даже
> хуже: если две транзакции попытаются одновременно писать в одно место файла с
> таблицей, то получится каша, часть символов из одной транзакции, часть из
другой.
Верно.
> При обновлении строки не перезаписываются старые данные, а добавляется в конец
> файла с таблицей новая строка. Идет запись в разные места файла.
Верно
> Затем обе транзакции коммитятся, первая запишет 110, а вторая 120, хотя мы
> ожидали 130. Похоже на потерянное обновление.
Верно.
> LOCK IN SHARE MODE. Если нужно блокировать и на чтение, то SELECT ... FOR UPDATE.
Верно.
>Оп по моему разжевал уже дальше некуда.
Однако всё равно натыкаются на разные преграды и запутываются. Подсказки для того, чтобы им распутаться и новым взглядом окинуть задачу.
Грамотные программисты используют очень активно. Но грамотных мало, потому и дурная слава за языком.
> $regexp[0] = '/[ ][,][ ]/u';
> $regexp[1] = '/[ ][!][ ]/u';
Вместо кучи выражений для замены надо сделать одно, работающее со всеми знаками препинания, а в выражении замены использовать что-то вроде $1.
> $sentence = mb_strtoupper(mb_substr($sentence, 0, 1)).mb_substr($sentence, 1, mb_strlen($sentence));
Это длинное выражение лучше вынести в отдельную функцию с понятными именем
>>637452
Можно написать так: (точка или запятая или вопрос или другой знак), за ним буквы. Чтобы написать "один из указанных знаков", можно использовать квадратные скобки.
>>637535
> А дальше я вот не знаю, как можно заставить работать вот такое нечто:
> if ($lastThousandNum == 2|3|4) {
Вообще плохо, это надо было раньше изучать. Так как ты написал, написать нельзя, но есть такие варианты:
если число == 2 ИЛИ число == 3 ИЛИ число == 4
если число больше/равно 2 И меньше/равно 4
если число содержится в массиве [2, 3, 4]
И не путай операторы: | это битовое ИЛИ (не то что нужно), || это логическое ИЛИ (то что нужно)
> либо сделать массив $menSpelling, который будет подставляться в функцию вместо $femaleSpelling - и менять то, что и так должно выходить правильно
Можно сделать так, второй массив, и выбирать в зависимости от пола.
>>637551
На них каждый второй запинается. Покажи код, попроси подсказку, задай уточняющий вопрос. В треде есть эксперты по этим задачам.
>>637566
Если ты запускаешь код в консоли - через функцию gets(). Если в браузере - через HTML формы и инпуты. На ideone есть поле для ввода данных, подаваемых на вход и нужно использовать gets().
>>637709
Оправданно. Во-первых, научишься Апач настраивать, во-вторых, не придется разбираться в багах и особенностях сборок. Пасты есть в ОП посте.
>>637715
Стоит. А то люди ставят сборки, а потом приходят в тред жаловаться, что у них что-то не работает.
>>637721
Со сборками точно также могут проблемы, и решать их еще сложнее так как надо разобраться не только в особенностях Апача, но и сборки.
>>637764
Погугли про связи в БД, один к одному, многие ко многим. Не зная этого нельзя проектировать базы данных.
> либо сделать массив $menSpelling, который будет подставляться в функцию вместо $femaleSpelling - и менять то, что и так должно выходить правильно
Можно сделать так, второй массив, и выбирать в зависимости от пола.
>>637551
На них каждый второй запинается. Покажи код, попроси подсказку, задай уточняющий вопрос. В треде есть эксперты по этим задачам.
>>637566
Если ты запускаешь код в консоли - через функцию gets(). Если в браузере - через HTML формы и инпуты. На ideone есть поле для ввода данных, подаваемых на вход и нужно использовать gets().
>>637709
Оправданно. Во-первых, научишься Апач настраивать, во-вторых, не придется разбираться в багах и особенностях сборок. Пасты есть в ОП посте.
>>637715
Стоит. А то люди ставят сборки, а потом приходят в тред жаловаться, что у них что-то не работает.
>>637721
Со сборками точно также могут проблемы, и решать их еще сложнее так как надо разобраться не только в особенностях Апача, но и сборки.
>>637764
Погугли про связи в БД, один к одному, многие ко многим. Не зная этого нельзя проектировать базы данных.
Это баг. Советую для начала взять developer tools (Ctrl + Shift + I) в Хроме или ФФ и изучить ситуацию. Я подозреваю, это связано с тем что верстку там поменяли, а js код определения позиции остался старый. Возможно из-за box-sizing: border-box.
Думаю было бы полезно найти, исправить баг и отправить патч. Хотя стоит глянуть сайт проекта - может кто-то уже нашел и исправил баг.
>>638039
Там 32 символа, замучаешься угадывать. Посчитай сколько возможных вариантов кода может быть и сколько надо перебрать чтобы угадать.
> Если ты делаешь какую-то очень защищенную систему, можешь при логине записывать айпи пользователя и айди сессии, потом на каждой странице проверять
Лучше использовать https - это само по себе даст больше надежности.
Привязываться к айпи может быть чревато проблемами, да и через тор работать не будет.
>>638055
Запости код, напиши что именно ты не можешь понять?
>>638064
Что такое global? Глобальная переменная? Нет.
>>638253
Не, у тебя там зачем-то в коде заложено число 2868 - откуда оно? И что ты будешь делать если надо для другой суммы посчиать? Не годится.
Да и кода много, надо упростить, например выражение ($creditBalance * $percent ) + $servicePayment зачем-то повторяется 2 раза.
Это баг. Советую для начала взять developer tools (Ctrl + Shift + I) в Хроме или ФФ и изучить ситуацию. Я подозреваю, это связано с тем что верстку там поменяли, а js код определения позиции остался старый. Возможно из-за box-sizing: border-box.
Думаю было бы полезно найти, исправить баг и отправить патч. Хотя стоит глянуть сайт проекта - может кто-то уже нашел и исправил баг.
>>638039
Там 32 символа, замучаешься угадывать. Посчитай сколько возможных вариантов кода может быть и сколько надо перебрать чтобы угадать.
> Если ты делаешь какую-то очень защищенную систему, можешь при логине записывать айпи пользователя и айди сессии, потом на каждой странице проверять
Лучше использовать https - это само по себе даст больше надежности.
Привязываться к айпи может быть чревато проблемами, да и через тор работать не будет.
>>638055
Запости код, напиши что именно ты не можешь понять?
>>638064
Что такое global? Глобальная переменная? Нет.
>>638253
Не, у тебя там зачем-то в коде заложено число 2868 - откуда оно? И что ты будешь делать если надо для другой суммы посчиать? Не годится.
Да и кода много, надо упростить, например выражение ($creditBalance * $percent ) + $servicePayment зачем-то повторяется 2 раза.
> throw new Error("Аргумент "+ arguments+" не является элементом сети");
Подставлять объект в строку не стоит, так как если его не удастся преобразовать к строке, то будет ошибка. Лучше указывать номер аргумента.
> if (this._elements.getPowerProduction) {
Что-то мне не очень нравится, что функция может быть, может не быть. Не проще ли в базовом классе сделать эту функцию и возвращать ей ноль? Ну или если у тебя все завязано на классы Generator/Consumer то сделать проверку что объект является их наследником. Хотя мне кажется проще функции сделать в базовом классе.
>>638457
Пруфы?
>>638469
> Его нужно применять чтобы классы как бы не пересекались с друг другом, а как бы первый класс передавался на вход другого,
Это называется зависимости - одному объекту для работы нужен другой. Вполне обычная ситуация. Идея DI в том что объект не должен сам искать или создавать свои зависимости, а в том что ему передает их снаружи тот кто его создал. Обязательные зависимости через конструктор, необязательные через метод-сеттер (необязательные - это например объект-логгер - работать можно и без него, только логи никуда не пишутся).
> Точнее сказать, не могу понять как применить это к конкретно моей проблеме со статическими методами
Отказаться от статических методов.
> В этом классе делать метод setRegistrationHelper(RegistrationHelper $reghelper) и вызывать его далее:
> Мне все равно придется писать где-то в начале $reghelper = new RegistrationHelper()
Верно, где-то нам все равно надо создать объекты. Тут есть такие варианты:
1) создавать их в скрипте инициализации, bootstrap или init, если их немного
2) сделать контейнер или сервис локатор, который умеет их создавать. Создать контейнер в скрипте инициализации и передавать в контроллер. А контролллер из контейнера получает нужные ему объекты-сервисы. Только не злоупотребляй этим - не надо контейнер передавать везде, иначе мы опять получаем что неясно от чего зависит класс.
> Я не хочу так делать, я хочу чтобы я вызвал одну единственную функцию и все было готово как я это сделал здесь
Тогда тебе нужен контейрнер, который умеет сам создавать нужные объекты.
> Это вообще входит в рамки задачи?
Конечно, полезно разобраться. Ты должен в своей программе понимать каждую строчку, почему и зачем она так написана.
> Неужели я обречен всегда пользоваться инъекциями и забыть про статические методы?
Неужели ты обречен писать хороший код, а не спутанную лапшу?
> Зачем их тогда вообще сделали,
Сделали чтобы отвязать классы друг от друга. Чтобы в классе не были жестко прописаны его зависимости. Чтобы было можно их подменять, чтобы было удобнее тестировать по отдельности, чтобы код был лучше.
Смотри как статические методы отравляют код. Если тебе в RegisterHelper нужен например маппер, тебе придется его создавать там внутри. А тому нужен ПДО - надо опять же его создавтаь. Вот так все получается намертво спутано - мы не можем взять и вместо PDO передать какой-нибудь объект который например логгирует все походящие через него запросы.
Да и нелогично это, класс должен выполнять свою задачу, а не думать о том как создать или где получить объекты которые ему нужны.
Я же писал в уроке, DI позволяет нам разделить классы, это как устройства с разъемами, которые соединены проводами и которые можно переподключать. А статические методы это когда все намертво припаяно друг у другу.
> будут ли от них избавляться(или уже избавились)?
Нет. Избавляться мы будем от засилия статических методов и спутанного кода.
> Извиняюсь что так много вопросов, просто я совсем не понимаю это.
Задавай еще. Важно разобраться.
>>638474
> Здесь мне тоже нужно будет пользоваться инъекциями зависимостей?
> public function addStudent(Student $student, Container $container) {
Это какая-то странная зависимостей. Ты пока не понял принцип. Какой смысл в addStudent передавать какие-то лишние объекты? Контейнер всегда один и тот же, значит незачем его передавать каждый раз, можно один раз его передать при создании объекта.
Вторая ошибка - ты передаешь слишком много. Вот я смотрю на этот метод и не понимаю: что я должен передать ему? То есть я вижу, что контейнер, а что в нем должно быть? Непонятно. Надо указывать конкретные сервисы которые нужны, а не передавать контейнер непонятно с чем.
То есть должно быть ясно видно, какие зависимости есть у класса.
То есть давай я попробую повторить принципы хорошего кода:
- класс не должен сам создавать или искать нужные ему объекты (зависимости) - создавать их это задача того, кто создает объект
- класс должен позволять подсунуть ему объект с другими настройками. например если классу нужен объект PDO, мы должн иметь возможность задать для него произвольные настройки, или вообще сделать наследника этого класса и передать объект-наследник PDO вместо PDO
- должно быть четко обозначено, какие есть зависимости у класса - нельзя указывать контейнер
- зависимости надо разделять на обязетельные и необязательные (без которых класс может работать)
- должно быть сделано так, что нельзя создать неработоспособный объект. Например, если объекту для работы нужен PDO, то надо передавать его через конструктор, чтобы нельзя было создать объект не передав ему все нужное для работы. То есть если я смог создать объект - он должен работать
Часть этих принципов не относится к контроллеру. Например, в контроллер можно передавать конейтнер и не обозначать четко его зависимости (хотя есть и те кто считает что это плохо).
> throw new Error("Аргумент "+ arguments+" не является элементом сети");
Подставлять объект в строку не стоит, так как если его не удастся преобразовать к строке, то будет ошибка. Лучше указывать номер аргумента.
> if (this._elements.getPowerProduction) {
Что-то мне не очень нравится, что функция может быть, может не быть. Не проще ли в базовом классе сделать эту функцию и возвращать ей ноль? Ну или если у тебя все завязано на классы Generator/Consumer то сделать проверку что объект является их наследником. Хотя мне кажется проще функции сделать в базовом классе.
>>638457
Пруфы?
>>638469
> Его нужно применять чтобы классы как бы не пересекались с друг другом, а как бы первый класс передавался на вход другого,
Это называется зависимости - одному объекту для работы нужен другой. Вполне обычная ситуация. Идея DI в том что объект не должен сам искать или создавать свои зависимости, а в том что ему передает их снаружи тот кто его создал. Обязательные зависимости через конструктор, необязательные через метод-сеттер (необязательные - это например объект-логгер - работать можно и без него, только логи никуда не пишутся).
> Точнее сказать, не могу понять как применить это к конкретно моей проблеме со статическими методами
Отказаться от статических методов.
> В этом классе делать метод setRegistrationHelper(RegistrationHelper $reghelper) и вызывать его далее:
> Мне все равно придется писать где-то в начале $reghelper = new RegistrationHelper()
Верно, где-то нам все равно надо создать объекты. Тут есть такие варианты:
1) создавать их в скрипте инициализации, bootstrap или init, если их немного
2) сделать контейнер или сервис локатор, который умеет их создавать. Создать контейнер в скрипте инициализации и передавать в контроллер. А контролллер из контейнера получает нужные ему объекты-сервисы. Только не злоупотребляй этим - не надо контейнер передавать везде, иначе мы опять получаем что неясно от чего зависит класс.
> Я не хочу так делать, я хочу чтобы я вызвал одну единственную функцию и все было готово как я это сделал здесь
Тогда тебе нужен контейрнер, который умеет сам создавать нужные объекты.
> Это вообще входит в рамки задачи?
Конечно, полезно разобраться. Ты должен в своей программе понимать каждую строчку, почему и зачем она так написана.
> Неужели я обречен всегда пользоваться инъекциями и забыть про статические методы?
Неужели ты обречен писать хороший код, а не спутанную лапшу?
> Зачем их тогда вообще сделали,
Сделали чтобы отвязать классы друг от друга. Чтобы в классе не были жестко прописаны его зависимости. Чтобы было можно их подменять, чтобы было удобнее тестировать по отдельности, чтобы код был лучше.
Смотри как статические методы отравляют код. Если тебе в RegisterHelper нужен например маппер, тебе придется его создавать там внутри. А тому нужен ПДО - надо опять же его создавтаь. Вот так все получается намертво спутано - мы не можем взять и вместо PDO передать какой-нибудь объект который например логгирует все походящие через него запросы.
Да и нелогично это, класс должен выполнять свою задачу, а не думать о том как создать или где получить объекты которые ему нужны.
Я же писал в уроке, DI позволяет нам разделить классы, это как устройства с разъемами, которые соединены проводами и которые можно переподключать. А статические методы это когда все намертво припаяно друг у другу.
> будут ли от них избавляться(или уже избавились)?
Нет. Избавляться мы будем от засилия статических методов и спутанного кода.
> Извиняюсь что так много вопросов, просто я совсем не понимаю это.
Задавай еще. Важно разобраться.
>>638474
> Здесь мне тоже нужно будет пользоваться инъекциями зависимостей?
> public function addStudent(Student $student, Container $container) {
Это какая-то странная зависимостей. Ты пока не понял принцип. Какой смысл в addStudent передавать какие-то лишние объекты? Контейнер всегда один и тот же, значит незачем его передавать каждый раз, можно один раз его передать при создании объекта.
Вторая ошибка - ты передаешь слишком много. Вот я смотрю на этот метод и не понимаю: что я должен передать ему? То есть я вижу, что контейнер, а что в нем должно быть? Непонятно. Надо указывать конкретные сервисы которые нужны, а не передавать контейнер непонятно с чем.
То есть должно быть ясно видно, какие зависимости есть у класса.
То есть давай я попробую повторить принципы хорошего кода:
- класс не должен сам создавать или искать нужные ему объекты (зависимости) - создавать их это задача того, кто создает объект
- класс должен позволять подсунуть ему объект с другими настройками. например если классу нужен объект PDO, мы должн иметь возможность задать для него произвольные настройки, или вообще сделать наследника этого класса и передать объект-наследник PDO вместо PDO
- должно быть четко обозначено, какие есть зависимости у класса - нельзя указывать контейнер
- зависимости надо разделять на обязетельные и необязательные (без которых класс может работать)
- должно быть сделано так, что нельзя создать неработоспособный объект. Например, если объекту для работы нужен PDO, то надо передавать его через конструктор, чтобы нельзя было создать объект не передав ему все нужное для работы. То есть если я смог создать объект - он должен работать
Часть этих принципов не относится к контроллеру. Например, в контроллер можно передавать конейтнер и не обозначать четко его зависимости (хотя есть и те кто считает что это плохо).
Поставь echo который выводит ситуацию на каждом месяце, чему равны все переменные, и попробуй разобраться.
>>638647
Хорошо, а теперь убери еще строчки которые повтряются 2 раза:
> $paymentTotal = $paymentTotal + $creditBalance;
> $creditBalance = $creditBalance - $creditBalance;
>>638700
Решено верно. Но можно еще улучшить код, если проверку на то что набран миллион поставить в шапку цикла (внутрь круглых скобок), а вывод информации поставить после цикла.
>>638849
Норм, хотя проверку на достижение миллиона можно бы поставить в шапку цикла.
>>639092
Нет, не одно и то же. Видимо, плоховато знаешь. Куки - данные, которые хранятся в браузере пользователя. Сессия- данные, которые хранятся на сервере, а идентификатор сессии хранится у пользователя в куке.
>>639114
> PHP Notice: Undefined variable: paymentTotal in /home/LwUcTo/prog.php on line 9
> PHP Notice: Undefined variable: paymentTotal in /home/LwUcTo/prog.php on line 9
Ошибка из-за обращения к еще не существующей переменной. Надо исправить.
Выражение ($credit * $percent) + $commission повторяется 3 раза, надо бы избавиться от повтора.
Если поставить сумму в 1000 р то считает неправильно - во втором банке должно быть 2030 р, а не 2940: http://ideone.com/kzHxKh
Пока не годится.
Поставь echo который выводит ситуацию на каждом месяце, чему равны все переменные, и попробуй разобраться.
>>638647
Хорошо, а теперь убери еще строчки которые повтряются 2 раза:
> $paymentTotal = $paymentTotal + $creditBalance;
> $creditBalance = $creditBalance - $creditBalance;
>>638700
Решено верно. Но можно еще улучшить код, если проверку на то что набран миллион поставить в шапку цикла (внутрь круглых скобок), а вывод информации поставить после цикла.
>>638849
Норм, хотя проверку на достижение миллиона можно бы поставить в шапку цикла.
>>639092
Нет, не одно и то же. Видимо, плоховато знаешь. Куки - данные, которые хранятся в браузере пользователя. Сессия- данные, которые хранятся на сервере, а идентификатор сессии хранится у пользователя в куке.
>>639114
> PHP Notice: Undefined variable: paymentTotal in /home/LwUcTo/prog.php on line 9
> PHP Notice: Undefined variable: paymentTotal in /home/LwUcTo/prog.php on line 9
Ошибка из-за обращения к еще не существующей переменной. Надо исправить.
Выражение ($credit * $percent) + $commission повторяется 3 раза, надо бы избавиться от повтора.
Если поставить сумму в 1000 р то считает неправильно - во втором банке должно быть 2030 р, а не 2940: http://ideone.com/kzHxKh
Пока не годится.
Не пишите здесь. Никто вам не ответит. Идите в новый тред.
Это копия, сохраненная 19 февраля 2016 года.
Скачать тред: только с превью, с превью и прикрепленными файлами.
Второй вариант может долго скачиваться. Файлы будут только в живых или недавно утонувших тредах. Подробнее
Если вам полезен архив М.Двача, пожертвуйте на оплату сервера.