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

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

Если вам полезен архив М.Двача, пожертвуйте на оплату сервера.
33 Кб, 500x500
157 Кб, 1024x683
193 Кб, 1024x768
70 Кб, 604x604
Клуб изучающих PHP #60 #551625 В конец треда | Веб
Добро пожаловать в наш уютный тредик. Тут мы изучаем язык PHP (а также JS/CSS/HTML/SQL), решаем задачки и даже делаем простые сайты! Зачем? Кто-то хочет научиться программировать, кто-то - делать сайты, кто-то - просто размять мозги и заняться чем-то полезным.

Почему PHP? Потому что фейсбук и википедия на нем написаны, и вакансий море, и учить легко.

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

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

Предыдущий тред был тут: >>543720 (OP)

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

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

У нас есть уроки по основам 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
- Проверялка решений на 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.github.io/ru-php-the-right-way/ )
- По PHP: Профессиональное программирование на PHP Джордж Шлосснейгл
- По PHP: Мэтт Зандстра — PHP: Объекты, шаблоны, методики программирования
- JS: learn.javascript.ru
- Про Git:

Подскажи сайты для поиска работы, я не умею гуглить? brainstorage.me, geekjob.ru, hh.ru
Нужен ли ООП, фреймворки, MVC? — Да, однозначно. Посмотри любую вакансию.
Сайт опять упал!!!!! — Не паникуй, а открой http://rghost.net/45000175
Оформляй код аккуратно!!! — например пропусти через phpformatter.com . Также, если ты пользуешься IDE вроде PhpStorm, Netbeans, Eclipse, то в них эта опция встроена, подробнее: https://gist.github.com/codedokode/8759492
ОП, сделай за меня мою работу или домашнее задание? — Это конечно, хорошая идея, но нет.
Где искать работу и заказы — hh.ru, geekjob.ru, brainstorage.me, fl.ru, odesk.com. Имей в виду, что кроме фриланса есть еще постоянная удаленная работа (remote job) когда тебе не надо тратить время на поиск заказов и переговоры с неадекватными заказчиками.
56 Кб, 500x644
72 Кб, 1022x575
173 Кб, 750x987
#2 #551629
Код нужно писать не как попало, а аккуратно и по правилам. Почему? Потому, что на неакуратно написанный код не хочется даже смотреть.

Если тебе лень выравнивать код руками, закачай его на 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, то рассказать об этом стоит в каком-нибудь другом треде.

Ах да. Если тебе кажется, что что-то в учебнике или задачах можно сделать лучше — пиши, обратная связь всегда очень полезна.
56 Кб, 500x644
72 Кб, 1022x575
173 Кб, 750x987
#2 #551629
Код нужно писать не как попало, а аккуратно и по правилам. Почему? Потому, что на неакуратно написанный код не хочется даже смотреть.

Если тебе лень выравнивать код руками, закачай его на 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, то рассказать об этом стоит в каком-нибудь другом треде.

Ах да. Если тебе кажется, что что-то в учебнике или задачах можно сделать лучше — пиши, обратная связь всегда очень полезна.
#3 #551633
Если я кого-то забыл или не ответил, напомните о себе. Ну и зайдите в предыдущий тред, посмотрите, может быть я вам ответил, просто позже.

Напомню сделать задачу на SPA, анон просит >>546355

Напомню проверить >>550257

https://github.com/nsdvw/file-sharing

> Джаваскрипт действительно лучше больше не смотри, мне лучше сначала основательно подучить теорию.


https://github.com/nsdvw/classifieds
#4 #551649
Кстати, на codeacademy открылся курс по SQL. Очень удобно учить синтаксис по этому курсу с уже готовыми таблицами.
#5 #551662

>Буэээ: https://jsfiddle.net/wv2L7oog/1/



Надо чтобы твои примечания работали в любом тексте а не только содержащем p. Также не очень понял зачем margin-top на первом элементе? Ты пытаешься компенсировать margin-top у p? А что если после примечания идет не p, а h1-h6? Элемент без маргин-топа? Гм, хороший вопрос я придумал, как же это сделать правильно.

Прочитай также комментарий к задаче (или может он в другой задаче) про маргины и паддинги.

Куда должно прилипать примечание? Я не хуя не понял. Прилипать к списку, картинке, заголовку, абзацу?
#6 #551664
>>551662

Список, картинка, заголовок не должны съезжать влево.

Несколько идущих подряд примечаний не должны выстраиваться горизонтально.
#7 #551668
>>551664

>не задавай поля с помощью margin на <p>. Поля задаются с помощью padding на родительском элементе


если задать паддинг, то как добиться чтобы <aside> находились в зоне паддинга, они остаются внутри родителя.
https://jsfiddle.net/wv2L7oog/3/
#8 #551681
>>551668

Маргин может быть отрицательным (не только для флоатов): https://gist.github.com/codedokode/3f6063edf0a2227eb313
#9 #551684
Я по ходу не сделаю калькулятор. Парсить строку да еще отделить дробь от знака деления.
#10 #551688
Если в foreach перебирается не массив/объект, хранящийся в переменной, а тот что возвращает некий метод, то этот метод будет вызываться на каждой итерации цикла, или только один раз перед его началом?
foreach ($obj->getArray() as $item)
Есть смысл вынести результат работы метода в отдельную переменную?
#11 #551690
В закрепленном треде так и не дождался ответа. Отпишусь тут.
Помогите с литературой по SQL. Дело в том, что решил задрочиться на эту тему буквально с нуля. После окончания универа (инженер-программист), работал не по специальности. В SQL'е в студенческие годы я немного шарил, но естественно все забыл к хуям. Так вот, кроме тех книг, которые указаны в шапке (закрепленного треда), есть ли еще какая-либо литература, способная обучить меня, полного нуба в этом деле?
#12 #551693
>>551688
сделай новый класс и пройдись по объекту массивом в нем.
#13 #551695
>>551688

Один раз. Также, foreach делает для себя приватную копию и итерирует по ней, даже если мы меняем исходный массив, пример:

$a = [1, 2, 3];
foreach ($a as $b) {
$a[1] = 100;
echo $b; // 123
}

http://ideone.com/PWYlAd

> Есть смысл


Если выражение длинное то да, ради читабельности.

>>551690

У нас есть задания на MySQL в ОП посте, и там какие-то ссылки по теории. Или тебе важен именно SQL а не его конкретная реализация?
#14 #551707
>>551695
Мне важно всё по этому языку
#15 #551709
>>551363
Какой еще график работы и опыт? В задании об этом ничего не сказано.
Ладно, я просто не понял условие. Переделал.
http://ideone.com/PaVVXL

Объекты-работников добавил в цикле, к ним можно обращаться по индексу в массиве (будем считать, что это у нас такая бд).
Создавать каждого сотрудника отдельно, чтобы дать ему имя, возраст и прочие характеристики, это уже нереально. Надо тогда уже делать админку, чтобы заполнять эти поля.
#16 #551713
>>551695
Нашел там это
http://www.pyramidin.narod.ru/rusql/index.htm
годно ли для полного нуба?
#17 #551719
>>551707
Эм, бака, в различных БД используються различный синтаксис, какой из тебя инжер если ты не в курсе?
#18 #551720
>>551709

> public function fireEmployee($index)


Это неправильно и нелогично. Как этим пользоваться? Где брать этот индекс?

Это явное нарушение инкпусуляции, то есть ты внутренние знания Department (под каким индексом в нем работник) вытаскиваешь наружу.

Логично в качестве идентификатора работника использовать самого работника:

function fireEmployee(Employee $e)

> public function hireCrowd


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

> if ($this->departments[$i]->name != $name) continue;


if надо писать в 3 строчки и со скобками ради качества кода, а не заставлять твоих коллег потом ставить за тебя эти скобки при правке.

> for ($i = 0; $i < count($this->departments); $i++) {


Для обхода массива логичнее и удобнее использовать foreach

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

Функцию printReport я бы вынес из класса Company. Она не часть компании, а работает над ее данными и его логично вынести наружу. К сожалению, это плохое объяснение.

>>551713

Почитать можно, но туториал который есть в заданиях на MySQL, гораздо ближе к практике.
#18 #551720
>>551709

> public function fireEmployee($index)


Это неправильно и нелогично. Как этим пользоваться? Где брать этот индекс?

Это явное нарушение инкпусуляции, то есть ты внутренние знания Department (под каким индексом в нем работник) вытаскиваешь наружу.

Логично в качестве идентификатора работника использовать самого работника:

function fireEmployee(Employee $e)

> public function hireCrowd


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

> if ($this->departments[$i]->name != $name) continue;


if надо писать в 3 строчки и со скобками ради качества кода, а не заставлять твоих коллег потом ставить за тебя эти скобки при правке.

> for ($i = 0; $i < count($this->departments); $i++) {


Для обхода массива логичнее и удобнее использовать foreach

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

Функцию printReport я бы вынес из класса Company. Она не часть компании, а работает над ее данными и его логично вынести наружу. К сожалению, это плохое объяснение.

>>551713

Почитать можно, но туториал который есть в заданиях на MySQL, гораздо ближе к практике.
#19 #551721
>>551719

Нет. SQL на 90% одинаковый, а только 10% это особенности того или иного диалекта.
#20 #551724
>>551709

И что насчет антикризисных мер? Не вижу пока что функций которые бы брали компанию и осуществляли над ней антикризисные действия.
#21 #551725
>>551709

> $profDependencies = $this->getProfDependencies($this->profession);


зачем передавать $this->profession? По моему это излишне.
#22 #551727
>>551709

> return ($this->isBoss) ? self::BOSS_PREMIUM $profDependencies['wageRate'] $this->rank


: $profDependencies['wageRate'] * $this->rank;
Это надо упростить и разбить на 2-3 команды. Ибо читаемость очень плохая получается, и рекомендуемый лимит это 80 символов на строку.
#23 #551728
>>551709

А, я придумал почему printReport надо вынести наружу. Потому что ты смешиваешь код отвечающий за логику (модель компании) и код отвечающий за вывод этих данных. Традиционно во всех системах отделяют модель от кода представления.
#24 #551729
>>551709

> while (strlen($string) < $columnSize) {


> $string .= ' ';


1) почему strlen? Не читал мой урок по строковым функциям и utf-8?

2) почему не str_repeat вместо цикла?
#25 #551736
ОП, привет. Я - анон, который писал тебе про задачи с регекспами. Постарался исправить в соответствии с твоими рекомендациями:
1) Первая задача про номера - переделал, чтобы всё проверялось регуляркой. Не нравится то, что пришлось во всех местах, где может быть что-то из "-()" их перечислять снова и снова, громоздко выглядит http://ideone.com/7gz4e5
2) Вторая на проверку текста на ошибки - там ты указал на небольшие косяки, вроде поправил. http://ideone.com/y858QL Кстати, почему нужно было вынести счётких замен ($count) в отдельную строку, снаружи if?
3) Третья - убрать лишние символы из номера, вроде тут всё несложно - http://ideone.com/ynYv7Q
4) Последняя - автоисправление ошибок. Тут я разошёлся, решил сделать регистронезависимыми эти замены, с помощью коллбека, и не пойму, нормально это или нет. Проверял, в каком регистре буква, и заменял соответственно. Кстати, почему-то не заработало ctype_lower() на кириллице, на латинице работает. Пришлось регистр регекспом проверять. http://ideone.com/rwNeES
#26 #551738
>>551729
На mb ругается ideone.
Я же написал в комментариях на 4 строке.
>>551728
Наружу это куда? В отдельную функцию, или писать какой-то класс-хелпер?
>>551720

>Логично в качестве идентификатора работника использовать самого работника


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

Вообще логичнее было бы именно дать сотрудникам имена, и искать уже по имени как по ключу в ассоциативном массиве-списке сотрудников.
Но я не буду руками писать код создания 101 объекта, а затем 101 раз вызывать метод добавления сотрудника.

>>551724
Потом, если не надоест.
#27 #551741
ОП, как в yii2 лучше передавать информацию в вид, если ее довольно много?
Объектом, или массивом?
Например, увидел что у arrayhelper есть метод toArray(), может быть так будет быстрее, или наоборот, конвертация замедлит работу.
Не зашквар ли использовать foreach, если есть arrayhelper'ы?
#28 #551746

> mb_stlen


черт
#29 #551747
>>551738

> Call to undefined function mb_stlen() - Ideone не подключено расширение?


Опечатка в названии, пруф: http://ideone.com/49VNtK

> В отдельную функцию, или писать какой-то класс-хелпер?


Можно и так и так, тут главное чтобы модель компании была ООП, а сторонние по отношению к ней функции можно оставить как функции.

> и после первого добавления сотрудников они куда-то сохранятся (в базу, файл)


Это тут не при чем. Сохранение в файл обычно просто сериализует данные (например в JSON) и кладет в файл и никаких идентификаторов нам не дает. В базе они есть, да, но тут никто про базу не говорил да и не лучшая идея писать код который без наличия базы не может увольнять сотрудников.

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

> Вне объекта компании сотрудники долго не живут, я не могу постоянно держать ссылку на объект снаружи.


Это какая-то непонятная логика. Вот у нас есть объект Департамент, в который можно добавлять сотрудников. Где они будут храниться это не его дело, он не должен об этом знать. Каждый должен заниматься своим делом. Соответственно никакой привязки к базе когда мы хотим просто удалить сотрудника из департамента, быть не может.

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

> логичнее было бы именно дать сотрудникам имена, и искать уже по имени как по ключу


Нет. Имена неуникальны, а объекты уникальны (тут конечно можно взять и начать присваивать работникам табельные номера). Ты почему-то пытаешься усложнить задачу. У тебя уже есть уникальный идентификатор — это сам объект, какой смысл придумывать дополнительные идентификаторы?

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


Тем не менее для целей задачи (сделать прогноз в случае антикризисных мер) этого достаточно.
#30 #551749
>>551741

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

Метод toArray() там для случаев когда надо куда-то экпортировать эту информацию, в JSON например.
#31 #551752
>>551749
ну хз, массивы же вроде как быстрее работают.
Еще хотел спросить:
в виде ставить условия -- плохо?
как быть если нужно отобразить разную информацию в зависимости от чего-то
#32 #551758
>>551752

> массивы же вроде как быстрее работают.


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

> в виде ставить условия -- плохо?


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

Используется синтаксис с двоеточием и endif.

>>551738

Хочу также сказать следующее. Решение задачи на Вектор целиком поможет тебе лучше знать ООП. А ведь на собеседованиях иногда дают задачи на ООП, вот пример:

https://github.com/groov/lightsoft#4-oop

Она сложная на первый взгляд, но если подумать то можно догадаться как это сделать в рамках ООП-подхода (хотя там в примерах все объяснено).
#33 #551761
>>551758
спасибо!
44 Кб, 706x692
Аноним #34 #551768
Задачка про нахождение палиндрома, второе условие совсем непонятно. Двощ, хелпани подсказкой......
#35 #551778
Какой абсурдный пример: https://hacks.mozilla.org/2015/09/subresource-integrity-in-firefox-43/

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

Более того, вычислять и подставлять хеши — нетривиальное занятие и требует модификации приложения (просто в гульпе дописать правило не получится). Следовательно никто это использовать не ьудет.

Я не могу придумать ни одного сценария для этого.

Пойду еще на HN отпишусь, пусть минусуют.
#36 #551807
>>551720

> public function hireCrowd


>Незачем это класть в департамент, это не его функция создавать работников. Это нужно разместить отдельно.


Как не его функция? Есть объект департамент, у него должен быть метод по добавлению работников. Или ты сагрился на композицию, что объект сотрудника создается внутри метода класса департамент? Ок, сделал отдельной функцией.

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


Как быть, если в департаменте нет ни единого аналитика?
И что это за "антикризисные меры" - повышать зарплату и другие (кофе) расходы на сотрудников?

Сейчас доделаю, чтобы показать, что могу. Но у меня ощущение, что я занимаюсь ненужной херней.
#37 #551810
>>551807

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


Не менять руководителя.

> И что это за "антикризисные меры" - повышать зарплату и другие (кофе) расходы на сотрудников?


Финансовая стимуляция труда.

> Но у меня ощущение, что я занимаюсь ненужной херней.


Отчего же? Разве новая версия программы не лучше старой? Разве ты ничему совсем не научился?
258 Кб, 1000x562
#38 #551811
ОП, сделал задачку "Клавиша shift" в разделе "Повторим".

Можешь подсказать, не сильно ли я наговнокодил? Может есть какие-то случаи дурного тона которые я применил в своем коде?

http://ideone.com/JvdwlP

Делал два дня
#39 #551813
>>551811
И еще вопрос, почему нужно писать в регулярном выражении буквы и маленьким и большим регистром если можно в конце поставь "i" и регистр не будет учитываться?
#40 #551818
>>551813

А где это написано? В древних версиях PHP флаг i не работал с кириллицей но начиная с (вроде) 5.3 он (а также \w) работает нормально и можно его использовать.
20 Кб, 697x174
#41 #551831
>>551818
Ну немного неправильно выразился, ОП не говорил, что так нужно делать, просто везде в поясненниях он пишет дополнительно буквы верхним регистром и не использует "i".
#42 #551839
>>551768
$i<=$halfLength - определяем сколько будет циклов, т.е. если в слове 12 букв, то будет шесть циклов сравнения: 1-ая буква с 12-ой, 2-я с 11-ой и. т.д.
Если буквы одинаковые то увеличиваем значение переменной $result на один а потом сравниваем $result с $halfLength, если равны значит палиндром.
#43 #551844
>>551695

> foreach делает для себя приватную копию и итерирует по ней


Э, а мне нужно в цикле удалить некоторые элементы массива. Че делать?
#44 #551854
>>551844
хуячь по ссылке, очевидно же, или другой массив создавай.
#45 #551859
как создать простой личный кабинет пользователя с данным о нем?
#46 #551878
>>551810
Если финансовая стимуляция труда, то должен быть ее результат, то есть увеличение производительности, кол-во вырабатываемых клерками страниц бумаги.
А так только повышение расходов, какие же это антикризисные меры.

Ладно, сделал 2 из 3.
http://ideone.com/PaVVXL
#47 #551903
>>551844

Так удаляй, в чем проблема? А foreach будет итерировать по своей сделанной копии.

Или тебе надо чтобы он не обходил удаляемые в ходе цикла элементы? Тогда переделывай алгоритм ибо это быдлокод.
#48 #551910
>>551878

Профессии надо сделать константами. Что там еще за магические строки вроде 'engineer'?

Константы защищают от опечаток и делают код понятнее и надежнее.

> Employee::updateDependencies(array('analyst'=>array('wageRate'=>1100,'coffee'=>75,'pages'=>5)));


Массив на массиве погоняет. Сделай-ка чтобы были методы вроде задать базовую зарплату, задать потребление кофе и тд. Не надо тут городить массиво-ориентированное программирование и нарушать инкапсуляцию данных внутри Employee.

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

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

> if ($department != $dep) continue;


Это надо писать в 3 строчки со скобками

> public function fireEmployee(Employee $e)


> {


> foreach ($this->employees as $employee) {


> $index = array_search($employee, $this->employees);


Почему тут и цикл и array-search одновременно?

> public static function updateDependencies(array $dependencies)


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

В общем, пока есть над чем работать.
#48 #551910
>>551878

Профессии надо сделать константами. Что там еще за магические строки вроде 'engineer'?

Константы защищают от опечаток и делают код понятнее и надежнее.

> Employee::updateDependencies(array('analyst'=>array('wageRate'=>1100,'coffee'=>75,'pages'=>5)));


Массив на массиве погоняет. Сделай-ка чтобы были методы вроде задать базовую зарплату, задать потребление кофе и тд. Не надо тут городить массиво-ориентированное программирование и нарушать инкапсуляцию данных внутри Employee.

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

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

> if ($department != $dep) continue;


Это надо писать в 3 строчки со скобками

> public function fireEmployee(Employee $e)


> {


> foreach ($this->employees as $employee) {


> $index = array_search($employee, $this->employees);


Почему тут и цикл и array-search одновременно?

> public static function updateDependencies(array $dependencies)


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

В общем, пока есть над чем работать.
#49 #551914
>>551649
А что делать бакам, которые не знают ангельский?
#50 #551918
>>551910

>Функция обновляет правила глобально для всех компаний и департаментов что очевидно неверно


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

Если не так, очевидно ты неправильно сформулировал условие задачи.
#51 #551936
>>551910
Что тебе не нравится в использовании массивов?
Создать класс для зависимостей?

И ответь, строго ли зависят такие характеристики как потребление кофе или производство отчетов от профессии?
Если нет, тогда действительно лучше завести свойства для каждого конкретного объекта, а не использовать статические класса.
#52 #551943
>>551918

В случае антикризисных мер это не так. Требуется индивидуально менять базовую ставку.

>>551936

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

работник -> задатьБазовуюСтавку(100);

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

> И ответь, строго ли зависят такие характеристики как потребление кофе или производство отчетов от профессии?


Не строго. По умолчанию они зависят, но руководство может менять их для каждого работника индивидуально.
#53 #552037
Помогите задачу с функцией решить про айпад, она легкая я чувтвую, но я куда то не туда иду, весь мозг сломал уже.
Вот тут задачка http://archive-ipq-co.narod.ru/l1/functions.html (айпад в кредит)
Тут мое гавно http://ideone.com/vQDc3R

Там нужно количество месяцев искать или как? Я вообще туплю уже
#54 #552055
Делаю автоопрделение города на сайте с помощью ipgeobase, как мне протестить работу? Пример реализации можно где-нибудь посмотреть, чтобы знать как грамотно делается?
#55 #552093
>>552037
Бля решил походу, больше 2х часов сидел над ней, аж жопа вспотела, но мне почему-то кажется что гораздо проще можно сделать хз http://ideone.com/UJkWzw
#56 #552097
Посоны, а у вас тоже wav не воспроизводятся через тег <audio>?
Всё делаю как следует, mp3 работает, vaw - нет.
Во всех браузерах
#57 #552101
>>551943
Ну и зачем тогда вообще нужна система рангов служащих, если можно вручную раскидать им какие угодно данные? Менеджеру первого уровня я сейчас возьму и задам зарплату в три раза больше чем начальнику 3 левела.

>>551910

> Сделай-ка чтобы были методы вроде задать базовую зарплату, задать потребление кофе и тд.


Базовое потребление кофе, или общее? У тебя в условии задачи сказано, что начальник потребляет в два раза больше кофе и производит 0 отчетов.
Мне кажется, нужно тогда уже задавать итоговое кол-во, раз уж мы лезем в механизм вычисления характеристик снаружи.

>методы вроде задать базовую зарплату


Базовую или итоговую? Зарплата зависит от ранга и статуса начальник/подчиненный.
Мы задаем базовую ставку, от которой будет вычисляться итоговая зарплата в зависимости от доп.коэффициентов, или итоговую?

Сформулируй нормальное условие.
#58 #552104
>>552101

> Ну и зачем тогда вообще нужна система рангов служащих,


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

А возможность менять базовую ставку индивидуально все же нужна. Как минимум для решения пункта про антикризисные меры.

> Базовое потребление кофе, или общее?


А в условии этого не написано? в случае антикризисных мер мы меняем именно базовые величины, базовую ставку и базовое потребление кофе.

> Мне кажется, нужно тогда уже задавать итоговое кол-во,


Нет, это неправильно. Ну сам подумай, тогда при повышении ранга например зарплата не поменяется.

> Сформулируй нормальное условие.


в случае антикризисных мер мы меняем именно базовые величины, базовую ставку и базовое потребление кофе для части сотрудников.
#59 #552107
>>552055

Я делал так: если стоит кука debugGeoIp или GET-параметр то брать IP для определения города из него. Ну а найти IP для нужного города не проблема.

>>552097

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

1) audio воспроизводит не любое аудио а только то что поддерживает браузер
2) в wav данные могут быть в разных форматах. Опять же не все воспроизводятся.

Ну и wav по моему обычно не сжатый и потому много весит, что тебе мешает в mp3 перекодировать?

Информация о поддержке форматов:

https://developer.mozilla.org/en-US/docs/Web/HTML/Supported_media_formats (англ)
http://caniuse.com/#feat=audio
http://caniuse.com/#feat=wav
http://caniuse.com/#feat=mp3
http://caniuse.com/#feat=opus
http://caniuse.com/#feat=ogg-vorbis

На стороне JS можно проверить наличие поддержки методом canPlayType(): https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/canPlayType

Ну и проверь правильно ли ты все подключил, например инспектором на вкладке network посмотри скачивается ли файл.
#59 #552107
>>552055

Я делал так: если стоит кука debugGeoIp или GET-параметр то брать IP для определения города из него. Ну а найти IP для нужного города не проблема.

>>552097

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

1) audio воспроизводит не любое аудио а только то что поддерживает браузер
2) в wav данные могут быть в разных форматах. Опять же не все воспроизводятся.

Ну и wav по моему обычно не сжатый и потому много весит, что тебе мешает в mp3 перекодировать?

Информация о поддержке форматов:

https://developer.mozilla.org/en-US/docs/Web/HTML/Supported_media_formats (англ)
http://caniuse.com/#feat=audio
http://caniuse.com/#feat=wav
http://caniuse.com/#feat=mp3
http://caniuse.com/#feat=opus
http://caniuse.com/#feat=ogg-vorbis

На стороне JS можно проверить наличие поддержки методом canPlayType(): https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/canPlayType

Ну и проверь правильно ли ты все подключил, например инспектором на вкладке network посмотри скачивается ли файл.
3528 Кб, 250x188
#60 #552133
>>551910

>Почему тут и цикл и array-search одновременно?


>>551903
http://ideone.com/XgVdjJ
#61 #552137
>>551910

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


Объект передается по ссылке.
Как этому воспрепятствовать? Первая антикризисная мера увольняет часть сотрудников, таким образом у нас переписывается объект компании. Но мне нужно, чтобы изменения произошли только внутри этой функции с антикризисными мерами, в глобальной области объект компании не должен меняться, чтобы можно было применять меры не последовательно друг за другом, а независимо.
#62 #552144
>>552133

У тебя непонимание как работают массивы.

Вот что например делает тут последняя команда?

$a = 100;
$b = [];
$b[] = $a;

Она кладет в массив $b переменную $a? Неверно. Она кладет в массив копию значения в переменной $a. Ты теперь можешь поменять значение в переменной или удалить ее, массив от этого никак не изменится.

С объектами ситуация чуть интереснее так как они передаются «как бы» по ссылке, а не копируются.

$a = new Test;
$b = [];
$b[] = $a;

Здесь тоже есть копирование, но копируется не объект, а ссылка на него. То есть ссылка на объект в переменной $a копируется в массив и теперь на этот объект есть 2 ссылки (в переменной и в массиве). Опять же, что бы мы не делали с переменной, из массива ничего не исчезнет. Однако
объект у нас только один:

$a->name = '123';
var_dump($b[0]->name); // 123

Теперь поговрим про удаление элементов из массива. Удалить их можно так:

unset($array[$key]);

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

От того что ты сделаешь unset($a) с массивом ничего не изменится.

Потому я не очень понял что ты хотел сказать своим кодом. Поясни?
#62 #552144
>>552133

У тебя непонимание как работают массивы.

Вот что например делает тут последняя команда?

$a = 100;
$b = [];
$b[] = $a;

Она кладет в массив $b переменную $a? Неверно. Она кладет в массив копию значения в переменной $a. Ты теперь можешь поменять значение в переменной или удалить ее, массив от этого никак не изменится.

С объектами ситуация чуть интереснее так как они передаются «как бы» по ссылке, а не копируются.

$a = new Test;
$b = [];
$b[] = $a;

Здесь тоже есть копирование, но копируется не объект, а ссылка на него. То есть ссылка на объект в переменной $a копируется в массив и теперь на этот объект есть 2 ссылки (в переменной и в массиве). Опять же, что бы мы не делали с переменной, из массива ничего не исчезнет. Однако
объект у нас только один:

$a->name = '123';
var_dump($b[0]->name); // 123

Теперь поговрим про удаление элементов из массива. Удалить их можно так:

unset($array[$key]);

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

От того что ты сделаешь unset($a) с массивом ничего не изменится.

Потому я не очень понял что ты хотел сказать своим кодом. Поясни?
#63 #552145
>>552137

Да, объект передается «как бы» по ссылке (мануал http://php.net/manual/ru/language.oop5.references.php ) и в 99% случаев это именно то что мы хотим. Мы не хотим плодить тысячу копий одного объекта.

Но в этой задаче, действительно, нам нужно сделать несколько копий компании чтобы проводить эксперименты. Для клонирования объектов есть оператор clone: http://php.net/manual/ru/language.oop5.cloning.php

Тебе также придется переопределить магический метод __clone для компании и департамента чтобы при клонировании ее содержимое тоже клонировалось, а не копировались ссылки на объекты.

Ну вот видишь, какая полезная задача, сколько ты нового узнаешь. Я тебе настоятельно рекомендую показать на проверку решение, а также решить кошки-мышки — она тоже на ООП, только еще сложнее и ошибок там делают кучу. И также задачу про скидки было бы хорошо порешать.
#64 #552146
>>552133

> foreach ($arr as $test) {


>\tif ($test->name == 'hello') unset($test);


$test это не элемент массива. Это переменная которая хранит копию его значения. Меняя ее ты никак не меняешь исходный массив.
#65 #552149
>>552137

Алсо, в PHP есть 2 способа сравнения объектов: http://php.net/manual/ru/language.oop5.object-comparison.php

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

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

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

# проверить что обе переменные указывают на один объект
if a is b:

А сравнение через == происходит через вызов метода у одного из объектов и этот метод определяет правила сравнения.
#66 #552150
>>552144
Ты здесь спросил >>551910

>Почему тут и цикл и array-search одновременно?


вот в таком куске кода

foreach ($this->employees as $employee) {
if ($employee != $e) continue;
$index = array_search($employee, $this->employees);
unset($this->employees[$index]);
break;
}

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

Можно было впрочем использовать for, но тогда будут длинные некрасивые конструкции во вложенных циклах вида
$vector->departments[$i]->employee[$j]->rate
384 Кб, 1000x750
#67 #552152
Ананасы, я совсем запутался.
Вообщем есть задачка, ускорить скрипт к которому подсоединяются клиенты (их много, данных среднее кол-во).

Был предложен вариант: ReactPHP, non blocking I/O, ывент дривен говно и прочая малафья. Не мог ли ты дорогой анон подсказать кейсы где его лучше всего использовать? С меня нихуя конешно же

Этот скрипт, выполняет много разной работы, и это зависит от условий.

1. Берем сеттинги из базы для клиента, без которых никак нельзя, они пригодятся позже.
2. Берем из базы, всякие плюшки, коих много и разные.
3. В зависимости от этих плюшек шлём ответ клиенту
4. + Клиенты сами отправляют разные данные, которые также необходимо записать в базу

Подходит ли сама суть React для этого? Я вот читаю, что все обмазываются этим, а сути истерии понять не могу (ментально ограничен видимо).
#68 #552153
>>552152
Бля, забыл добавить, то что иногда в зависимости от плюшек придется читать файлы, они не большие (макс. 1кб). Но именно это меня и смущает
#69 #552156
>>552150

Зачем цикл если ты можешь найти индекс элемента через array_search и удалить?

Проверить наличие объекта в массиве можно через http://php.net/manual/en/function.in-array.php хотя тут это и не требуется.

>>552152

«Ускорение» скрипта начинают с поиска узких мест, профайлинга и определения причин проблем с производительностью.

Те кто начинают его с предложения перейти на другую технологию просто-напросто некомпетентны.

React это фреймворк для поддеркжи асинхронных однопоточных приложений.
#70 #552157
>>552152

> Где их лучше всего использовать


Чат
#71 #552159
Для анонов поясню, почему люди так любят использовать всякие новомодные технологии даже если они не нужны. Есть такая штука как resume driven development - в итоге мы имеем человека у которого в резюме 30 технологий и ни в одной он дальше хелло ворлда не разобрался. Разумеется, раскусить их легко парой вопросов по той или иной технологии.
#72 #552162
>>552156

>«Ускорение» скрипта начинают с поиска узких мест, профайлинга и определения причин проблем с производительностью.



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

>React это фреймворк для поддеркжи асинхронных однопоточных приложений.



Сможет ли он подойти к тем критериям, которые описал выше?

>>552157
Чат на вебсокетах лучше делать
#73 #552163
Самый ламповый поток раздела
#74 #552164
>>552162

>но есть клиент у которого овер дохуя клиентов


бля не выспался, вообщем есть кейс, где нужно очень много подключений.
#75 #552167
>>552156
Все, я заебался.
http://ideone.com/NR5ZVt
#76 #552168
>>552159
Обожаю эти вопросы на резюме

>Что будет если мы сделаем вот так:


>echo "1" + eval('log(10)') + 1 - '1' + 2.3333333;



Сразу представляю какой говнокод там в проектах
#77 #552173
Вас послушать, так все конторы делятся на 2 категории:
1. Хипсторы, которые маются "нестандартной" хуитой.
2. Дноконторы, которые натягивают вордпресс.

Надеюсь все же есть третий вариант, буду искать место, где не занимаются совсем примитивной работой, но и не морочат голову своей псевдоинтеллектуальностью и показной нестандартностью.
264 Кб, 1280x923
someApprentice #78 #552184
https://github.com/someApprentice/Cat-and-Mouse

https://github.com/someApprentice/Cat-and-Mouse/blob/master/Classes/Animal.php#L99
Очевидно, здесь чтобы кошка "ловила" мышку нужно указать что-то вроде:

$this->getWorld()->determineTheObject($x, $y) != $track

но здесь встает такая проблема, чтобы получить $track нужно пройтись по массиву $tracks. Если использовать foreach, то не получиться использовать continue чтобы пропустить предполагаемый ход, потому что continue будет заставлять переходит к следующему элементу массива $tracks, а не к следующему предполагаемому ходу. Что я пропустил?

https://github.com/someApprentice/Cat-and-Mouse/blob/master/Classes/World.php#L86
Почему элементы принтуються по два раза? Попытка написать подобный код на ideone, чтобы более детально рассмотреть код,оказалась неудачной, потому что он не поддерживает html-тэги.
#79 #552189
>>552184

> Почему элементы принтуються по два раза?


Ну а ты на код свой посмотри:

> foreach ($this->getAllAnimals() as $object) {


Для каждой клеточки делается цикл по всем животным и на каждом шаге либо выводится картинка либо минус.
#80 #552191
>>552184

Весь HTML код без исключения надо вынести из классов в отдельный шаблон и подключать его через require как описано тут: http://www.phpinfo.su/articles/practice/shablony_v_php.html

В твоем случае удобно в index.php внутри <body> сделать примерно так:

для i от 0 до N {
делаем ход;
подключаем шаблон выводящий ситуацию на текущем ходе.
}

Для кошек/мышек можно сделать просто массив, хранящий соответствие тип => URL картинки.
#81 #552192
Привет, анон. Я решил заняться программированием, и выбрал php. Сейчас читаю учебник с нуля из ОП-поста. И у меня вопрос:
http://archive-ipq-co.narod.ru/l1/strings.html - здесь задачу с палиндромом надо делать через два массива, где элементами первого будут все символы строки, а элементами второго - все элементы кроме пробелов и переносов строки?
#82 #552199
>>552192
Бля, я еблан.
#83 #552203
Вопрос знатокам по поводу "$matches"
Как сделать чтобы оно выдавало не одно значение "$matches[1]", а все http://ideone.com/7pXyzL.
мимо-нуб
#85 #552217
как создать простой личный кабинет пользователя с данным о нем?
#86 #552218
>>552217
Что это за вопрос вообще? В чем конкретно проблема? Руками создавай.
#87 #552226
>>552213
нихуя не понятно...
#88 #552228
>>552226
Что там непонятного? Функция отличается от preg_match только тем, что записывает все совпадения с шаблоном в массив. preg_match записывает первый попавшийся, затем возвращает true.
#89 #552229
Вредные советы по оформлению кода. Я знаю минимум одного анона который им следует:

> Никогда не вставляйте фигурные скобки { } в своих блоках if-else, если этого не требует синтаксис. Когда в вашем коде несколько выражений и блоков if-else идут подряд, причем еще и с неправильным выравниванием, то вы можете запутать даже опытного коллегу.



http://m.habrahabr.ru/company/friifond/blog/268063/
#90 #552231
>>552226

preg_match находит только первое совпадение а preg_match_all все. Она описана в учебнике где-то в конце урока по регуляркам.
#91 #552232
>>552228
>>552231
спс, просто попробовал вписать прег матч ол, не получалось, щас посмотрим где я ошибся
19 Кб, 450x300
#92 #552233
ОП, дай подсказку, я не соображаю уже.
Вот набросал:
https://jsfiddle.net/wv2L7oog/4/
Итого:
1. проблема с картинкой, два последних aside разве не должны быть на уровне последнего абзаца?
2. как элегантно избавиться от проблемы с верхним отступом в первом абзаце?
#93 #552235
>>552203
Воспользуйся циклом foreach и перебери массив $matches и будет что-то что ты хочешь

мимо

Ну а вообще, ты все сделал через жопу и не так как нужно, ведь если найдется ошибка, то будет показываться только сама ошибка типа "шы", а там насколько я помню, нужно, что было показывалось слово с ошибкой
#94 #552237
>>551625 (OP)
Аноны, я совсем зеленый, как заставить mb_strlen давать отрицательное значение? Ну, в строке, к примеру, 20 символов, как сделать так чтоб подсчитовалось количество символов и перед числом ставился минус -?
#95 #552244
>>552233

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


Обычно текст начинается с заголовка, и можно написать правило для этого заголовка. А иногда меняются стили для тегов. В браузере теги hN, ul, p все имеют маргин сверху и снизу, можно поменять чтобы он был только снизу. Еще как вариант, можно нагородить правило типа p:first-child, h1:first-child { ... }.

Я не знаю какого-о универсального решения.

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


А вот это вопрос к тебе, почему так и как это исправить? (подсказка: замени картинку на слово не заключенное в теги и перечитай как позиционируется флоат, например на softwaremaniacs)
#96 #552246
>>552233

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

Надеюсь ты разобрался как работают флоаты на примере этой задачи.
#97 #552249
Няшный анон, поясни за капчу

Мне интересно, как происходит процесс ответа в api anti-captcha
Что находится в файле anti-captcha.com/in.php
И что происходит на странице с распознаванием у китайцев?
Хотелось бы примеры, эти два файла
во я ахуел
Верю в тебя, анон
#98 #552250
>>552249

В этом треде не обсуждается вредоносное и спамерское ПО. Мы тут все белые и пушистые.
#99 #552251
>>552250
я просто спрашиваю как это устроено
#100 #552253
Я однажды пришла на собеседование и сказала, что сделала свою борду. А он спросил сидишь на сосаче? я говорю ну да (итак понятно), а он такой: ТАК ТЫ ТЯН ТЯНОЧКА ТЯН ЕОТ ТЯНТЯНЯТЯНЯТЯНЯТНЯТЯНТЯНЯМИМИМНЯШНАЯТЯНОЧКАТЯНВПЕРДАЧЕЛОЕОТЯНТЯНЯТЯНЯТЯНЯ
#101 #552254
>>552184
бля ты где таких мышей достал?
#102 #552256
так как мне пустой гитигнор создать. в винде не создаются доки без имени! чо чужой проект с гитигнором ради одного файла качать?
#103 #552259
>>552256

Анон что за детский сад?

1) Берешь любой нормальный редактор или IDE (а не блокнот, никогда не программируй блокнотом), создаешь файл, сохранить -> «все файлы» -> вписываешь любое имя.

2) Допустим у тебя нет ни денег и интернета чтобы «купить» редактор на ближайшем торренте. Берешь блокнот, сохранить, вписываешь имя в кавычках.

3) Просишь доброанона закачать пустой гитигнор на файлообменник или гитхаб

4) Пишешь в командной строке echo > .hello

Дальше может еще кто дополнит.
#104 #552262
>>552217
Создаёшь скрипт, допустим profile.php, юзер заходит в свой профиль по ссылке profile.php?name=vasya, скрипт делает запрос в базу данных по имени, которое содержится в GET переменной и выводит на экран данные профиля, которые хранятся в бд.
#105 #552277
Как сделать предложение задом наперед в php?
#106 #552279
>>552277
А, strrev не работает, не могу решить простую задачу на палиндром.
#107 #552281
>>552279
Можно ли как то это сделать через mb_substr? У меня не получается, помогите.
#108 #552285
>>552277
Сложный вариант - режешь на символы, делаешь массиву реверс, склеиваешь.
#109 #552287
>>552285
А если указать кодировку в strrev?
#110 #552292
>>552189
Не могу понять что не так с этим? Мне в каждой клеточке как раз и нужна либо картинка либо минус, а не картинка и минус или минус и минус.

>>552254
http://unicode-table.com/ru/search/?q=%D0%BC%D1%8B%D1%88%D1%8C
#111 #552297
>>552292
Все понял. Хи-хи.
#112 #552328
Я раньше думал, что могу спарсить всё, что угодно с помощью одних лишь регулярок, но столкнулся с проблемой: банально не знаю как спарсить див с неопределенным количеством дивов внутри? Гугл выдает мне какие-то конечные автоматы и посимвольное считывание.
не надо мне советовать готовые библиотеки, я тут пытаюсь изобрести велосипед
#113 #552348
>>552328
Если проблема в том, что теряются закрывающие теги, есть смысл включить "жадность" (флаг U).
http://www.php.su/lessons/?lesson_17
#114 #552357
По сфинксу:
https://gist.github.com/codedokode/10539366
у меня почему-то ругается на оператор match, mysql говорит syntax error.
Я что-то забыл прописать/установить?
Когда читал мануал тоже не мог понять, с какого перепуга mysql вдруг начнет понимать синтаксис запросов сфинкса.

Кстати при запуске демона из консоли он выдает warning о какой-то устаревшей настройке
WARNING: compat_sphinxql_magics=1 is deprecated; please update your application and config

ubuntu 14, mysql 5.5
#115 #552377
>>552191

>Весь HTML код без исключения надо вынести из классов в отдельный шаблон и подключать его через require как описано тут:


Не могу сообразить, это мне надо убрать из класса World метод printMap() и реализовать её, например, в /templates/print.phtml? Причем сделать это даже не процедурно, а просто php-кодом?

Спасибо.
#116 #552391
>>552357
А, блин, это мануал виноват.
https://gist.github.com/codedokode/10539366#file-sql-test-php
'mysql:host=localhost;port=9306' нельзя localhost, нужно писать айпи, теперь заработало

Еще он у меня странно перезапускается с ошибкой
service sphinxsearch restart
FATAL: failed to lock pid file '.../log/searchd.pid': Resource temporarily unavailable (searchd already running?)
У меня две копии что ли запущено, не понимаю?
#117 #552438
Аноны, кто из ОП поста задачи решал все по JS?
Там под конец такие же сложные и долгие как по PHP, которые решают по несколько месяцев?
#118 #552498
>>552391
searchd --stop
searchd
#119 #552587
ОП, я поставил php на ubuntu, но с последней дело не имел, да и ОС и вообще в unix не разбираюсь. Читаю php the right way, а там composer, vargant и еще до кучи утилит которые пригодятся в разработке, это критично, что я буду работать на windows первое время?
#120 #552592
Програны, я правильно сделал, что перешел на Symfony с Битрикса? Ожидаю, что порог входа тут выше и такого говна, как раньше от других прогеров не будет.
#121 #552640
Можете посмотреть на мой код по задаче про айпад, я не могу понять где уменя ошибка и почему он вообще не запускается.
http://codepad.org/oJqM3VUt
#122 #552647
>>552640
Не закрыт блок (фигурная скобка).
Пости лучше на ideone, там автоматическая подсветка ошибок. Или установи простой редактор типа notepad++ или sublime text.

>>552592
Респект, если перешел.
Или только собираешься? С симфони действительно работают только грамотные, квалифицированные программисты, поэтому плохого кода конечно меньше.
По этой же причине вот так просто перейти на него не очень легко и быстро.
#123 #552658
>>552647
а что с laravel? подходит для первого фреймворка?
#124 #552659
>>552647
Но когда я закрываю оператор "если" он помечает мне что в этой строке ошибка.
http://ideone.com/eUStP7
#125 #552686
>>552659
Точка с запятой после break.
#126 #552693
У меня несколько упоротый вопрос. Можно ли сделать рандом не рандомным в зависимости от какого то условия?
Т.е. например, getrand('sobaka') выдавало бы всегда 1 5 6, например.
А getrand ('kot') всегда выдавало бы 2 4 8
#127 #552694
>>552693
Ты ебнутый?
#128 #552696
>>552694
Немножко, просто не спал давно.
Ладно, переформулирую. Хочу функцию, которая выдавала бы рандомные значения, но одинаковые, при передаче этой функции переменной, например мд5 хэша.
#129 #552706
>>552696

> мд5 хэша.


То, что ты описал, и есть хеш.
#130 #552710
>>552693

Ты плохо объяснил что тебе нужно и для чего все это и потому хороший ответ на свой вопрос ты не получишь.

Есть такая штука. Генератор случайных чисел генерирует не настоящие случайные числа, а псевдослучайную последовательность, причем ты можешь задать ее начальное значение функцией http://php.net/manual/ru/function.mt-srand.php

Если ты поставишь в начале программы напримпер mt_srand(123); то она будет при каждом запуске генерировать одинаковую последовательность случайных чисел. Если к примеру ты делаешь игру на основе случайных чисел ты можешь таким образом сделать ее повторяемой.
#131 #552724
ОП, хуи сосешь?
#132 #552731
Задчака с мобильными номерами, нужно из любого введенного номера сделать дефолтный в формате 8ХХХХХХХХХХ без пробелов, скобок и тире, их все нужно как-то заменить или исключить. Не могу понять через что это делать, через preg_replace я не догоняю как там заменить. Может есть какая-то команда PREG_REPLACE_NO_(скобки, минусы, пробелы)

Исправьте кто-нибудь плиз, или какую-нибудь наводку http://ideone.com/kuBaQV
#133 #552737
>>552693
Можно.
Если я тебя правильно понял, то вот набросал: http://ideone.com/mtkqBg
Только зачем тебе это?
#134 #552741
>>552731
str_replace
#135 #552767
>>552587

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

>>552658

Подходит но он менее популярен чем например Юи.

>>552438

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

>>552391

Это наверно ты под линуксом запускаешь, там PDO увидев слово localhost вместо соединения с указанным портом пытается найти юникс-сокет и коннектится к MySQL в итоге.

Я наблюдаю у себя под дебианом такой эффект:

mysql -hlocalhost --port=9000 (порт сфинкса)
коннектится к MySQL несмотря на указанный порт

mysql -h127.0.0.1 --port=9000
коннектится к сфинксу

Это описано в мануале: http://php.net/manual/ru/ref.pdo-mysql.connection.php#refsect1-ref.pdo-mysql.connection-notes

Но спасибо за информацию. Исправил на гитхабе. Можешь сейчас проверить исправленный код, работает ли?

> Еще он у меня странно перезапускается с ошибкой


Проверить лишние копии можно командой

ps lax | grep search

Прибить можно через

sudo service sphinxsearch stop

Либо kill -TERM 1234 если не поможет

1234 заменить на PID процесса. Сфинкс понимает чигнал TERM и корректно завершается.

Ну и не знаю, как ты его запускаешь, по идее если он у тебя установлен в системе глобально то через sudo service sphinxsearch start
#135 #552767
>>552587

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

>>552658

Подходит но он менее популярен чем например Юи.

>>552438

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

>>552391

Это наверно ты под линуксом запускаешь, там PDO увидев слово localhost вместо соединения с указанным портом пытается найти юникс-сокет и коннектится к MySQL в итоге.

Я наблюдаю у себя под дебианом такой эффект:

mysql -hlocalhost --port=9000 (порт сфинкса)
коннектится к MySQL несмотря на указанный порт

mysql -h127.0.0.1 --port=9000
коннектится к сфинксу

Это описано в мануале: http://php.net/manual/ru/ref.pdo-mysql.connection.php#refsect1-ref.pdo-mysql.connection-notes

Но спасибо за информацию. Исправил на гитхабе. Можешь сейчас проверить исправленный код, работает ли?

> Еще он у меня странно перезапускается с ошибкой


Проверить лишние копии можно командой

ps lax | grep search

Прибить можно через

sudo service sphinxsearch stop

Либо kill -TERM 1234 если не поможет

1234 заменить на PID процесса. Сфинкс понимает чигнал TERM и корректно завершается.

Ну и не знаю, как ты его запускаешь, по идее если он у тебя установлен в системе глобально то через sudo service sphinxsearch start
#136 #552768
>>552328

Открой для себя phpquery или аналогичную библиотеку.

>>552287

Не работает она с utf-8, урок: https://gist.github.com/codedokode/ff99e357e9860ea169b8

>>552281

Можно через mb_substr, можно разбить слово на массив букв и перевернуть.
#137 #552778
Читаю про паттерн Композит в книге, а вы не читаете, хаха лузеры)
70 Кб, 1019x578
76 Кб, 1019x604
#138 #552781
>>552767
Работает, но что-то странное с rt-индексом. Он почему-то всегда возвращает все записи, игнорируя match. Пик1.
Если использовать только дисковые индексы, поиск корректный.

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

Через php тоже некорректно, запрос
$pdo->query("SELECT * FROM index_news, rt_news WHERE MATCH('любая строка')");
возвращает все записи из таблицы rt_news. Если строка содержится в index_news, то возвращает найденный документ из index_news и все документы из rt_news.
#139 #552784
>>552768

>phpquery


Любые php библиотеки читающие ДОМ при большом количестве текста на php необратимо фейлятся по производительности. Нужно либо использовать более низкоуровневые решения на C например или попробывать nodejs, либо придумывать костыли с пошаговых парсингом. Меня как то на собеседование спросили, чем я буду парсить XML в 2гб. Никакая няшная библиотека с этим не справится.
#140 #552786
>>552781
А, через search вообще не находит, returned 0 matches
#141 #552798
test
#142 #552799
>>552781

> Как называется демон сфинкса, чтобы добавить его себе в группу?



cat /etc/pa s s wd | grep sphinx

Нужны права не только на саму папку но и право x для всех папок от корня до нужной папки.

Также это с точки зрения юниксов не очень правильно, системные демоны хранят обычно данные в /var/lib/... а конфиги в /etc. Если у тебя конфиг и данные в папке проекта, тебе лучше запускать сфинкс не через service а от своего пользователя или от пользователя проекта.

Если он не может сохранить данные в rt индексе на диск то индекс вообще не обязан работать. Я советую сначала с этим разобраться.

Также, почитай логи сфинкса где-нибудь в /var/log (может в daemon.log, может в messages). Как альтернатива, можно запускать демон из консоли с флагом -с config --console чтобы он был с твоими правами и писал ошибки в консоль.

Ну и попробуй еще поменять запрос чтобы искать только в rt_news.

>>552784

Встроенный в PHP DOM вроде хорошо большие файлы переваривает.

Для огромных XML файлов надо использовать поточные библиотеки вместо DOM, для PHP это XmlReader и XmlWriter (заметь ты сразу вспоминаешь Си, а о том что есть готовая библиотека не думаешь. это плохо, это значит ты велосипедист). Но в вебе 2гб HTML файлов нет.

Nodejs никак не поможет, это та же динамика что и PHP и память она ест так же.

Ну и ты изначально ведешь не в ту сторону. Я о том что анон быдлокодит и не хочет использовать нормальные библиотеки а ты придумыаешь оправдания и уводишь тему в сторону.
#143 #552800
>>552799

Ох лол! Если писать /etc/pa s s wd слитно то пост не отправляется. Это чудо-система защиты от хакеров на cloudflare как я понимаю - так как хакеры часто тестируют эксплойты через чтение этого файла, она считает слово подозрительным. Ну дауны.

Вот когда люди вместо того чтобы подумать головой используют новомодное машинное обучение, нейросети и прочую новомодную дрянь, всегда так получается.
#144 #552838
Ребята, как вы английский учили? Курсы, онлайн, кино?
#145 #552839
Почему некоторые объекты классов создаются со скобочками (). В чем разница?
например:
$class = new Class();
или
$class = new Class;
#146 #552840
>>552838
на форчане сижу. а зачем тебе английский?
#147 #552843
Да и какие еще учебники посоветуете по пхп, кроме того, что в шапке?
#148 #552858
>>552799
Перенес все конфигурационные файлы в /var/lib/sphinxsearch, все равно та же проблема с rt: через клиент mysql возвращает все документы, через команду search выдает ошибку об отсутствии файла
index 'rt_news': search error: failed to open /var/lib/sphinxsearch/data/rt_news.sph: No such file or directory
Мне что, руками этот файл создать? (Папка data присутствует, 755) В той же папке без проблем создаются файлы для дискового индекса, так что вряд ли дело в правах. И rt_news.lock присутствует, правда пустой.

>>552767
Устанавливал апт-гетом.
При входе в систему нет процесса, хотя я прописал запускать автоматически в /etc/default/sphinxsearch
# Should sphinxsearch run automatically on startup? (default: no)
START=yes

Поэтому запускаю руками sudo searchd.
После чего оказывается, что запущено два процесса
1 0 2872 1947 20 0 19368 932 wait S ? 0:00 searchd
5 0 2873 2872 20 0 22284 4192 poll_s Sl ? 0:00 searchd
А при попытке перезапустить через service sphinxsearch restart пишет
FATAL: failed to open log file '/var/lib/sphinxsearch/log/searchd.log': Permission denied
На папку log права 755. Но в ней от рута создан файл searchd.log с правами 600.
Дал права на чтение и запись. Теперь говорит, что не может создать pid файл.

Я уже запутался, там половина папок и файлов создана от рута, половина от sphinxsearch.
#149 #552860
И еще вопрос. переменную в классе нужно объявлять protected только в том случае, если к ней будут обращаться дочерние классы? Т.е. протектед и введено с целью наследования, чтобы такие переменные были доступны в доч. классах?
Алсо почему про классы пишут дочерние, а не сыновьи, разве тут нет сексизма? И почему матрицу называют так, а не патрицем или отцовцем?
#150 #552874
>>552860
а почему систему подчиненный-ведомый называют master-slave ? Нет ли тут бдсм подтекста?
#151 #552875
>>552860
на самом сдела это пришло из бизнеса.
выражение "Дочерняя компания"
"сыновья компания" это как-то странно и уебищно
#152 #552876
>>552839
да походу без разницы
https://www.google.ru/search?q=php+new+without+parentheses
алсо, учитесь гуглить то что вам нужно на инглише
#153 #552908
>>552876
Я просто помню, что мне еще кто-то сказал за эти скобочки, что не поставил.
#154 #552935
>>552858

Покажи свой конфиг сфинкса.

> Поэтому запускаю руками sudo searchd.


Надо sudo service sphinxsearch start

> При входе в систему нет процесса,


Можно проверить в sysv-rc-conf выставлен ли запуск (ну или в /etc/init.d или что там сейчас используют)

> Я уже запутался, там половина папок и файлов создана от рута, половина от sphinxsearch.


Это плохо.

>>552860

Да.

Ставить надо минимальный уровень доступа, если можно обойтись private то ставить его. Ну а вообще да, ты должен думать о том как будет использоваться поле и решать кто будет иметь доступ.

Не знаю, я пишу классы-наследники.
237 Кб, 1000x1687
#155 #552948
Добрый вечер тредик, вот я и снова с вами. пару дней назад меня пидорнули с моей можно сказать первой веб-дев работки. На которой я пол года кодил на Codeigniter'e, осваивал wordpress, а так же писал самопальные скрипты и менял баннеры на сайтах. Значимый прогресс был только первые месяца 3-4, потом все скатилось в рутину по смене баннеров и прочему контент-макакингу.

Сейчас я думаю, что мне нужно взять себя в руки и начать заполнять дыры в своих знаниях. Хоть я и ковырял небольшой проект с MVC - архитектурой, я до сих пор нихуя не понимаю в OOP и прочих паттернах.

Пока что у меня в голове дорешать задачи ОП-а, он кстати еще жив и участвует в треде, или вы тут сами катаетесь, и олдфаги прост обсуждают рабочие проблемы попутно помогая нубам решать задачу на айфоны?
Параллельно хочу добить основы на htmlacademy. Собственно вот. Что дальше делать не знаю. Понимаю полностью сейчас, что на работе я учился в 10 раз быстрее, чем сидя до этого дома занимаясь "самообразованием", ведь дома тупо можно бесконечно ебланить, а там тупо не до этого, просто берешь и делаешь.

Надеюсь найду через пару недель работу на джуно-позицию в одной из тех контор, куда ходил год назад и в которых фейлил тестовые задания.
#156 #552962
>>552948

На ООП есть задачи про Вектор, Кошки-мышки, ты их решал? А так, я советую тогда делать задание на Юи 2, например сайт тестов или может как другой анон, доску объявлений с иерархическими категориями и EAV.

Также обрати внимание что у нас есть задания на HTML/CSS и JS и на SQL, все в ОП посте.
#157 #552966
>>552935
Да, вот в этом было дело.
Вместо sphinxd нужно sphinxsearch.
Если быть точнее, его вообще не нужно запускать. В файле /etc/default/sphinxsearch можно выставить start=yes для автозапуска сфинкса вместе с операционной системой.
А я запустил вторую копию руками, причем от суперпользователя sudo sphinxd, поэтому происходил конфликт: файл search.pid уже существовал, созданный от пользователя sphinxsearch. Но я запускал вторую копию через судо, и не получал определенных прав.

Почистил руками папку data и log, перезапустился.
Через php все работает правильно (мне большего пока и не нужно). Только утилита search продолжает сообщать об отсутствии файла rt_news.sph, его действительно нет, не знаю чем это грозит. При перезагрузке системы данные rt индекса не теряются, видимо они подгружаются из rt_news.ram

Да, еще indexer приходится тоже выполнять от суперпользователя, иначе
FATAL: failed to open /var/lib/sphinxsearch/data/index_news.tmp.spl: Permission denied, will not index. Try --rotate option.
Причем с опцией --rotate та же ошибка, так что это ни при чем. От суперпользователя проиндексировалось успешно, хотя теперь половина файлов индекса принадлежит судо. Впрочем, все работает, кроме упомянутой утилиты search, которая прекрасно ищет по дисковому индексу, но в rt жалуется на отсутствие rt_news.sph.
На всякий случай фрагмент содержимого /etc/sphinxsearch/sphinx.conf (почти такое же, как в твоем примере из гайда, но со своими путями)

index index_news
{
morphology = stem_ru, stem_en
source = src_news
path = /var/lib/sphinxsearch/data/index_news
docinfo = extern
charset_type = utf-8
}

index rt_news
{
charset_type = utf-8
type = rt
path = /var/lib/sphinxsearch/data/rt_news
rt_field = header
rt_field = body
rt_attr_uint = added
rt_attr_uint = topic
}

searchd
{
listen = 9312
listen = 9306:mysql41

log = /var/lib/sphinxsearch/log/searchd.log
query_log = /var/lib/sphinxsearch/log/query.log

read_timeout = 5
max_children = 30
pid_file = /var/lib/sphinxsearch/searchd.pid
max_matches = 1000
seamless_rotate = 1
preopen_indexes = 1
unlink_old = 1
workers = threads
binlog_path = /var/lib/sphinxsearch/data
compat_sphinxql_magics = 0
}

Права на файлы в папке /var/lig/sphinxsearch/data

drwxr-xr-x 2 sphinxsearch root 4096 Окт 4 02:16 .
drwxr-xr-x 4 sphinxsearch root 4096 Окт 4 02:16 ..
-rw------- 1 sphinxsearch sphinxsearch 8 Окт 4 02:16 binlog.001
-rw------- 1 sphinxsearch sphinxsearch 0 Окт 4 02:16 binlog.lock
-rw------- 1 sphinxsearch sphinxsearch 11 Окт 4 02:16 binlog.meta
-rw-r--r-- 1 root root 128 Окт 4 01:39 index_news.spa
-rw-r--r-- 1 root root 480 Окт 4 01:39 index_news.spd
-rw-r--r-- 1 root root 337 Окт 4 01:39 index_news.sph
-rw-r--r-- 1 root root 1059 Окт 4 01:39 index_news.spi
-rw-r--r-- 1 root root 0 Окт 4 01:39 index_news.spk
-rw------- 1 sphinxsearch sphinxsearch 0 Окт 4 02:16 index_news.spl
-rw-r--r-- 1 root root 0 Окт 4 01:39 index_news.spm
-rw-r--r-- 1 root root 156 Окт 4 01:39 index_news.spp
-rw-r--r-- 1 root root 1 Окт 4 01:39 index_news.sps
-rw------- 1 sphinxsearch sphinxsearch 4 Окт 4 02:06 rt_news.kill
-rw------- 1 sphinxsearch sphinxsearch 0 Окт 4 02:16 rt_news.lock
-rw------- 1 sphinxsearch sphinxsearch 305 Окт 4 02:06 rt_news.meta
-rw------- 1 sphinxsearch sphinxsearch 388 Окт 4 02:06 rt_news.ram

>>552962
Там еще кроме древовидных категорий и eav не помешает полнотекстовый поиск, из-за чего я вожусь со сфинксом, для обновления счетчика просмотра страниц понадобился memcache с кроном, плюс нужно наполнить базу через faker, чтобы потестить производительность при помощи explain и cachegrind.
Куда ни плюнь, новая технология, такое впечатление чем больше учишь, тем больше их появляется на горизонте.
#157 #552966
>>552935
Да, вот в этом было дело.
Вместо sphinxd нужно sphinxsearch.
Если быть точнее, его вообще не нужно запускать. В файле /etc/default/sphinxsearch можно выставить start=yes для автозапуска сфинкса вместе с операционной системой.
А я запустил вторую копию руками, причем от суперпользователя sudo sphinxd, поэтому происходил конфликт: файл search.pid уже существовал, созданный от пользователя sphinxsearch. Но я запускал вторую копию через судо, и не получал определенных прав.

Почистил руками папку data и log, перезапустился.
Через php все работает правильно (мне большего пока и не нужно). Только утилита search продолжает сообщать об отсутствии файла rt_news.sph, его действительно нет, не знаю чем это грозит. При перезагрузке системы данные rt индекса не теряются, видимо они подгружаются из rt_news.ram

Да, еще indexer приходится тоже выполнять от суперпользователя, иначе
FATAL: failed to open /var/lib/sphinxsearch/data/index_news.tmp.spl: Permission denied, will not index. Try --rotate option.
Причем с опцией --rotate та же ошибка, так что это ни при чем. От суперпользователя проиндексировалось успешно, хотя теперь половина файлов индекса принадлежит судо. Впрочем, все работает, кроме упомянутой утилиты search, которая прекрасно ищет по дисковому индексу, но в rt жалуется на отсутствие rt_news.sph.
На всякий случай фрагмент содержимого /etc/sphinxsearch/sphinx.conf (почти такое же, как в твоем примере из гайда, но со своими путями)

index index_news
{
morphology = stem_ru, stem_en
source = src_news
path = /var/lib/sphinxsearch/data/index_news
docinfo = extern
charset_type = utf-8
}

index rt_news
{
charset_type = utf-8
type = rt
path = /var/lib/sphinxsearch/data/rt_news
rt_field = header
rt_field = body
rt_attr_uint = added
rt_attr_uint = topic
}

searchd
{
listen = 9312
listen = 9306:mysql41

log = /var/lib/sphinxsearch/log/searchd.log
query_log = /var/lib/sphinxsearch/log/query.log

read_timeout = 5
max_children = 30
pid_file = /var/lib/sphinxsearch/searchd.pid
max_matches = 1000
seamless_rotate = 1
preopen_indexes = 1
unlink_old = 1
workers = threads
binlog_path = /var/lib/sphinxsearch/data
compat_sphinxql_magics = 0
}

Права на файлы в папке /var/lig/sphinxsearch/data

drwxr-xr-x 2 sphinxsearch root 4096 Окт 4 02:16 .
drwxr-xr-x 4 sphinxsearch root 4096 Окт 4 02:16 ..
-rw------- 1 sphinxsearch sphinxsearch 8 Окт 4 02:16 binlog.001
-rw------- 1 sphinxsearch sphinxsearch 0 Окт 4 02:16 binlog.lock
-rw------- 1 sphinxsearch sphinxsearch 11 Окт 4 02:16 binlog.meta
-rw-r--r-- 1 root root 128 Окт 4 01:39 index_news.spa
-rw-r--r-- 1 root root 480 Окт 4 01:39 index_news.spd
-rw-r--r-- 1 root root 337 Окт 4 01:39 index_news.sph
-rw-r--r-- 1 root root 1059 Окт 4 01:39 index_news.spi
-rw-r--r-- 1 root root 0 Окт 4 01:39 index_news.spk
-rw------- 1 sphinxsearch sphinxsearch 0 Окт 4 02:16 index_news.spl
-rw-r--r-- 1 root root 0 Окт 4 01:39 index_news.spm
-rw-r--r-- 1 root root 156 Окт 4 01:39 index_news.spp
-rw-r--r-- 1 root root 1 Окт 4 01:39 index_news.sps
-rw------- 1 sphinxsearch sphinxsearch 4 Окт 4 02:06 rt_news.kill
-rw------- 1 sphinxsearch sphinxsearch 0 Окт 4 02:16 rt_news.lock
-rw------- 1 sphinxsearch sphinxsearch 305 Окт 4 02:06 rt_news.meta
-rw------- 1 sphinxsearch sphinxsearch 388 Окт 4 02:06 rt_news.ram

>>552962
Там еще кроме древовидных категорий и eav не помешает полнотекстовый поиск, из-за чего я вожусь со сфинксом, для обновления счетчика просмотра страниц понадобился memcache с кроном, плюс нужно наполнить базу через faker, чтобы потестить производительность при помощи explain и cachegrind.
Куда ни плюнь, новая технология, такое впечатление чем больше учишь, тем больше их появляется на горизонте.
#158 #552974
>>552966

Файлы индексов и PID должны принадлежать пользователю sphinxsearch, соответственно индексер запускается тоже от его имени.

Я бы их поменял: владелец и группа sphinxsearch, права 0664.

Логи для демонов принято вести в /var/log/

Для pid по моему есть /var/run (она часто размещается в RAM), но это можно не менять.

> для обновления счетчика просмотра страниц понадобился memcache с кроном,


О, это интересная штука, покажи потом на проверку. Там много подвохов. Ну и сразу статья: http://habrahabr.ru/company/mailru/blog/206494/
#159 #552975
>>552966

Запускать демоны от рута очень плохо так как для рута не работают многие проверки и можно разломать все в системе при ошибке.
#160 #552979
>>552948
За шо пидорнули то?
#161 #553056
>>552838
Аниме смотрю с ансабом.

>>552839
В скобочках передаются параметры конструктору, как аргументы функции. Смотри на конструктор класса, что он там принимает.
#162 #553075
Вторая задача по JQ, плавная прокрутка:

>в Хроме за прокрутку страницы отвечает html, а в других браузерах body


Хром, на $('html') не работает, на $('body') - работает.
Сам код: https://ideone.com/FiIuf0
#163 #553095
https://github.com/someApprentice/Cat-and-Mouse

Исправил большинство замечаний, вывел карту с помощью шаблона.

Остается актуальной проблема >>552184

>https://github.com/someApprentice/Cat-and-Mouse/blob/master/Classes/Animal.php#L99


>Очевидно, здесь чтобы кошка "ловила" мышку нужно указать что-то вроде:



>$this->getWorld()->determineTheObject($x, $y) != $track



>но здесь встает такая проблема, чтобы получить $track нужно пройтись по массиву $tracks. Если использовать foreach, то не получиться использовать continue чтобы пропустить предполагаемый ход, потому что continue будет заставлять переходит к следующему элементу массива $tracks, а не к следующему предполагаемому ходу. Что я пропустил?

#164 #553123
Как перестать прокрастинировать и начать учить пхп?
#165 #553128
>>552962
Вектор решал в своё время. Засел где-то на дополнительных задачах к нему, типа антикризисные решения.

>>552979
Сначала заболел и пропустил 2 дня, и начальник подгорел. Потом у нас был типа "разговор", хотя на самом деле монолог в одностороннем порядке, и я на следующий день опоздал на час из-за того что вообще не спал ночью из-за всего этого психологического пиздеца на работке, в общем как пришел, он совсем бомбанул и сказал что всё.
#166 #553129
>>553128
Говноконтора, или ты настолько говноспециалист сейчас, что заменить без проблем новым за неделю. Подтягивай уровень и устраивайся в нормальную, я по полмесяца в моей прогуливаю бывает, и ничего.
#167 #553131
Посоны, а это нормально, что в слой сервисов передаётся экземпляр класса предоставляемого фреймворком и вызываются его методы (геттеры)?
Или правильнее всё в контроллере распаковывать?
#168 #553138
>>553131
И нет, передаётся не контейнер зависимостей.
#169 #553143
>>553131

Зависит от того что именно передается.
#170 #553147
>>553129

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

>что заменить без проблем новым за неделю.


Это вообще легко. Любого студента со знанем html и основами php наймет и посадит баннеры менять на сайтах, а со временем нагрузит дополнительной хуетой. Собственно я пришел лишь со знанием php в своё время, а потом на меня wp и прочий html скинули.

>Подтягивай уровень и устраивайся в нормальную


Это и собираюсь делать

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


удаленно таски решаешь в таком случае или как?
#171 #553150
>>553143
Symfony\Component\HttpFoundation\File\UploadedFile
#172 #553158
Что если сделать сайт с уроками по пхп, как хтмл академия: базовое бесплатно, а экстра уроки платные? Напихать туда примеры паттернов, хуе-мое, фреймворки, цмски - все это систематизироват. Как думаете, взлетит? Вот смотрю чуваки с хабра курсы продают, но там оплата помесячная, как-то не тост.
http://geekbrains.ru/courses
#173 #553165
>>553158
Они косят под чуваков с хабра.
А ещё я бы не пошёл на эти курсы даже бесплатно.

И сделать качественный образовательный ресурс не так просто, как тебе кажется.
#174 #553166
>>552966

>чем больше учишь, тем больше их появляется на горизонте.


Это еще платон математически обосновал.
#175 #553169
>>553150

Тогда ты должен задать себе вопрос, что у тебя за метод?

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

Скорее всего второе или третье. Значит ты должен вместо UploadedFile передавать что-то более абстрактное, например Symfony\Component\HttpFoundation\File\File, SplFile или может просто путь.

>>553158

чтобы сделать хорошие уроки надо быть хорошим программистом, что не у всех получается, по PHP и вебу вообще очень много неграмотных статей и учебников.
#176 #553170
>>553169

Алсо я тут посмотрел, оказывается UploadedFile, File и SpliFileInfo наследуются друг от друга. Тогда ты можешь передавать UploadedFile, но должен подумать какой класс указать в тайп хинте аргумента функции.
#177 #553171
>>553165
Да главное, чтобы он систематизированный был. фронтенд джуниор, бэкенд джуниор, фронтенд миддл, бэкенд миддл, отдельный раздел по ООП с паттернами, отдельно по фроеймворком. Потому что вначале на человек наваливается каша из незнакомых не систематизированных слов и он заканчивает тем, что учит только верстку с баннерами и вордпресс.
#178 #553176
Простая задача про генератор стихов, вроде все правильно написал, но примерно 1/3 случаев 1 слово в какой-то строке выпадает, несколько раз уже менял код, все равно такая залупа. Из за чего может быть? http://ideone.com/e4aCxC
#179 #553181
>>553169
Метод, работающий только с загруженными через POST файлами. Он возвращает новый объект-модель файла, который я потом передаю уже в сохраняющие методы.
Если вдруг фреймворк поменяется или мы решим написать свои контроллеры, в сервисе придётся переписать только один метод-конвертер.
#180 #553184
>>553171
Этим уже занялись (вроде) компетентные люди.
http://map.hexlet.io/stacks/php
#181 #553186
>>553170
Да, наследуются. У меня частично используются и унаследованные методы (например SplFileInfo::getRealPath()).
#182 #553188
>>553181

Тогда ок. Учти что плохо когда например функция добавления аватарки пользователю принимает только UploadedFile, часто нужно иметь возможность например поставить аватарку из произвольного файла (наример для теста).
#183 #553199
>>553176
$i < 3

У тебя до трех слов цикл идет потому что.
#184 #553202
>>553184
Все-таки я считаю чат должен быть анонимным и без регистрации. Не забудьте шаблоны добавить из книги по ООП. Примеры. чтобы их можно было фиксить, как в хтмл академии и задачи для каждого шаблона с пойнтами и подсказками.
#185 #553206
>>553184

> вентили, регистры, ассемблер


Я бы уже на этом месте закрыл. Они учат не тому что полезнее а тому что им хочется преподавать.
#186 #553208
Добрый вечер, хочу ознакомиться с фреймворками и понять их суть, какой посоветуете взять для ознакомления? При первом знакомстве с MVC посоветовали Opencart , так как у него наиболее простая структура Сам склоняюсь к Yii2 (видимо из-за того, что название встречалось больше всего, так вот, стоит ли сперва взяться за Yii или можно взять сразу Yii 2? Либо всё же выбрать Zend или Laravel? и есть ли какая-то годная литература?
#187 #553216
>>553188
Понял, спасибо.
#188 #553221
>>553206
А книгу, которая идёт в контексте этой темы, советовал бы прочесть? Вот эту: http://www.ozon.ru/context/detail/id/28283366/
#189 #553230
>>553123
1. Устройся на месяц-два на быдло-работу, в макдональдс или типа того.
2. Охуей от мерзости людишек и тупой бессмысленной (но вместе с тем тяжелой) работы.
3. Осознай, что если не выучишь хорошую профессию, будешь жить вот так до самой смерти, пока Пукин (да славится имя Его) не даст пенсию (в 65 лет), которой хватит только на гречку на лопате.
4. ???
5. Перестаешь прокрастинировать быть лентяем и неудачником, начинаешь учить php.
#190 #553234
>>553230
6. Повторять предыдущие 5 пунктов каждый раз когда появляется желание пинать хуи
#191 #553240
>>553208

Opencart это CMS для магазинов, а не фреймворк.

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

>>553230

> 65


Да вы оптимист
330 Кб, 1685x1951
#192 #553250
Оп, я знаю, ты умный, ты такое должен знать.

Я делаю АПИ. По запросу ко мне я должен запустить длинную задачу, которая включает в себя несколько проверок данных в локальной БД, запросы во внешние АПИ и изменение данных в локальной БД по результатам этих запросов. Причем изменения такие, что повторный запрос ко мне с теми же параметрами - не пройдет (ибо проверки данных в БД вначале провалятся)

Как правильно всю эту хрень организовать так, чтобы:
- одновременные запросы ко мне не приводили к "двойным" изменениям в БД и "двойным" запросам во внешине АПИ. Ибо между начальной проверкой условий и изменением данных проходит время
- если скрипт упадет в процессе - чтобы .. ээ.. транзакция.. целиком откатилась. Только вот тут проблема в том, что в транзакцию эту запросы ко внешним АПИ-то не включить, и назад эти запросы не откатить...

Гугление выдает какую то мешанину инфы про такие хрени, как mutexes, two-phase commit protocol, идемпотентность запросов и т.п.
Но, блин, из этой мешанины понять, как именно можно\нужно подобные задачи решать - нихрена не понятно.

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

Заранее спасибо!
#193 #553260
>>553240
Думаешь Путин не доживет до 2057 года? Или еще поднимут пенсионный возраст?
#194 #553262
>>553240

>Opencart это CMS для магазинов, а не фреймворк.


Я не писал что Opencart это фреймворк, я лишь указал, что начал знакомство с МВЦ с опенкарта, так как он интуитивно понятен и хотел бы начать знакомство с фреймворками с чего-то простого/необходимого.

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


То-есть всё же наилучшим вариантом начать будет с yii2.
#195 #553272
Laravel или Yii2? Без оглядки на популярность, только основываясь на личных предпочтениях.
#196 #553277
Что этот код делает, я чот не догоняю.

class Product {
public $id;
public $name;
function __construct($id, $name){
$this->id = $id;
$this->name = $name;
}
}

class ProductFacade {
private $products = array();
function __construct($file){
$this->file = $file;
$this->compile();
}

private function compile(){
function getProductFileLines($file){
return file($file);
}
function getProductObjectfromID($id, $productname){
return new Product($id, $productname);
}

function getNameFromLine($line){
if(preg_match("/.-(.)\s\d+/", $line, $array)){
return str_replace('_', " ", $array[1]);
}
return '';
}

function getIDFromLine($line){
if(preg_match("/^(\d{1,3})-/", $line, $array)){
return $array[1];
}
return -1;
}

$lines = getProductFileLines($this->file);
foreach($lines as $line){
$id = getIDFromLine($line);
$name = getNameFromLine($line);
$this->products[$id]=getProductObjectfromID($id, $name);
}
}
function getProducts(){
return $this->products;
}
function getProduct($id){
return $this->products[$id];
}
}

$facade = new ProductFacade('test.txt');
$facade->getProduct(1);
#196 #553277
Что этот код делает, я чот не догоняю.

class Product {
public $id;
public $name;
function __construct($id, $name){
$this->id = $id;
$this->name = $name;
}
}

class ProductFacade {
private $products = array();
function __construct($file){
$this->file = $file;
$this->compile();
}

private function compile(){
function getProductFileLines($file){
return file($file);
}
function getProductObjectfromID($id, $productname){
return new Product($id, $productname);
}

function getNameFromLine($line){
if(preg_match("/.-(.)\s\d+/", $line, $array)){
return str_replace('_', " ", $array[1]);
}
return '';
}

function getIDFromLine($line){
if(preg_match("/^(\d{1,3})-/", $line, $array)){
return $array[1];
}
return -1;
}

$lines = getProductFileLines($this->file);
foreach($lines as $line){
$id = getIDFromLine($line);
$name = getNameFromLine($line);
$this->products[$id]=getProductObjectfromID($id, $name);
}
}
function getProducts(){
return $this->products;
}
function getProduct($id){
return $this->products[$id];
}
}

$facade = new ProductFacade('test.txt');
$facade->getProduct(1);
#197 #553283
>>553176
Бамп вопросу, аноны помогите, сейчас смотрю может вообще целая строка пропасть. Вообще от чего такое может быть, что через раз правильно срабатывает?
>>553199
Ты че то не так понял. 1 цикл - это одна строка в моем случае, мне нужно их всего 2, а третью я прописал вне цикла
#198 #553286
>>553283

> mt_rand(0, count($word1));


от 0 до количества, но суть в том, что если у тебя 5 значений в массиве то count покажет 5.
Но ключи идут с нулевого (0), а не с первого, дальше подумай что надо сделать с count($word1)
#199 #553290
>>553286
Извини за сумбурность, не всегда могу выразить так как хочу:
$word1 = array('Чудесных', 'Суровых', 'Занятных', 'Внезапных');
count($word1) покажет 4,
но в массиве нет значения с ключем 4 3 последний
#200 #553297
>>553277
Если коротко, то парсит лист с товарами и записывает в объект. Немного странно написан правда.
#201 #553298
>>553290
>>553286
О, спасибо, все понял
#202 #553300
>>553272
Битрикс
#203 #553302
Анончики, расскажите, как вы начинали изучение. Сильно тупили на первых задачах? Я вот сильно туплю. Есть шанс освоить за два года?
#204 #553308
>>553302
Если будешь упорно трудиться и не будешь халтурить, освоишь быстрее. Ничего сверхъестественного тут нет.
#205 #553332
>>553300
После любого адекватного фреймворка, на это говно по имени Bitrix невозможно смотреть, не обблевав клавиатуру. Его же пишут калеки из 1С.
#206 #553334
>>553302
За 2 года ты сможешь без пизды на миддла научиться. Чуть чуть упорства - и через 2 года ты на Сеньора пойдешь
#207 #553346
>>553332
Успешный-менеджер-моде-он
"Но лучше никто ничего не придумал"
"Самая лучшая цмс для махазинов"
"На нее затрачены сотни тысяч часов пронраммистов"
#208 #553350
>>553332
Пиздец ты даун, пишешь какую-то дичь

мимо-битриксоид
sage #209 #553370
давно не заходил
вы уже наверно все с работами да?
#210 #553377
>>553147

>Любого студента со знанем html и основами php наймет и посадит баннеры менять на сайтах


Не будь таким студентом. Учи test driven development, основы SOLID, архитектуру, оптимизацию БД, паттерны проектирования. Сможешь работать в конторах, где не только по-быстрому навалять сайты в вордпрессиках надо, а где также много внимания уделяется чистом коду, рефакторингу и правильным решениям.

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


Крупные конторы могут себе позволить затягивание сроков по запланированным проектам на 1-2 месяца, это норма. Задачи загонять разработчика до истощения как в мелких говноконторках не стоит.
#211 #553444
Задача на палиндром, делал ее дня 2 назад можно сказать в легкую, решил заново сделать и сижу уже больше 2 часов.
Все сделано правильно (проверял) до пункта if, там уже начинается какая-то порнография и я абсолютно не понимаю в чем ошибка. http://ideone.com/26lUCF
В ин-те вообще не нашел это задачи решенной, все только через strrev могут
#212 #553445
>>553444
У тебя в условии if идет присвоение, а не сравнение. '='
#213 #553447
>>553444
там у меня стоит одиночная =, на самом деле там нужно !=
Но все равно не работает
17 Кб, 400x365
Аноним #214 #553452
Привет, анон!

Я новенький в вашей среде, и я прохожу уроки, но я застрял на уроке про кубик. У меня не получается получить результат, но показывает, что задание выполнено "успешно". Вот как я сделал :

<?php

error_reporting (-1);

$anonDice1 = mt_rand(1,6); / Первый бросок анона /
$anonDice2 = mt_rand(1,6); / Второй бросок анона /

$compDice1 = mt_rand(1,6); / Первый бросок компьтера /
$compDice2 = mt_rand(1,6);

/ \n - это перенос строки
echo "У анона выпало {$anonDice1} и {$anonDice2}\nУ компьютера {$compDice1} и {$compDice2}\n";

/
Находим сумму чисел /

$anonSum = ($anonDice1 + $anonDice2);
$compSum = ($compDice1 + $compDice2);

/
Если выпали даблы - игра заканчивается /
/
Используй 2 знака равно для сравнения /
/
&& значит "И" /
if (( $anonDice1 == $anonDice2) && ($compDice1 == $compDice2)) {
\t\techo "2 дабла - тебя ждет большая удача. Запости скриншот!!\n";
\t\texit (); /
exit () завершает выполнение скрипта /
}

/
Проверяем, кто победил... */

В примере задания написано, что после "Проверяем, кто победил..." надо что-то дописать, но я не знаю даже что именно. В описание урока я ничего не могу найти подходящего. Кто выполнял это задание, то объясните нубу.
17 Кб, 400x365
Аноним #214 #553452
Привет, анон!

Я новенький в вашей среде, и я прохожу уроки, но я застрял на уроке про кубик. У меня не получается получить результат, но показывает, что задание выполнено "успешно". Вот как я сделал :

<?php

error_reporting (-1);

$anonDice1 = mt_rand(1,6); / Первый бросок анона /
$anonDice2 = mt_rand(1,6); / Второй бросок анона /

$compDice1 = mt_rand(1,6); / Первый бросок компьтера /
$compDice2 = mt_rand(1,6);

/ \n - это перенос строки
echo "У анона выпало {$anonDice1} и {$anonDice2}\nУ компьютера {$compDice1} и {$compDice2}\n";

/
Находим сумму чисел /

$anonSum = ($anonDice1 + $anonDice2);
$compSum = ($compDice1 + $compDice2);

/
Если выпали даблы - игра заканчивается /
/
Используй 2 знака равно для сравнения /
/
&& значит "И" /
if (( $anonDice1 == $anonDice2) && ($compDice1 == $compDice2)) {
\t\techo "2 дабла - тебя ждет большая удача. Запости скриншот!!\n";
\t\texit (); /
exit () завершает выполнение скрипта /
}

/
Проверяем, кто победил... */

В примере задания написано, что после "Проверяем, кто победил..." надо что-то дописать, но я не знаю даже что именно. В описание урока я ничего не могу найти подходящего. Кто выполнял это задание, то объясните нубу.
Аноним #215 #553453
>>553452
так даже легче будет, а то сразу не понял, как тут все у вас принято показывать.

http://ideone.com/z4APFZ
#216 #553459
>>553452
У анона выпало число X, у компа выпало число Y, сравнить и вывести на экран кто победил
#217 #553466
>>553298
короче, как-то так нужно решать.
http://ideone.com/gur5Pk
47 Кб, 492x233
43 Кб, 456x271
#218 #553469
>>553444
>>553447
Как видно на первом пике, переменные совпадают вплоть до 10го символа (11й есть только у первой).
Стоит мне прописать IF и неравенство между ними, начинается какая-то хуйня.
Я теперь спать не смогу...
#219 #553472
МАААМ МАААМ НУ КУПИ МНЕ ПОЕСТЬ Я ТУТ ДЖВА ГОДА НА СИНЬОРА ПХП САМООБУЧАЦА БУДУ УПОРНА НЕТ РАБОТАТЬ НИ ПАЙДУ МНЕ НАДА ОЧЕНЬ УПОРНА АБУЧАЦА ЧТОБ СРАЗУ НА СИНЬОРА ЗА ДЖВА ГОДА
#220 #553475
>>553447
>>553469
Проблема в том, что ты берешь, как и в случае выше, количество $lenght, забывая, что отсчет идет с ключа под номером 0, а не с 1.
#221 #553476
>>553370
Нет.
Аноним #222 #553477
>>553459
это то что надо дописать?
#223 #553481
>>553477
Да, только английскими буквами.
#224 #553482
>>553477
Допиши вывод на экран чисел, выпавших у анона и компьютера и результат (кто победил). Если ты читал урок, тебе не составит труда это сделать.
#225 #553483
эти задачки - какое-то некрофильство. ссу на всех, кто их делает.
#226 #553484
>>553483
"Я бежала за Вами три дня и три ночи, чтобы сказать Вам как Вы мне безразличны."
#227 #553485
>>553332
После работы с многими cms и фреймворками ,1-с Битрикс не плох и не хорош, он просто по своему ебанутый.
#228 #553494
>>552948
Бро, ты из какого города/региона?
9 Кб, 169x169
Аноним #229 #553502
>>553482
>>553481

если я правильно понял, то мне надо дописать после "if" условие "elseif"(условие 2), "elseif" (условия 3) и "else" или я снова не прав?
#230 #553503
>>553502
Так ты сперва напиши, как ты понял, а мы посмотрим, где ты не прав. Проще пояснить на практике.
#231 #553505
Не забудьте потом на гитхаб выложить, как вы ахуенно палиндром реверснули, такой-то опыт.
Аноним #232 #553521
>>553503
утром напишу. Сейчас уже голова не соображает толком.
#233 #553524
Заканчивая тему сфинкса.
Какую комбинацию индексов все-таки выбрать? В блоге, на который есть ссылка в оповском гайде,
http://chakrygin.ru/2013/04/sphinx-db-indexing-and-delta-indexes.html
описываются какие-то извращения с дисковыми индексами, один из которых переиндексируется кроном раз в определенный промежуток времени, и маленький дельта-индекс, затем они мержатся.
Почему автор так избегает rt-индексов? Мне кажется, что логичнее было бы как раз сделать дельта-индекс rt, который просто очищать при перестройке главного дискового. Тогда не нужно ничего мержить, создавать доп.таблицу с отслеживанием индексаций и тому подобных телодвижений.

Еще я не совсем понял, а зачем собственно нужно sphinx api для php, если все прекрасно работает через клиент mysql. Это для тех случаев, когда у нас база, отличная от mysql/postgresql? Или когда нет возможности установить клиент mysql?
#234 #553537
>>553524

> Почему автор так избегает rt-индексов?


Может быть rt индексов тогда не было. Так, конечно новые данные надо класть в rt индекс, а раз в сутки переиндексировать и переносить в основной индекс. Я могу ошибаться, но rt индексы рассчитаны на небольшие объемы данных - или это уже исправлено? Сфинкс быстро развивается.

> , который просто очищать при перестройке главного дискового.


Только надо не потерять данные которые писались в промежутке между началом перестройки и очисткой.

> а зачем собственно нужно sphinx api для php


По моему исторически оно появилось первым. Ну и есть функции вроде такой http://sphinxsearch.com/docs/current/api-func-buildexcerpts.html - есть ли аналоги им в MySQL API?

Ну и может кому-то обычное АПИ удобнее и он не хочет запросы городить.
#235 #553551
>>553250

> одновременные запросы ко мне не приводили к "двойным" изменениям в БД и "двойным" запросам во внешине АПИ. Ибо между начальной проверкой условий и изменением данных проходит время


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

> идемпотентность



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

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


Ну смотря какое АПИ. Если это АПИ загрузки файла на сервер, то в принципе его можно удалить при откате.

А так, опять же надо продумать алгоритм. Ну рассмотрим к примеру загрузку файла в облако с записью информации в БД. Тут лучше всего сначала загрузить файл, потом записать информацию. В этом случае при падении не получится такого что в базе файл есть, а на сервере нет. А при удалении, наоборот, надо успешно удалить файл из базы и только после - с удаленного сервера.
#236 #553626
http://ideone.com/8rwBUN
Анон, чому цикл не выводимт переменную
#237 #553629
>>553626
Подожди, пока рак на горе свистнет, да пока свиньи полетят. Раньше никак не выведет.
#238 #553631
>>553626
У тебя в условии стоит $divider<10, а сама переменная инициализируется со значением 100.
#239 #553719
>>551625 (OP)
ОП, я понимаю, что тебя уже доебал, но дальше двигаться не могу, томлюсь ожиданием >>551736
937 Кб, 2160x3600
#240 #553754
Как по мне FRONTEND конечно-- прогресс, но язык разметки сам по себе для быдла. Это все равно что иметь в руках пистолет, но вынимать из него патроны и метать во врага. Почему бы вам просто не умереть кодить на мультиплатформенных настоящих языках
/тред
#241 #553768
>>553754
в меде учишься?
Палиндром ебаный #242 #553769
http://ideone.com/Rj3XQy
Сука решил наконец-то эту ссаную задачу, в инт-те ни одного готового решения, ссаные пешки только через стрю могут сделать.
#243 #553770
>>553475
да и тебе спасибо, помог очень, кстати в прошлый раз выше это я и накосячил также с этим отсчетом с 0, не могу пока привыкнуть
#244 #553774
>>553754

У тебя есть альтернатива лучше? Или только критика?
#245 #553782
>>553769
Молодец что решил таки задачу. Лутай свою экспу:-)
Понравилось:
if ($symbol1 == $symbol2){
\t\t\t} else {
\t\tbreak;
\t}

!= или <> давно не работают ?
#246 #553815
рейт, сучечки.
http://ideone.com/7ebBq3

$word1 = array('Чудесных', 'Суровых', 'Занятных', 'Внезапных');
$word2=array('слов', 'зим', 'глаз', 'дней', 'лет', 'мир', 'взор');
$word3 =array('прикосновений', 'поползновений', 'судьбы явлений','сухие листья', 'морщины смерти', 'долины края', 'замены нету', 'сухая юность', 'навек исчезнув');
$word4=array('обретаю', 'понимаю', 'начертаю', 'закрываю', 'оставляю', 'вынимаю', 'умираю', 'замерзаю', 'выделяю');
$word5=array('очертания', 'безысходность', 'начертанья', 'смысл жизни','вирус смерти', 'радость мира');

function getPoem($word)
{
$length=count($word)-1;

$rand=rand(0, $length);

foreach($word as $key=>$value){

if($key==$rand && array_key_exists($rand, $word)){
echo $value." ";
}

}
}

getPoem($word1);
getPoem($word2);
getPoem($word3);
getPoem($word4);
getPoem($word5);
#246 #553815
рейт, сучечки.
http://ideone.com/7ebBq3

$word1 = array('Чудесных', 'Суровых', 'Занятных', 'Внезапных');
$word2=array('слов', 'зим', 'глаз', 'дней', 'лет', 'мир', 'взор');
$word3 =array('прикосновений', 'поползновений', 'судьбы явлений','сухие листья', 'морщины смерти', 'долины края', 'замены нету', 'сухая юность', 'навек исчезнув');
$word4=array('обретаю', 'понимаю', 'начертаю', 'закрываю', 'оставляю', 'вынимаю', 'умираю', 'замерзаю', 'выделяю');
$word5=array('очертания', 'безысходность', 'начертанья', 'смысл жизни','вирус смерти', 'радость мира');

function getPoem($word)
{
$length=count($word)-1;

$rand=rand(0, $length);

foreach($word as $key=>$value){

if($key==$rand && array_key_exists($rand, $word)){
echo $value." ";
}

}
}

getPoem($word1);
getPoem($word2);
getPoem($word3);
getPoem($word4);
getPoem($word5);
#247 #553827

>>>553769


Я просто хотел выебнуться, код - это как член, от величины пользы может и нет, зато выглядит как охуенно
#248 #553828
>>553827
Но ведь чем меньше код, тем он круче. Маленький и аккуратный код всегда краше глазу чем большой.
#249 #553829
>>553815
Не правильно. лол. Строки одной нет, посмотри условия задачи еще раз
1 2 3
1 2 3
4 5
#250 #553830
>>553815
Цикл не нужен. Если (есть элемент в массиве по индексу) то (вывести элемент массива) ,иначе (вывести ''хуй тебе")
#251 #553831
>>553828
Тут не в размере дело, лол. А в балансе подробности / читаемости.
#252 #553833
Анон, который делает сайт объявлений на Юи, что это за ерунда тут?

https://github.com/nsdvw/classifieds/blob/master/protected/models/Ad.php#L38

Мне это не нравится. Зачем перехватывать любые вызовы любых методов? Если это решение какой-то проблемы ее явно можно было решить более аккуратно.

> https://github.com/nsdvw/classifieds/blob/master/protected/models/Ad.php#L177


Этот метод никакого отношения к Ad по моему не имеет.

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

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

Вот обзорный урок по тестам: https://gist.github.com/codedokode/a455bde7d0748c0a351a

Так как сайт не сложный, я думаю, там нужны будут в основном E2E тесты. Чтобы не мучаться с селениумом, можно будет использовать codeception + phantomJS (это эмулятор браузера на вебките поддерживающий JS/CSS и контролируемый через selenium-соместимый протокол). Ну к примеру тест будет проходить форму создания объявления и убеждаться что оно добавилось в список.

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

Как план-максимум - настроить запуск тестов на travis CI чтобы он сам брал новые коммиты из твоего гитхаба, прогонял тесты и у тебя был бэйджик со статусом их выполнения, вот как тут висит: https://github.com/slimphp/slim

А вот лог выполнения одного из тестов (провален): https://travis-ci.org/slimphp/Slim/jobs/83432661

Один на один с тестами никто тебя не бросит, я подскажу и как codeception настроить и опишу пошагово пример теста какого-нибудь. Ну и конечно придется статьи почитать, на хабре например яндекс и баду на эту тему что-то интересное писали.

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

Подумай сам, хочешь ты изучить современный и прогрессивный подход или хочешь по старинке вручную все кнопочки протыкивать (конечно вручную протыкивать может оказаться и быстрее но ведь это ручная рутинная работа).
#252 #553833
Анон, который делает сайт объявлений на Юи, что это за ерунда тут?

https://github.com/nsdvw/classifieds/blob/master/protected/models/Ad.php#L38

Мне это не нравится. Зачем перехватывать любые вызовы любых методов? Если это решение какой-то проблемы ее явно можно было решить более аккуратно.

> https://github.com/nsdvw/classifieds/blob/master/protected/models/Ad.php#L177


Этот метод никакого отношения к Ad по моему не имеет.

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

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

Вот обзорный урок по тестам: https://gist.github.com/codedokode/a455bde7d0748c0a351a

Так как сайт не сложный, я думаю, там нужны будут в основном E2E тесты. Чтобы не мучаться с селениумом, можно будет использовать codeception + phantomJS (это эмулятор браузера на вебките поддерживающий JS/CSS и контролируемый через selenium-соместимый протокол). Ну к примеру тест будет проходить форму создания объявления и убеждаться что оно добавилось в список.

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

Как план-максимум - настроить запуск тестов на travis CI чтобы он сам брал новые коммиты из твоего гитхаба, прогонял тесты и у тебя был бэйджик со статусом их выполнения, вот как тут висит: https://github.com/slimphp/slim

А вот лог выполнения одного из тестов (провален): https://travis-ci.org/slimphp/Slim/jobs/83432661

Один на один с тестами никто тебя не бросит, я подскажу и как codeception настроить и опишу пошагово пример теста какого-нибудь. Ну и конечно придется статьи почитать, на хабре например яндекс и баду на эту тему что-то интересное писали.

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

Подумай сам, хочешь ты изучить современный и прогрессивный подход или хочешь по старинке вручную все кнопочки протыкивать (конечно вручную протыкивать может оказаться и быстрее но ведь это ручная рутинная работа).
#253 #553835
>>553833
Вот ты вроде по делу говоришь, а кажется будто ты ему гербалайф впариваешь.
#254 #553837
>>553835

Приходится применять все доступные методы чтобы хоть одного анона уговорить научиться тестированию. А то рубисты, питонисты, даже яваскриптщики - все пишут тесты, одни мы тут как в каменном веке сидим (хотя один анон все же освоил юнит-тесты, но на яваскрипте).
#255 #553838
Что это за тесты такие?
#256 #553839
http://ideone.com/7WoeiH
http://ideone.com/wtioNY
http://ideone.com/OL6z7l

Вроде работает, энивей, покажите где я проебался.
Целый день на это проебал, пиздец просто!
#257 #553843
>>553838

Автоматизированные тесты, проверяющие правильность работы твоего кода. Там есть юнит-тесты (вызывают функцию и смотрят что она вернет) и end-to-end тесты (робот открывает сайт, тыкает кнопки и смотрит что получится).

https://gist.github.com/codedokode/a455bde7d0748c0a351a
sage #258 #553844

> $femaleSpelling = array(1 => 'одна', 2 => 'две'


кек
только в рнр тредике
#259 #553848
>>553844
Это ОП макет так сделал. Ну не стукай!
#260 #553854
>>553833

Кстати, если посмотреть тесты Слима то видно что они еще запускают программу для проверки правильно ли отформатированы файлы с кодом:

https://travis-ci.org/slimphp/Slim/jobs/83432661#L215

> vendor/bin/phpcs --standard=PSR2 --ignore=vendor/* -n -p .



Это хороший способ заставить всех правильно оформлять код.
#261 #553859
http://ideone.com/1cDZc5
Так чем же всё-таки отличается абстрактный класс от интерфейса? Помимо их разного назначения.
Точно так же, как и в интерфейсе я могу в абстрактном классе объявить абстрактные методы, которые необходимо реализовать в дочернем классе и получится, что все они будут реализовывать "интерфейс" AbstractClassName. Даже тайп-хинтинг в этом случае работает.
sage #262 #553861
интерфейс это контракт
абстрактный клас ненужное говнище
#263 #553863
>>553861
Абстрактный класс тоже можно использовать в качестве контракта.
sage #264 #553866
>>553863
не
нуж
но
#265 #553874
>>553866
Вопрос не в этом, а в том, какие у них функциональные различия. Неужто только то, что в абстрактном классе можно объявить наследуемые свойства?
#266 #553879
>>553833

>что это за ерунда тут


> __call...


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

Аааа... Я вспомнил что писал об этом в прошлом треде.
Проблема >>546980
Тупое решение проблемы >>547026

>>547765

> А в какой ситуации может понадобиться обратиться к несуществующему свойству? У объектов список свойств фиксированный и известный заранее, следовательно в правильном коде обращений к несуществующему свойству быть не может.


В той ситуации, когда модель выполнена по паттерну eav. У одной модели один набор атрибутов, у второй совсем другой. Но в представлении мне приходится обращаться к определенным атрибутам, и я не знаю, есть они или нет.
И снова возвращаемся к начальному вопросу: почему твиг не агрится на заведомую ерунду типа test.hello, но при обращении к свойству реальной модели выбрасывает ошибку?

У объявления есть свойство "цена", причем это необязательный eav атрибут. Цену можно не указывать в определенных рубриках, например "отдам даром" или вакансии с предложением подработки.
В представлении я писал model.price, и твиг (или скорее php) говорил об обращении к несуществующему свойству.

Самое странное, что сейчас убрал этот call, все работает. Не понимаю что такое, сейчас откачу на момент того коммита, и посмотрю в чем дело.

>>553833
Тесты однозначно нужны, даже в таком простом проекте как это сайт объявлений или файлообменник тяжело отслеживать ошибки типа описанной выше. Что уж говорить о серьезном проекте.
Вопрос только во времени.
Я планировал сначала разобрать твои замечания по говнокоду, чтобы привести его в нормальный вид.
Затем заняться оптимизацией кода и бд. В прошлом треде ты мне показал интересный инструмент cachegrind, с помощью которого можно анализировать медленные места в коде, надо этим заняться после чистки грубых ошибок.
Затем уделить время команде explain и посмотреть, что можно сделать с базой.
После этого уже займусь тестами.
#266 #553879
>>553833

>что это за ерунда тут


> __call...


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

Аааа... Я вспомнил что писал об этом в прошлом треде.
Проблема >>546980
Тупое решение проблемы >>547026

>>547765

> А в какой ситуации может понадобиться обратиться к несуществующему свойству? У объектов список свойств фиксированный и известный заранее, следовательно в правильном коде обращений к несуществующему свойству быть не может.


В той ситуации, когда модель выполнена по паттерну eav. У одной модели один набор атрибутов, у второй совсем другой. Но в представлении мне приходится обращаться к определенным атрибутам, и я не знаю, есть они или нет.
И снова возвращаемся к начальному вопросу: почему твиг не агрится на заведомую ерунду типа test.hello, но при обращении к свойству реальной модели выбрасывает ошибку?

У объявления есть свойство "цена", причем это необязательный eav атрибут. Цену можно не указывать в определенных рубриках, например "отдам даром" или вакансии с предложением подработки.
В представлении я писал model.price, и твиг (или скорее php) говорил об обращении к несуществующему свойству.

Самое странное, что сейчас убрал этот call, все работает. Не понимаю что такое, сейчас откачу на момент того коммита, и посмотрю в чем дело.

>>553833
Тесты однозначно нужны, даже в таком простом проекте как это сайт объявлений или файлообменник тяжело отслеживать ошибки типа описанной выше. Что уж говорить о серьезном проекте.
Вопрос только во времени.
Я планировал сначала разобрать твои замечания по говнокоду, чтобы привести его в нормальный вид.
Затем заняться оптимизацией кода и бд. В прошлом треде ты мне показал интересный инструмент cachegrind, с помощью которого можно анализировать медленные места в коде, надо этим заняться после чистки грубых ошибок.
Затем уделить время команде explain и посмотреть, что можно сделать с базой.
После этого уже займусь тестами.
#267 #553907
Спасайте.
Слышал, что в yii2 можно использовать rest так, чтобы он выдирал сходу из базы связанные строки таблиц. К примеру в одной таблице есть поле options_id, а в таблице options поле id, и эти два поля связаны. То есть сделать так, чтобы возвращались соответствующие значения второй таблицы вместе с первой. Что-то говорили про extraFields, но я нихуя не могу нагуглить.
#268 #553939
>>551684

В задаче про простой калькулятор не надо поддерживать дробные числа, только целые. Также не надо соблюдать приоритет операций. В задаче про сложный калькулятор надо, но ты не так понял. Дробь 1⁄3 и деление 1÷3 это одно и то же. В обоих случаях мы делим 1 на 3. Там имеется в виду что сложный калькулятор не должен вычислять выражение вроде 1/3 (округляя до 0.333 и теряя точность), а должен хранить его в памяти и выводить на печать именно как дробь. И соответственно поддерживать операции над дробями. Ну к примеру 1/3 + 1/3 должно давать ответ 2/3 а не 0.6666.

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

https://ru.wikipedia.org/wiki/%D0%A1%D0%B8%D0%BD%D1%82%D0%B0%D0%BA%D1%81%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7

Для превращения токенов в дерево можно использовать алгоритм рекурсивного спуска.

http://lord-n.narod.ru/download/books/walla/programming/Spr_po_C/24/24.htm
http://habrahabr.ru/post/122397/

https://ru.wikibooks.org/wiki/%D0%A0%D0%B5%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC%D0%BE%D0%B2/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D1%80%D0%B5%D0%BA%D1%83%D1%80%D1%81%D0%B8%D0%B2%D0%BD%D0%BE%D0%B3%D0%BE_%D1%81%D0%BF%D1%83%D1%81%D0%BA%D0%B0
http://ejudge.btty.su/bmstu/2008-2009/term2/practice/arithm_article.pdf
http://ermak.cs.nstu.ru/cprog/html/076.htm

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

>>551736

Не жди меня, решай дальше.

> Первая задача про номера


> http://ideone.com/7gz4e5



> [-\\(\\)\\s]


[\\-()\\s] - внутри квадратных скобок большинство символов не надо экранировать (кроме - ^ [ ] \ которые имеют особое значение)

В остальном все верно.

> Вторая на проверку текста на ошибки


Видит ошибки там, где их нету: http://ideone.com/652183

Я советую написать такое выражение для а/но: буква пробелы (а или но) граница_слова

> Кстати, почему нужно было вынести счётких замен ($count) в отдельную строку, снаружи if?


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

> Третья - убрать лишние символы из номера,


Ок, все верно

> Последняя - автоисправление ошибок.



> (к|К)оординально/ui


Если есть флаг i зачем писать К|к? Забыл поправить наверно.

> $orphPatt2 = '/(с|С)десь/ui';


> $orphPatt3 = '/(?:(з|З)дела)((?:ю|л|н)\\s)/ui';


> $orphPatt4 = '/([а-яё](?:ж|ш))(ы)([а-яё]*)/ui';


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

$replace = [
['pattern' => ..., 'callback' => function () { ... }],
....
];

Либо сделать свою функцию, тогда массив будет не нужен:

fixGrammar('/..../', function () {
...
});

Массивы $pattern и $replacement объедини в один чтобы было видно что чему соответствует: ['/координально/' => '$1ардинально', ...]
#268 #553939
>>551684

В задаче про простой калькулятор не надо поддерживать дробные числа, только целые. Также не надо соблюдать приоритет операций. В задаче про сложный калькулятор надо, но ты не так понял. Дробь 1⁄3 и деление 1÷3 это одно и то же. В обоих случаях мы делим 1 на 3. Там имеется в виду что сложный калькулятор не должен вычислять выражение вроде 1/3 (округляя до 0.333 и теряя точность), а должен хранить его в памяти и выводить на печать именно как дробь. И соответственно поддерживать операции над дробями. Ну к примеру 1/3 + 1/3 должно давать ответ 2/3 а не 0.6666.

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

https://ru.wikipedia.org/wiki/%D0%A1%D0%B8%D0%BD%D1%82%D0%B0%D0%BA%D1%81%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7

Для превращения токенов в дерево можно использовать алгоритм рекурсивного спуска.

http://lord-n.narod.ru/download/books/walla/programming/Spr_po_C/24/24.htm
http://habrahabr.ru/post/122397/

https://ru.wikibooks.org/wiki/%D0%A0%D0%B5%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC%D0%BE%D0%B2/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D1%80%D0%B5%D0%BA%D1%83%D1%80%D1%81%D0%B8%D0%B2%D0%BD%D0%BE%D0%B3%D0%BE_%D1%81%D0%BF%D1%83%D1%81%D0%BA%D0%B0
http://ejudge.btty.su/bmstu/2008-2009/term2/practice/arithm_article.pdf
http://ermak.cs.nstu.ru/cprog/html/076.htm

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

>>551736

Не жди меня, решай дальше.

> Первая задача про номера


> http://ideone.com/7gz4e5



> [-\\(\\)\\s]


[\\-()\\s] - внутри квадратных скобок большинство символов не надо экранировать (кроме - ^ [ ] \ которые имеют особое значение)

В остальном все верно.

> Вторая на проверку текста на ошибки


Видит ошибки там, где их нету: http://ideone.com/652183

Я советую написать такое выражение для а/но: буква пробелы (а или но) граница_слова

> Кстати, почему нужно было вынести счётких замен ($count) в отдельную строку, снаружи if?


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

> Третья - убрать лишние символы из номера,


Ок, все верно

> Последняя - автоисправление ошибок.



> (к|К)оординально/ui


Если есть флаг i зачем писать К|к? Забыл поправить наверно.

> $orphPatt2 = '/(с|С)десь/ui';


> $orphPatt3 = '/(?:(з|З)дела)((?:ю|л|н)\\s)/ui';


> $orphPatt4 = '/([а-яё](?:ж|ш))(ы)([а-яё]*)/ui';


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

$replace = [
['pattern' => ..., 'callback' => function () { ... }],
....
];

Либо сделать свою функцию, тогда массив будет не нужен:

fixGrammar('/..../', function () {
...
});

Массивы $pattern и $replacement объедини в один чтобы было видно что чему соответствует: ['/координально/' => '$1ардинально', ...]
#269 #553942
>>551811

> return ($text);


Скобки не нужны (впрочем и вреда от них нет, просто смотрится странно и сбивает с толку).

И давай кое-что переделаем. Смотри, сейчас у тебя код выглядит так:

// Разбиваем текст на буквы
$x = сложный запутанный кусок кода;

Можно ли увеличить читаемость кода? Конечно, можно вынести сложный код в функцию с понятным именем (разбить на буквы = splitToLetters):

$x = splitToLetters($string);

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

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

Далее.Чтобы сделать первую букву заглавной, достаточно отрезать ее mb_substr, перевести в верхний регистр, присоединить хвост строки.

Предложения удобнее может быть склеивать, кладя их в массив и вызывая implode().

$characters[$i] - незачем класть каждую строку в отдельный элемент массива, можно использовать одну и ту же переменную для всех строк по очереди.

> [\\s]+


То же самое что \\s+. Скобки значат «один из символов», и тут у тебя всего один вариант и дан.

> $text = $edit;


Непонятно в чем смысл этого перекладывания из одной переменной в другую.

>>551831

ОПу показалось что так нагляднее в данном примере. Используй что больше по ситуации подходит. Конечно это можно и с флагом i переписать.

>>551859

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

>>551914

Изучать потихоньку, использовать bing translate (вдруг читабельно окажется). Также ты можешь организовать перевод на русский — я или аноны могу подсказать перевод в сложных случаях. Ну и заодно пока ты будешь переводить, ты наизусть все это выучишь.

Реально перевод заключается в прогоне текста через bing transalator и ручную корректировку проблемных мест (которых там будет много). Я проверил — процентов на 50-80 читабельно.

Правда там остается проблема авторских прав, так что опубликовать перевод ты наверно не сможешь.

>>552037

> Там нужно количество месяцев искать


Надо вывести общую сумму заплаченного по кредиту.

>>552093

Анон, ты перезаписал свой код и сейчас по ссылке http://ideone.com/UJkWzw что-то про правописание.

А программа тут http://ideone.com/vQDc3R не работает. Перезапости. Программа должна писать общую сумму выплаченного, около 61270.

>>552167

> else return $this->wageRate * $this->rank;


Ужасно. Надо выдерживать единый стиль. Ставь скобки и пиши в 3 строчки как положено.

> switch ($profession) {


> case Employee::PROF_MANAGER :


> $this->baseCoffee = 20;


Это надо бы вынести в отдельную функцию из конструктора, и может быть стоит поместить значения в массив вида [ профессия => [ 'coffee' => 20, 'pages' => 200, 'wage' => 500 ]] ?

И у тебя не сделаны отдельные классы для профессий, а только один Employee. Это значит что для добавления новых профессий придется править и исправлять старый код, пытаясь не забыть сделать замену во всех местах где требуется. А в случае с несколькими классами достаточно лишь написать новый класс. Ну это не ошибка, это я просто тебя информирую что ты упускаешь шанс изучить наследование и абстрактные методы.

> class Department


> public function getReport()


Мне кажется, это все же должно быть в отдельной функции а не в Department. Ибо видов отчетов может быть много и если мы каждый начнем добавлять в департамент, он раздуется без надобности. Это так называемый принцип Single Responsibility — класс должен заниматься только своим делом а не всем сразу.

Тут логичнее сделать функцию которая берет Департамент и возвращает Отчет по нему. Аналогично с компанией.

> public $employees = array();


> public $departments = array();


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

> public function fireEmployee(Employee $e)


> foreach ($this->employees as $employee) {


> $index = array_search($employee, $this->employees);


это неправильное. Зачем здеь цикл? Обяъсни что тебе мешает сразу вызвать array_search? Алсо почему не указан строгий тип сравнения? Ты не прочел статью про вид сравнения объектов? У тебя ищется вообще не тот объект который ты передал а любой похожий с такими же значениями свойств.

> foreach ($this->departments as $department) {


> unset($department);


Это не удаляет департамент из массива.

> for ($i=0; $i < 95; $i++) echo '-';


Во-первых, надо писать в 3 строчки со скобками, во-вторых, использовать str_repeat или даже сделать отдельный метод printLine() чтобы сделать длинную простыню кода короче.

> $paddingSize = $columnSize - mb_strlen($string);


> $string .= str_repeat(' ', $paddingSize);


А что если paddingSize отрицательный?

Антикризисные меры надо сделать функциями, я же говорил. И сделать клонирование компании чтобы вывести все 4 отчета.

В увольнении инженеров надо вроде бы отобрать 40% наиболее низкоранговых и не увольнять боссов. Для этого надо взять список инженеров, убрать из него боссов (array_filter), отсортировать по рангу, взять 40% (array_slice) и уволить. Так код будет последовательным и читаемым, а у тебя как-то все запутанно получилось.
#269 #553942
>>551811

> return ($text);


Скобки не нужны (впрочем и вреда от них нет, просто смотрится странно и сбивает с толку).

И давай кое-что переделаем. Смотри, сейчас у тебя код выглядит так:

// Разбиваем текст на буквы
$x = сложный запутанный кусок кода;

Можно ли увеличить читаемость кода? Конечно, можно вынести сложный код в функцию с понятным именем (разбить на буквы = splitToLetters):

$x = splitToLetters($string);

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

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

Далее.Чтобы сделать первую букву заглавной, достаточно отрезать ее mb_substr, перевести в верхний регистр, присоединить хвост строки.

Предложения удобнее может быть склеивать, кладя их в массив и вызывая implode().

$characters[$i] - незачем класть каждую строку в отдельный элемент массива, можно использовать одну и ту же переменную для всех строк по очереди.

> [\\s]+


То же самое что \\s+. Скобки значат «один из символов», и тут у тебя всего один вариант и дан.

> $text = $edit;


Непонятно в чем смысл этого перекладывания из одной переменной в другую.

>>551831

ОПу показалось что так нагляднее в данном примере. Используй что больше по ситуации подходит. Конечно это можно и с флагом i переписать.

>>551859

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

>>551914

Изучать потихоньку, использовать bing translate (вдруг читабельно окажется). Также ты можешь организовать перевод на русский — я или аноны могу подсказать перевод в сложных случаях. Ну и заодно пока ты будешь переводить, ты наизусть все это выучишь.

Реально перевод заключается в прогоне текста через bing transalator и ручную корректировку проблемных мест (которых там будет много). Я проверил — процентов на 50-80 читабельно.

Правда там остается проблема авторских прав, так что опубликовать перевод ты наверно не сможешь.

>>552037

> Там нужно количество месяцев искать


Надо вывести общую сумму заплаченного по кредиту.

>>552093

Анон, ты перезаписал свой код и сейчас по ссылке http://ideone.com/UJkWzw что-то про правописание.

А программа тут http://ideone.com/vQDc3R не работает. Перезапости. Программа должна писать общую сумму выплаченного, около 61270.

>>552167

> else return $this->wageRate * $this->rank;


Ужасно. Надо выдерживать единый стиль. Ставь скобки и пиши в 3 строчки как положено.

> switch ($profession) {


> case Employee::PROF_MANAGER :


> $this->baseCoffee = 20;


Это надо бы вынести в отдельную функцию из конструктора, и может быть стоит поместить значения в массив вида [ профессия => [ 'coffee' => 20, 'pages' => 200, 'wage' => 500 ]] ?

И у тебя не сделаны отдельные классы для профессий, а только один Employee. Это значит что для добавления новых профессий придется править и исправлять старый код, пытаясь не забыть сделать замену во всех местах где требуется. А в случае с несколькими классами достаточно лишь написать новый класс. Ну это не ошибка, это я просто тебя информирую что ты упускаешь шанс изучить наследование и абстрактные методы.

> class Department


> public function getReport()


Мне кажется, это все же должно быть в отдельной функции а не в Department. Ибо видов отчетов может быть много и если мы каждый начнем добавлять в департамент, он раздуется без надобности. Это так называемый принцип Single Responsibility — класс должен заниматься только своим делом а не всем сразу.

Тут логичнее сделать функцию которая берет Департамент и возвращает Отчет по нему. Аналогично с компанией.

> public $employees = array();


> public $departments = array();


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

> public function fireEmployee(Employee $e)


> foreach ($this->employees as $employee) {


> $index = array_search($employee, $this->employees);


это неправильное. Зачем здеь цикл? Обяъсни что тебе мешает сразу вызвать array_search? Алсо почему не указан строгий тип сравнения? Ты не прочел статью про вид сравнения объектов? У тебя ищется вообще не тот объект который ты передал а любой похожий с такими же значениями свойств.

> foreach ($this->departments as $department) {


> unset($department);


Это не удаляет департамент из массива.

> for ($i=0; $i < 95; $i++) echo '-';


Во-первых, надо писать в 3 строчки со скобками, во-вторых, использовать str_repeat или даже сделать отдельный метод printLine() чтобы сделать длинную простыню кода короче.

> $paddingSize = $columnSize - mb_strlen($string);


> $string .= str_repeat(' ', $paddingSize);


А что если paddingSize отрицательный?

Антикризисные меры надо сделать функциями, я же говорил. И сделать клонирование компании чтобы вывести все 4 отчета.

В увольнении инженеров надо вроде бы отобрать 40% наиболее низкоранговых и не увольнять боссов. Для этого надо взять список инженеров, убрать из него боссов (array_filter), отсортировать по рангу, взять 40% (array_slice) и уволить. Так код будет последовательным и читаемым, а у тебя как-то все запутанно получилось.
#270 #553943
На капче написано «выберите всю еду» и одна из картинок это плывущий бобер. Я крепко задумался, еда он или пока еще нет.

>>552277

Разбить на массив букв, перевернуть массив array_reverse.

>>552731

нужен preg_replace. Указываешь ему выражение для поиска и на что надо заменить найденный текст (для удаления - на пустую строку).

По ссылке http://ideone.com/kuBaQV задача про кубики и там ошибка - после else нет фигурных скобок.

>>552737

> $getRand = makeRandomizerWithMemory();


Тут лучше объект использовать а не имитировать ООП с помощью замыканий.

>>552860

> И почему матрицу называют так, а не патрицем или отцовцем?


Разрешаю тебе использовать «патрицу» для равновесия.

>>553075

А в фаерфоксе проверял? В браузерах не на вебките используется html по моему. Я помню что элементы разные в разных браузерах.

> var $linkTo = $(e.target).attr('href');


> var $linkToOffsetTop = $($linkTo).offset().top;


Неправильно. Атрибут href может содержать не #abc а например page.html#abc. Ты должен определять указывает ли ссылка на эту страницу или другую, есть ли в ней хеш и указывает ли он на существующий элемент. Для разбора ссылки не надо писать велосипеды а надо использовать свойства которые есть у DOM элемента ссылки:

https://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement

Обрати внимание что там доступны host, hash и тд. Также вопрос на проверку, а ты знаешь в чем разница между attr('href') и prop('href')? Если нет то плохо.

Также, давай сделаем задание интереснее. Если ты сравнишь работу страницы без твоего скрипта и с ним, то обнаружишь что без скрипта переходы записываются в историю и можно вернуться назад кнопкой «назад» (а при обновлении страницы или передаче ссылки кому-нибудь страница прокручивается к нужному месту). Со скриптом разумеется ничего не работает. Исправь это, подсказки:

- для решения проблемы обновления страницы и пересылки ссылки достаточно менять хеш в URL. Чтобы страница при этом не прыгала надо либо менять хеш после окончания анимации (не очень хорошо) либо попробовать делать это через History API.
- для решения проблемы кнопки назад на первый взгляд кажется сложно что-то сделать. К счастью, у нас есть Web History API которое позволяет добавлять записи в историю, а также реагировать на переходы по ней:

https://developer.mozilla.org/en-US/docs/Web/API/History_API
http://habrahabr.ru/post/144071/

В старых браузерах нет History API и там остается только применять грязные трюки с

Ну и оформи-ка свой код в виде плагина jQuery, чтобы для его использования достаточно было написать

$.smoothHashScroll();

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

$.smoothHashScroll('destroy');
#270 #553943
На капче написано «выберите всю еду» и одна из картинок это плывущий бобер. Я крепко задумался, еда он или пока еще нет.

>>552277

Разбить на массив букв, перевернуть массив array_reverse.

>>552731

нужен preg_replace. Указываешь ему выражение для поиска и на что надо заменить найденный текст (для удаления - на пустую строку).

По ссылке http://ideone.com/kuBaQV задача про кубики и там ошибка - после else нет фигурных скобок.

>>552737

> $getRand = makeRandomizerWithMemory();


Тут лучше объект использовать а не имитировать ООП с помощью замыканий.

>>552860

> И почему матрицу называют так, а не патрицем или отцовцем?


Разрешаю тебе использовать «патрицу» для равновесия.

>>553075

А в фаерфоксе проверял? В браузерах не на вебките используется html по моему. Я помню что элементы разные в разных браузерах.

> var $linkTo = $(e.target).attr('href');


> var $linkToOffsetTop = $($linkTo).offset().top;


Неправильно. Атрибут href может содержать не #abc а например page.html#abc. Ты должен определять указывает ли ссылка на эту страницу или другую, есть ли в ней хеш и указывает ли он на существующий элемент. Для разбора ссылки не надо писать велосипеды а надо использовать свойства которые есть у DOM элемента ссылки:

https://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement

Обрати внимание что там доступны host, hash и тд. Также вопрос на проверку, а ты знаешь в чем разница между attr('href') и prop('href')? Если нет то плохо.

Также, давай сделаем задание интереснее. Если ты сравнишь работу страницы без твоего скрипта и с ним, то обнаружишь что без скрипта переходы записываются в историю и можно вернуться назад кнопкой «назад» (а при обновлении страницы или передаче ссылки кому-нибудь страница прокручивается к нужному месту). Со скриптом разумеется ничего не работает. Исправь это, подсказки:

- для решения проблемы обновления страницы и пересылки ссылки достаточно менять хеш в URL. Чтобы страница при этом не прыгала надо либо менять хеш после окончания анимации (не очень хорошо) либо попробовать делать это через History API.
- для решения проблемы кнопки назад на первый взгляд кажется сложно что-то сделать. К счастью, у нас есть Web History API которое позволяет добавлять записи в историю, а также реагировать на переходы по ней:

https://developer.mozilla.org/en-US/docs/Web/API/History_API
http://habrahabr.ru/post/144071/

В старых браузерах нет History API и там остается только применять грязные трюки с

Ну и оформи-ка свой код в виде плагина jQuery, чтобы для его использования достаточно было написать

$.smoothHashScroll();

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

$.smoothHashScroll('destroy');
#271 #553944
Кто запостил вопрос или решение 3 октября или раньше, и я не ответил, напомните о себе. Кто запостил вчера или сегодня, придется подождать.
#272 #553951
>>553859

Чем отличается собака от кошки? Очевидно что класс и интерфейс это разные вещи по определению.

Это вопрос на то понимаешь ли ты что такое класс/интерфейс или нет. Класс это такая штука, описывающая однотипные объекты, а интерфейс это набор требований к классу.

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

Давай-ка ты сам перечислишь все возможные отличия которые знаешь, а мы проверим.

> я могу в абстрактном классе объявить абстрактные методы, которые необходимо реализовать в дочернем классе и получится, что все они будут реализовывать "интерфейс"


Не будут, они будут наследоваться. Реализуют это когда стоит слово implements.

> Точно так же, как и в интерфейсе я могу в абстрактном классе объявить абстрактные методы, которые необходимо реализовать в дочернем классе и получится, что все они будут реализовывать "интерфейс" AbstractClassName. Даже тайп-хинтинг в этом случае работает.



Ты ищешь отличия в том как это работает. А надо искать отличия в том что это разные вещи имеющие разный смысл. Если ты делаешь абс. класс ты говоришь «делайте наследников этого класса» а если интерфейс то «реализуйте этот интерфейс любыми своими классами какими хотите».

Ну и паста

-----------------------

Интерфейс это набор требований к классу. «требование» здесь значит требование чтобы в классе был определенный метод.

Если класс реализует интерфейс, в нем обязаны быть эти методы.Обычно интерфйес представляет собой какое-то умение: классы, реализующие этот интерфейс, умеют что-то делать.

Допустим мы делаем сайт где можно ставить лайки постам и комментам. Допустим у нас есть классы User, Post и Comment.

Вот у нас есть пост и коммент, мы можем увеличить число лайков, допустим методом increaseLikeCount и узнавать сколько у них лайков методом getLikeCount, то есть у них есть что-то общее, но как описать это в коде? Как сказать что эти 2 класса в отличие от других умеют работать с лайками?

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

function addLike(User $user, $object) ...

Мы сказали что $user должен быть объектом класса User, а как сказать что $object должен быть классом, умеющим работать с лайками?

Обе проблемы решают интерфейсы. Объявим интерфейс Likeable, который представляет собой умение получать лайки. Опишем какие методы обязаны реализовать такие классы:

interface Likeable
{
public function increaseLikeCount( );
public function getLikeCount( );
}

Теперь укажем в коде что посты и комменты можно лайкать:

class Post implements Likeable { ... }
class Comment implements Likeable { ... }

на этом этапе php проверит, не забыли ли мы реализовать в классах упомянутые методы. Если забыли — выдаст ошибку. Как удобно!

Ну и теперь мы можем использовать интерфейс чтобы указать какие аргументы принимает функция addLike:

function addLike(User $user, Likeable $object) { ... }

заметь что благодаря интферйесам наш код стал расиряем. Допустим завтра мы добавим класс Photo который тоже можно лайкать. Если он будет реализовывать интерфейс Likeable то функция вроде addLike сможет работать и с ним без переписывания кода.

В общем интерфейс представляет какую-то способность класса и требует от него реализовать определенные методы.
#272 #553951
>>553859

Чем отличается собака от кошки? Очевидно что класс и интерфейс это разные вещи по определению.

Это вопрос на то понимаешь ли ты что такое класс/интерфейс или нет. Класс это такая штука, описывающая однотипные объекты, а интерфейс это набор требований к классу.

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

Давай-ка ты сам перечислишь все возможные отличия которые знаешь, а мы проверим.

> я могу в абстрактном классе объявить абстрактные методы, которые необходимо реализовать в дочернем классе и получится, что все они будут реализовывать "интерфейс"


Не будут, они будут наследоваться. Реализуют это когда стоит слово implements.

> Точно так же, как и в интерфейсе я могу в абстрактном классе объявить абстрактные методы, которые необходимо реализовать в дочернем классе и получится, что все они будут реализовывать "интерфейс" AbstractClassName. Даже тайп-хинтинг в этом случае работает.



Ты ищешь отличия в том как это работает. А надо искать отличия в том что это разные вещи имеющие разный смысл. Если ты делаешь абс. класс ты говоришь «делайте наследников этого класса» а если интерфейс то «реализуйте этот интерфейс любыми своими классами какими хотите».

Ну и паста

-----------------------

Интерфейс это набор требований к классу. «требование» здесь значит требование чтобы в классе был определенный метод.

Если класс реализует интерфейс, в нем обязаны быть эти методы.Обычно интерфйес представляет собой какое-то умение: классы, реализующие этот интерфейс, умеют что-то делать.

Допустим мы делаем сайт где можно ставить лайки постам и комментам. Допустим у нас есть классы User, Post и Comment.

Вот у нас есть пост и коммент, мы можем увеличить число лайков, допустим методом increaseLikeCount и узнавать сколько у них лайков методом getLikeCount, то есть у них есть что-то общее, но как описать это в коде? Как сказать что эти 2 класса в отличие от других умеют работать с лайками?

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

function addLike(User $user, $object) ...

Мы сказали что $user должен быть объектом класса User, а как сказать что $object должен быть классом, умеющим работать с лайками?

Обе проблемы решают интерфейсы. Объявим интерфейс Likeable, который представляет собой умение получать лайки. Опишем какие методы обязаны реализовать такие классы:

interface Likeable
{
public function increaseLikeCount( );
public function getLikeCount( );
}

Теперь укажем в коде что посты и комменты можно лайкать:

class Post implements Likeable { ... }
class Comment implements Likeable { ... }

на этом этапе php проверит, не забыли ли мы реализовать в классах упомянутые методы. Если забыли — выдаст ошибку. Как удобно!

Ну и теперь мы можем использовать интерфейс чтобы указать какие аргументы принимает функция addLike:

function addLike(User $user, Likeable $object) { ... }

заметь что благодаря интферйесам наш код стал расиряем. Допустим завтра мы добавим класс Photo который тоже можно лайкать. Если он будет реализовывать интерфейс Likeable то функция вроде addLike сможет работать и с ним без переписывания кода.

В общем интерфейс представляет какую-то способность класса и требует от него реализовать определенные методы.
#273 #553954
Аноны, я не понимат задачу "Задача на массивы 2" про рост анона. Не ссыкайте, пожалуйста, но у меня вобще нет идей, как ее решить. Я прямо завис на этом, хотя пол года назад проходил весь этот курс буквально за сутки.
Халп!
#274 #553957
>>553879

> В той ситуации, когда модель выполнена по паттерну eav. У одной модели один набор атрибутов, у второй совсем другой. Но в представлении мне приходится обращаться к определенным атрибутам, и я не знаю, есть они или нет.



Ну так ты и не должен делать все эти динамически добавляемые менеджерами свойства полями класса. да и как ты определишь названия полей если там доступно только название на русском (например «модель машины»)?

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

Поясни примером кода если считаешь что я ошибаюсь.

> проблема с твигом


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

Если ты не знаешь список атрибутов то тебе нужен не класс а массив.

> почему твиг не агрится на заведомую ерунду типа test.hello, но при обращении к свойству реальной модели выбрасывает ошибку?


Не знаю, а ты strict_vars включил? Твиг как-то сложно ищет свойство несколькими способами, пытается найти его как элемент массива, как публичное свойство, как геттер.

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

> В представлении я писал model.price


Должно быть что-то вроде model.getCustomAttribute('price')

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


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

> сейчас откачу на момент того коммита, и посмотрю в чем дело.


Ок только много времени наверно тратить не стоит. Ну а вообще ты можешь залезть внутрь твига и натыкать вар дампов в getAttribute()

https://github.com/twigphp/Twig/blob/master/lib/Twig/Template.php#L431

Он вызывается при обращении через точку.

Вот кстати у кого-то похожая проблема: https://github.com/twigphp/Twig/issues/1557

Там еще это может быть связано с тем что Юи добавляет в модели магические методы __get, __call и другие. Переопределяяя их ты кстати ломаешь работу active record. Вот они видны:

https://github.com/yiisoft/yii/blob/1.1.16/framework/db/ar/CActiveRecord.php#L134
#274 #553957
>>553879

> В той ситуации, когда модель выполнена по паттерну eav. У одной модели один набор атрибутов, у второй совсем другой. Но в представлении мне приходится обращаться к определенным атрибутам, и я не знаю, есть они или нет.



Ну так ты и не должен делать все эти динамически добавляемые менеджерами свойства полями класса. да и как ты определишь названия полей если там доступно только название на русском (например «модель машины»)?

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

Поясни примером кода если считаешь что я ошибаюсь.

> проблема с твигом


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

Если ты не знаешь список атрибутов то тебе нужен не класс а массив.

> почему твиг не агрится на заведомую ерунду типа test.hello, но при обращении к свойству реальной модели выбрасывает ошибку?


Не знаю, а ты strict_vars включил? Твиг как-то сложно ищет свойство несколькими способами, пытается найти его как элемент массива, как публичное свойство, как геттер.

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

> В представлении я писал model.price


Должно быть что-то вроде model.getCustomAttribute('price')

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


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

> сейчас откачу на момент того коммита, и посмотрю в чем дело.


Ок только много времени наверно тратить не стоит. Ну а вообще ты можешь залезть внутрь твига и натыкать вар дампов в getAttribute()

https://github.com/twigphp/Twig/blob/master/lib/Twig/Template.php#L431

Он вызывается при обращении через точку.

Вот кстати у кого-то похожая проблема: https://github.com/twigphp/Twig/issues/1557

Там еще это может быть связано с тем что Юи добавляет в модели магические методы __get, __call и другие. Переопределяяя их ты кстати ломаешь работу active record. Вот они видны:

https://github.com/yiisoft/yii/blob/1.1.16/framework/db/ar/CActiveRecord.php#L134
#275 #553959
>>553954

Сделай переменную, положи в нее нуль, если видишь высокого анона, увеличивай на один.
#276 #553962
>>553951

>Ты ищешь отличия в том как это работает. А надо искать отличия в том что это разные вещи имеющие разный смысл. Если ты делаешь абс. класс ты говоришь «делайте наследников этого класса» а если интерфейс то «реализуйте этот интерфейс любыми своими классами какими хотите».


Смысл и назначение обеих этих вещей мне вроде понятны. Мой вопрос можно переформулировать иначе: "Зачем нужны интерфейсы, если то же самое можно реализовать на абстрактных классах?"
Но теперь я вспомнил, что один класс может реализовывать несколько интерфейсов, что с помощью абстрактных классов сымитировать не получится. Вот и вполне себе функциональное отличие.
#277 #553966
>>553962
А снова задуматься над этим меня заставил Пример #1 по ссылке: http://php.net/manual/ru/language.oop5.abstract.php
#278 #553993
Внезапно меня осенило. Программист - это такая же РАБота, как и все остальные. Ты делаешь, что тебе говорят. Похуй, что тебе не нравится Битрикс, изволь хуячить сайты-клоны. Похуй на твой перфекционизм, главное наклепать за 3 дня. Пиздец, реально макаки.
Аноним #279 #554004
На сайте http://archive-ipq-co.narod.ru/ задания находятся не сделанные до конца? Просто я застрял на задание W3. Что конкретно надо делать? http://ideone.com/fork/xNOvg0

Если делаю по примеру на сайте, то получаются числа, которые я пишу в "$random= ~". Я что-то вообще не понимаю, где брать инфу, чтобы я знал в каком порядке что делать.
sage #280 #554028
>>553993
да, всё верно
что теперь делать будешь?
#281 #554030
>>554004
Может мне еще за тебя решить задание?
#282 #554031
>>554028
Продолжу задрачивать. Капитал-то надо как-то высрать.
Аноним #283 #554037
>>554030
я не прошу тут никого решать задания за меня. Я всего лишь прошу объяснить, как нужно правильно его выполнять. Как разобраться в тексте перед самим заданием? Делать прям все что в этом тексте или что-то конкретное? Смотрю следующее задание про игрока анона и компьютера, и уже понимаю, что решить эту задачу я смогу через неделю.
#284 #554040
>>554037
Там написано что нужно делать. Делай задание как ты понял и выкладывай в тред, не нужно готовиться неделями к элементарным заданиям, задавая миллион вопросов.
sage #285 #554051
>>554031
какой капитал?
#286 #554059
>>553830
вот это уже называется доебываться лишь бы доебаться.
#287 #554060
Что означает ?: в регулярках?
#288 #554063
>>553859
в абстрактном еще функции, у которых есть тело, можно прописывать, а в интерфейсе нельзя, только методы обяъвляешь.
20 Кб, 200x200
#289 #554076
Ребята, я недавно начал учить (меньше недели), раньше вообще никак не сталкивался с программированием. Могу сидеть и тупить над простой задачей несколько часов, или просто очень долго залипать на чужой код, где мне все вроде знакомое написано, но я как будто накурен и не могу собраться.
Все плохо? Как у вас было по началу?
Я просто смотрю как некоторые задачи решают, они там такие пируэты выдают, о которых я бы хрен додумался.
не гуманитарий
#290 #554081
>>554076
Not this shit again...
#291 #554082
>>554081
prosti...
Аноним #292 #554083
Эти коды которые я пишу на сайте, так и будут все время выглядить или надо через что-то открыть их, и тогда я увижу какую-нибудь красиво сделанную страницу?
#293 #554086
>>554060
preg_match помещает в массив совпадений matches не только совпадения, но и подмаски, указанные в круглых скобках.
Оператор ?: запрещает класть в $matches подмаску, то есть скобки используются только для группировки.
Запусти код и посмотри
preg_match('/(hell)o(wor)ld/', 'helloworld', $matches);
var_dump($matches);
preg_match('/(?:hell)o(?:wor)ld/', 'helloworld', $matches);
var_dump($matches);
#294 #554087
>>554086
Спасибо за развернутый ответ, понял
#295 #554088
>>554004

Там надо после $random = вписать не число а вызов одной функции которая генерирует случайные числа (она есть в уроке в списке функций). Попробуй сделать и покажи код если что.

>>554030

Не надо так.

>>554051

Для тян наверно?
#296 #554090
>>554059

Не, он прав. Чтобы получить значение элемент массива $array имея ключ $key ты пишешь

$x = $array[$key];

Это быстрая операция. Чтобы найти элемент имея значение $value придется обходить массив циклом или функцией array_search, это не быстрая операция на больших массивах.

Проверить наличие элемента по ключу можно быстро через if (array-key_exists или if (isset($array[$key])) (второй вариант не сработает если значение элемента null)

Проверить наличие элемента зная значение можно перебором массива функцией

if (in_array($value, $array))

Ну и еще функция count() быстро возвращает число элементов в массиве.

это ты должен знать наизусть без шпаргалок. Если не понимаешь слова ключ, значение, посмотри картинки в уроке.
#297 #554091
>>554083

Для этого нужен веб сервер (Апач или встроенный в PHP), установить его на компьютер, и знание HTML, тогда сможешь делать красиво. Если не терпится, ссылки и задачи по HTML в шапке треда. Но и PHP не бросай.

>>554076

Это нормально. Если что пости вопрос и показывай код.

>>554060

Не захватывать и не запомнинать часть строки попавшую в скобки.
(по умолчанию захватывается)
#298 #554093
>>553962

Если понятны то ждем список отличий.

> "Зачем нужны интерфейсы, если то же самое можно реализовать на абстрактных классах?



А если класс уже унаследован от другого, как ты добавишь еще один? да и это побуждает наследовать что попало от чего попало а наследовать можно только однотипные вещи.

за такое надо бить канделябром.

Ну например унаследовать Танк от СредствоПередвижения можно, а Танк от РучнаяГраната нельзя (с точки зрения логики) так как танк это не улучшенная версия гранаты.

Потому если ты пишешь библиотеку и хочешь чтоюы тебе передавали любой объект с нужными методами используй интерфейс (при этом ты можешь также дать в библиотеке готовый класс который его реализует). Если ты хочешь чтобы пользователь библиотеки обязан был унаследоваться от твоего класса, используй абс класс.
#299 #554096
>>553962

Или рассмотрим случай: у нас в игре есть Танк и Солдат, как сделать функцию которая ими стреляет? Надо сделать интерфейс УмеетСтрелять и пусть оба класса его реализуют не наследуюясь друг от друга.

Дам еще ссылочку поломать голову про разделение интерфейсов: http://m.habrahabr.ru/company/ivi/blog/256517/

Еще можешь попробовать прочитать про SOLID но будь готов что не поймешь.
#300 #554098
>>553962

И держи одну из моих любимых статей про хлеб:

http://habrahabr.ru/post/153225/ (правильного ответа на вопрос нет)
http://habrahabr.ru/post/153845/

Наверно есть еще книги разжвывающие принципы ООП, я увы их не читал в свое время.
98 Кб, 900x740
#301 #554107
Ох уж эти замыкания в JS. Голова трещит от них.
Надеюсь на практике они не так часто применяются?
#302 #554111
>>553957
Давай по порядку.
1. Большинство классов в первом yii наследуется от ccomponent, у которого определены геттеры вида
https://books.google.com.ua/books?id=agVGAgAAQBAJ&pg=PA21&lpg=PA21&dq=%D0%BC%D0%B0%D0%BA%D0%B0%D1%80%D0%BE%D0%B2+yii+%D0%B3%D0%B5%D1%82%D1%82%D0%B5%D1%80%D1%8B&source=bl&ots=6K8AN6mYQS&sig=-3NY3FYjYzjU1kF2QxOfeLxM2AM&hl=ru&sa=X&ved=0CDkQ6AEwBGoVChMIyqTOjtiryAIVBTJyCh2XTQvU#v=onepage&q=%D0%BC%D0%B0%D0%BA%D0%B0%D1%80%D0%BE%D0%B2%20yii%20%D0%B3%D0%B5%D1%82%D1%82%D0%B5%D1%80%D1%8B&f=false
2. У CActiveRecord этот метод не переопределяется, а расширяется (или как это называется по-научному, когда используется parent)
https://github.com/yiisoft/yii/blob/1.1.16/framework/db/ar/CActiveRecord.php#L134
3. В библиотеке EavActiveRecord, которую я юзаю, геттеры наследуются(?) следующим образом
https://github.com/iAchilles/eavactiverecord/blob/master/EavActiveRecord.php#L78
То есть если атрибута нет в текущей модели, выбрасывается исключение.

Итак, что мне с этим делать? Еще раз, моя проблема:
в шаблоне я вывожу список объявлений. У большинства из них есть eav-атрибут "цена". Но у некоторых цена не задана, то есть не просто пустая строка или ноль, вообще нет такого свойства (апдейт: у третьей группы свойство есть, но пустое, null; кажется, именно в этом проблема). Что делать?
Попробовал сделать проверку оператором IN твига, который работает как in_array('price', model.eavAttributeNames), не помогает. Ошибка вываливается даже тогда, когда свойство price (вернее геттер для него) доступно, но пустое (null).
Значит все-таки проблема в твиге, его взаимодействии с yii.
https://github.com/twigphp/Twig/issues/1557
Если я правильно понял, то твиг проверяет if ($object instanceof ArrayAccess && isset($object[$arrayItem])). Но в случае если свойство равно null, и иссет пролетает мимо.
Так что делать? Мне унаследовать класс Twig_Template и переопределить этот метод?
#303 #554112
>>554111

Сделать у модели методы например

hasCustomAttribute('price')
getCustomAttribute('price')
#304 #554115
>>554093

>Если понятны то ждем список отличий.


Ну ладно. Вот основное, возможно, есть тонкости, о которых я не знаю.
По сути:
Абс. класс, как я понимаю, - это класс-заготовка, основа для других классов; интерфейс - это "протокол", по которому взаимодействуют разные части программы, гарантия, что класс имеет конкретные методы.

По функционалу:
1. Класс может реализовывать сколько угодно интерфейсов, но унаследовать он может только один абс. класс.

2. Интерфейс не может включать в себя свойства.

3. Абстрактный класс может включать в себя реализацию методов, интерфейс - нет.

4. Методы интерфейса - только публичные.
#305 #554126
>>554098
Прочитал, улыбнулся, добавил в закладки
#306 #554130
>>554096
Ну лучше сделать их наследниками класса Юнит, и в метод Атака пихать разные реализации СтрелятьСКалаша ЕбашитьЛопатой СтрелятьСнарядом
#307 #554131
>>554107
Нууууууу, асинхронные (которые паралельно основному коду выполняются) функции обычно вызывают замыкания.
#308 #554134
>>554096

>SOLID


Статьи с википедии подойдут?
#309 #554136
>>554134
Мартина почитай, много нового узнаешь заодно. Без чего чем-то лучше макаки стать сложно
#310 #554146
>>554136
Окей. Речь идёт, в первую очередь, о его "Чистом коде"?
#311 #554147
>>554146
Ноуп.
"Быстрая разработка программ. Принципы, примеры, практика", чистый код лучше потом читать.
#312 #554148
>>554147
Спасибо.
#313 #554154
>>553959
Вау, спасибо! Я бы не додумался сам лол.
#314 #554168
>>554090
зачем мне писать аррай(кей), чтобы получить валью, если я могу просто написать валью? мне кажется, ты хуйню несешь.
#315 #554182
>>553833

>class Ad ...


>public function getCategories...


>Этот метод никакого отношения к Ad по моему не имеет.


Твиг не понимает статические методы, поэтому мне приходится городить обычные методы объекта.
Не хотелось создавать объект Категория и передавать его в представление только ради того чтобы получить список категорий, поэтому положил метод в класс объявлений.
Больше ничего не могу придумать, кроме как получить этот список в контроллере и передать массивом в виде переменной в представление.
#316 #554187
Поясните, как сделать так?

https://ideone.com/H95YQH
#318 #554199
>>554187
Не понимаю, что тебе нужно. Новый массив?
#319 #554208
Аноны, поясните плиз. Когда и для чего нужен REST? какая от него реально польза?
#320 #554210
>>554208
Правильная работа с HTTP запросами, в темные времена все запросы были вида profile.php?user=delete и подобные ужасы.
#321 #554213
>>554199
Чтобы при генерации массива вставляло букву. Кароче, алфавитный указатель.
#322 #554218
>>554213
foreach ($array as $element) {
...
Если (первая буква текущего эл. != первой букве предыдущего) {напечатать первую букву текущего элемента}
...
}
23 Кб, 600x312
#323 #554226
>>554218

>первая буква текущего эл. != первой букве предыдущего


НЕПОНИМАТЬ
https://ideone.com/A41FWM
#324 #554237
>>554051
Капитал, чтобы больше не работать на дядю.
Например, франшиза Пятерочки входит лямов в 10 (сама франшиза + аренда + отделочные работы). Доход - 500к-2кк в месяц. Средняя окупаемость - 1.5 года. Процент разорения - 5%.
#325 #554241
>>553494
Новосибирск, а что? Надеюсь не поздно ответил.
134 Кб, 1280x720
#327 #554246
Прикиньте аноны, я то раньше думал, что в объекте можно только редактировать поля, причем которые ты описал в классе А нихуя, оказывается можно как в массиве добавлять туда дополнительные поля по желанию.
http://ideone.com/tI95se

>>554226
https://ideone.com/r8M9rg

Держи маленькая попрошайка :3 Думаю что есть решение и поизящнее, но какой вопрос, такой и ответ.
#328 #554323
>>554168

Очевидно это нужно когда у тебя есть $key и $array а $value надо найти. Если это ты вместо [] испольовал цикл то перечитай урок про массивы ибо тема важная и надо с ней разобраться. Ну и код не забудь показать на проверку.

>>554182

> Больше ничего не могу придумать, кроме как получить этот список в контроллере и передать массивом в виде переменной в представление.


Так и надо. А то что твиг не позволяет, может и хорошо, чтобы ты код из контроллера не тащил во вью.
#329 #554330
Во многих вакансиях требуют знание линукса, поэтому решил все же накатить себе на виртуалку это чудо. Какая сборка наиболее распространена, как ос для предприятий/разработчиков? Какую ставить то?!
#330 #554332
>>554330
Если ты продвинутый пользователь, то Arch Linux. Если ты домохозяйка, то Ubuntu.
#331 #554333
>>554332
продвинутый пользователь чего именно?
#332 #554338
>>554330
Самая популярная Ubuntu. Оп рекомендует Debian. У него есть большая паста на эту тему.
#333 #554339
>>554338
спасибо, а где её искать? эту пасту, на гите не видно
#334 #554344
>>554339
У меня только старый версия есть.
https://www.evernote.com/shard/s510/sh/e19231a9-a192-4282-920d-7513d940d5fc/345117e726392e102fe54c5e98354ef5
Eще много хороших гайдов наложено на digitalocean.
#335 #554352
>>554339

https://gist.github.com/codedokode/420c8c12a1edae25f0ec

Ubuntu основана на debian так что многое из пасты и к ней относится.
2133 Кб, 2560x1600
Статические методы? #336 #554362
Анон, есть необходимость собирать кучу функций с примитивным функционалом и некоторыми общими константными строковыми параметрами, как-то так:

class Foo{
static $bar1 = 'http://blablabalabla/;
static $bar2 = '&param=lalalala';

public static function fn1($a){
echo $this->bar1 . $a . $this->bar2;
}
public static function fn2($a,$b){
echo $this->bar1 . ucfirst($a) . $b . $this->bar2;
}
...

};

Стоит ли так делать?
16 Кб, 299x265
#337 #554365
>>554246
Как скриптик прикрутить сюда? :-)
https://ideone.com/hYKpS0
#338 #554370
>>554210
спасибо
#339 #554380
>>554362

>$this->


не будет работать в статик методе, делай self::$bar1, а если эти переменные не будут меняться, то лучше константы:

>const BAR1

1254 Кб, 2560x1440
#340 #554381
>>554380
Спасибо, а вообще насколько хорошая идея иметь подобный класс для конструирования строк?
38 Кб, 600x524
#341 #554434
>>554365
>>554246
Всё заработало: $post->post_title

Спасибо!
#342 #554437
>>554246

> Прикиньте аноны, я то раньше думал, что в объекте можно только редактировать поля, причем которые ты описал в классе А нихуя, оказывается можно как в массиве добавлять туда дополнительные поля по желанию.


Жаль с методами так делать нельзя, исключая костыли типа runkit
#343 #554445
оп, блять, объясни уже этим тупым хуесосам, что объект это не массив с методами
#344 #554518
С задачей создания счетчика посещений объявления я решил остановиться на следующем решении.
Использовать memcached, сохранять туда сериализованный массив вида array('page_id'=>1234, 'ip'=>127.0.0.1). В качестве ключа использовать хеш этой сериализованной строки.
Таким образом, я получаю уникальный ключ (id, ip), и смогу засчитывать только уникальные посещения. Вопрос только в том, сколько времени я смогу хранить историю посещений в memcached, то есть как часто мне его чистить. Наверное придется раз в сутки, чтобы не захламлять память. Обновлять счетчик в базе каждые 5/10/20... минут (И создать доп.таблицу с историей апдейтов счетчика, чтобы удалять из кеша только сохраненные в базу просмотры).

Так что абсолютной уникальности к сожалению таким способом не добиться, ведь я теряю историю просмотров каждые 24 часа. В идеале хотелось бы, чтобы счетчик засчитывал только абсолютно новых посетителей за все время (неделю), чтобы пользователь видел в кабинете объективную статистику, защититься от накрутки. Например гнусные риелтеры, посредники и прочие унтерки будут по много раз просматривать объявление, а их просмотры продавцу вообще-то не уперлись.
Наверное, для реализации абсолютно точного счетчика лучше бы хранить историю через какой-нибудь redis, но я не пока не в теме, и не хочется подключать множество лишних дополнений, если memcached уже есть то предпочтительнее на нем и реализовать.

Еще в memcached мне не понравилось отсутствие возможности хранить сложные структуры данных. (Или я что-то упустил?)
Непонятно, по каким ключам брать из него только действительно необходимые данные. Вижу пока только возможность загрузить все, а потом в цикле php ходить и фильтровать ключи по какому-то префиксу.

Всякие метрики и аналитики прикручивать неохота, сайт всегда должен быть автономным.
#345 #554521
>>554437
__call(), также наверно можно через reflection
#346 #554524
>>554521

$obj = new stdClass();
$obj->callback = function() {
print "HelloWorld!";
};
$obj->callback->__invoke();

http://stackoverflow.com/questions/4535330/calling-closure-assigned-to-object-property-directly
4 Кб, 245x58
max #347 #554532
пацаны. я не знаю, как мне быть. в чем лучше делать анимацию в html, выбирать css либо js. я уже просто не выдерживаю, читаю книги по js, там про анимацию ни слова. лажу по туториалам, а там пиздец какой-то. догнать до конца не могу.
что же выбрать? я иссяк.
пикрандом
я там тред создал, но он взлетит и пиздец
#348 #554537
>>554532
Тебе лучше поесть говна, аутист ебучий.
#349 #554538
>>554537
да рот закрой блядина тупорылая, съебалась под шконку
#350 #554547
>>554518

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

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

> сохранять туда сериализованный массив вида array('page_id'=>1234, 'ip'=>127.0.0.1). В качестве ключа использовать хеш этой сериализованной строки.


Нафига что-то сериализовать, если можно сделать ключ вида

visit:1234:127.0.0.1

а класть туда пустую строку или единичку.

> Обновлять счетчик в базе каждые 5/10/20... минут (И создать доп.таблицу с историей апдейтов счетчика, чтобы удалять из кеша только сохраненные в базу просмотры).


А на большом числе объявлений и просмотров этот скрипт не станет медленным? Ты ведь пока не тестировал сколько записей в секунду может переварить база? Это может стать узким местом.

Вообще это число и есть ключевой фактор при выборе решения: если база может пережевать нужное число операций то и заморачиваться с мемкешем смысла нет. По моему, типичные цифры для MySQL это сотни транзакций в секунду и несколько тысячи строк в секунду. Это на магнитных дисках, на SSD я не мерял.

И мне интересен алгоритм обновления данных в БД: вот есть у тебя допустим 100 000 объявлений и 5 000 просмотров за 5 минут, а пок акому алгоритму ты данные будешь переносить в базу? Тут очень много подводных камней.

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

> ведь я теряю историю просмотров каждые 24 часа.


Тогда надо продлить время жизни в кеше.

> Еще в memcached мне не понравилось отсутствие возможности хранить сложные структуры данных.


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

Еще стоит помнить что кеш лучше всего работает с данными небольшого объема.

> Всякие метрики и аналитики прикручивать неохота, сайт всегда должен быть автономным


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

Насчет автономности это хорошо но иногда цена (на разработку и поддержку) такой автономности очень высока.

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

Но я бы советовал и мемкеш изучить как следует. ну и конечно надо понимать общие концепции: почему мемкеш легко масштабируется а mysql нет, что стоит и что не стоит хранить в кеше и тд.
#350 #554547
>>554518

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

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

> сохранять туда сериализованный массив вида array('page_id'=>1234, 'ip'=>127.0.0.1). В качестве ключа использовать хеш этой сериализованной строки.


Нафига что-то сериализовать, если можно сделать ключ вида

visit:1234:127.0.0.1

а класть туда пустую строку или единичку.

> Обновлять счетчик в базе каждые 5/10/20... минут (И создать доп.таблицу с историей апдейтов счетчика, чтобы удалять из кеша только сохраненные в базу просмотры).


А на большом числе объявлений и просмотров этот скрипт не станет медленным? Ты ведь пока не тестировал сколько записей в секунду может переварить база? Это может стать узким местом.

Вообще это число и есть ключевой фактор при выборе решения: если база может пережевать нужное число операций то и заморачиваться с мемкешем смысла нет. По моему, типичные цифры для MySQL это сотни транзакций в секунду и несколько тысячи строк в секунду. Это на магнитных дисках, на SSD я не мерял.

И мне интересен алгоритм обновления данных в БД: вот есть у тебя допустим 100 000 объявлений и 5 000 просмотров за 5 минут, а пок акому алгоритму ты данные будешь переносить в базу? Тут очень много подводных камней.

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

> ведь я теряю историю просмотров каждые 24 часа.


Тогда надо продлить время жизни в кеше.

> Еще в memcached мне не понравилось отсутствие возможности хранить сложные структуры данных.


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

Еще стоит помнить что кеш лучше всего работает с данными небольшого объема.

> Всякие метрики и аналитики прикручивать неохота, сайт всегда должен быть автономным


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

Насчет автономности это хорошо но иногда цена (на разработку и поддержку) такой автономности очень высока.

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

Но я бы советовал и мемкеш изучить как следует. ну и конечно надо понимать общие концепции: почему мемкеш легко масштабируется а mysql нет, что стоит и что не стоит хранить в кеше и тд.
#351 #554551
>>554538
Я всё думаю, каким же надо быть тупым, чтобы не понимать, как работает анимация в js и, что самое важное, не найти об этом информацию в сети.
Мамкин строитель лендингов обосрался, да?
#352 #554554
>>554551

Что ты забыл в нашем треде для начинающих, умник?
#353 #554560
>>554554
Это PHP тред, дурачок.
661 Кб, 853x480
#354 #554561
ОП, помоги. В разделе "Повторим" делаю задачку где нужно вывести сумму в текстовом виде. http://ideone.com/uQ9xG

Вроде и кусок кода есть и подсказки, а я банально не понимаю с чего начать.

Как я понял, в том коде в самому конце используется только одна функция, та которая первая, а их всего 3. Получается я должен в первой функции заюзать две остальные?

Также обьясни, вот в первой функции нужно подать четыре значения $number, $word1, $word2, $word5, а где я их должен взять если по идее я должен код редактировать только внутри функций? понимаю, что можно самому доделать, но тогда нет смысла показывать где писать код

Да и вообще зачем аж 4 значения? Вроде как на вход функции поступает число, мы находим две последние цифры каким-то образом узнаем, что конкретно подходит "рубля рублей рубль" и возвращаем нужное слово. Не?
Аноним #355 #554563
http://ideone.com/NSDqx1

все правильно сделал?
#356 #554567
>>554563
Цифры нереальные просто.
#357 #554570
>>554563
А если надо будет сменить количество долларов или курс, то рубли тоже переписывать придётся. Поразмышляй, зачем нужны переменные.
87 Кб, 560x305
#358 #554571
>>554563
Зачем вообще вводить переменные, если ты ими не пользуешься?
#359 #554575
>>554561

слова это вариант написания например «слон», «слона», «слонов». таким образом функция может склонять любые слова а не только рубли.
#360 #554576
>>554563
Я надеюсь ты не толстишь, а то я бы кекнул.
#362 #554581
>>554579
Вот теперь +50 ЕХР
Аноним #363 #554583
>>554567
>>554570
>>554571
>>554576
>>554579
ну наверно я только учусь, и нуб в ваших РНР.
#364 #554604
>>554581
Я пофиксил за того анона. Не надо было этого делать.

>>554583
Теперь решай более сложные задачки.
#365 #554612
http://ideone.com/ifhcBs
Подскажите пожалуйста, в чем ошибка в 3 строке?
#366 #554617
>>553815

>$word1 = array('Чудесных', 'Суровых', 'Занятных', 'Внезапных');


>$word2=array('слов', 'зим', 'глаз', 'дней', 'лет', 'мир', 'взор');


>$word3 =array('прикосновений', 'поползновений', 'судьбы явлений','сухие листья', 'морщины смерти', 'долины края', 'замены нету', 'сухая юность', 'навек исчезнув');



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

>function getPoem($word)


Ставь PHPDoc @param с типом для принимаемого аргумента:

>echo $value." ";


В функции так не делай. Функция должна возвращать результат, а не заниматься его выводом. Выводом заниматься - задача клиента функции. Таким образом твой код можно будет повторно использовать.
#367 #554634
>>554547

>мемкеш это кеш, а не постоянное хранилище


Я в курсе, но данные по посещениям за 5-20 минут не являются критически важными, поэтому можно пренебречь возможностью потери таких данных.

>учитывая что это учебная задача, где все должно быть «правильно», это не очень хорошо


И к чему это? Не использовать мемкеш, потому что он может потерять данные по просмотрам? Я не понял, к чему ты это написал. Я буду использовать memcached, не вижу альтернатив.

>Нафига что-то сериализовать


Да, протупил.

>почему мемкеш легко масштабируется а mysql нет


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

>что стоит и что не стоит хранить в кеше


Часто запрашиваемые ресурсы : html, большие картинки, результаты медленных или частых запросов к бд.
Но эту тему я еще не разбирал. Я хочу сделать счетчик, потом буду думать, что еще закешировать.
В нашем случае со счетчиком: временные данные, которые не жалко потерять и невыгодно с точки зрения производительности часто дергать базу для их обновления.

>вот есть у тебя допустим 100 000 объявлений и 5 000 просмотров за 5 минут, а пок акому алгоритму ты данные будешь переносить в базу? Тут очень много подводных камней


Очевидно буду делать мультиинсерт новых объявлений, используя транзакцию, как ты советовал здесь >>550423
Я не пропускаю то что ты пишешь, просто у меня не идеальная память, я не могу запомнить с первого раза, систематизировать и проанализировать огромные объемы новой и сложной информации.
Для инсертов использовать синтаксис через запятую INSERT INTO advertisement (title, description, ...) VALUES (первая запись), (вторая запись), ...
Плохим решением будет инсертить каждую запись в цикле.
Для апдейтов сначала сгруппировать по кол-ву просмотров, и обновлять всю группу одним запросом UPDATE <таблица счетчиков> SET views_count = views_count + <кол-во просмотров> WHERE id IN (<id сущностей с одинаковым кол-вом просмотров>), как написано в статье мейлру.

>Тут очень много подводных камней


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

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

>Сначала попробовали реализовать «в лоб». Мы создали в таблице сущности поле views_count


Я тоже так сделал с самого начала, пока там default 0.

>Подумали-подумали, и решили, что количества просмотров объявлений (views_count) в листингах нам не нужны, а нужны они нам только в админке и в личном кабинете пользователя. А значит и не зачем это поле хранить в таблице сущности


У меня наоборот, никаких "листингов" не предвидится (хотя кто знает). Счетчик будет выводиться именно при просмотре страницы объявления, следовательно принадлежить к сущности объявления.
Ага, впрочем, в рабочем кабинете (который я еще не делал), как раз будет такой список "мои объявления", и там это число обязательно должно выводиться. По моей логике это лишний раз подтверждает, что счетчик принадлежит к сущности объявления, но может я ошибаюсь.
С другой стороны, во время апдейтов будут блокировки таблицы на выборку (пусть только конкретных строк в innodb, все равно это будет тормозить).
Значит да, нелишним будет перенести счетчик в отдельную таблицу. Ок, сделаю миграцию.

>теперь появилась очередь из апдейтов этой новой таблицы


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

>Еще один важный трюк, который мы применили — это отказались от транзакций MySQL и реализовали свою альтернативу для работы с таблицей-окном.


Ловко. Возьму на заметку.

>Какие альтернативы мы рассматривали


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


И я о том же.

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

Хорошо, попробую сделать так.
Что можешь сказать о триггерах и процедурах? Стоит ли их изучить, или после вставки в эту временную таблицу делать еще один запрос count, и если кол-во записей окажется больше допустимого, запустить из php запрос на обновление?
Очевидно, нужен еще класс для счетчика. Да, тут есть над чем подумать.
#367 #554634
>>554547

>мемкеш это кеш, а не постоянное хранилище


Я в курсе, но данные по посещениям за 5-20 минут не являются критически важными, поэтому можно пренебречь возможностью потери таких данных.

>учитывая что это учебная задача, где все должно быть «правильно», это не очень хорошо


И к чему это? Не использовать мемкеш, потому что он может потерять данные по просмотрам? Я не понял, к чему ты это написал. Я буду использовать memcached, не вижу альтернатив.

>Нафига что-то сериализовать


Да, протупил.

>почему мемкеш легко масштабируется а mysql нет


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

>что стоит и что не стоит хранить в кеше


Часто запрашиваемые ресурсы : html, большие картинки, результаты медленных или частых запросов к бд.
Но эту тему я еще не разбирал. Я хочу сделать счетчик, потом буду думать, что еще закешировать.
В нашем случае со счетчиком: временные данные, которые не жалко потерять и невыгодно с точки зрения производительности часто дергать базу для их обновления.

>вот есть у тебя допустим 100 000 объявлений и 5 000 просмотров за 5 минут, а пок акому алгоритму ты данные будешь переносить в базу? Тут очень много подводных камней


Очевидно буду делать мультиинсерт новых объявлений, используя транзакцию, как ты советовал здесь >>550423
Я не пропускаю то что ты пишешь, просто у меня не идеальная память, я не могу запомнить с первого раза, систематизировать и проанализировать огромные объемы новой и сложной информации.
Для инсертов использовать синтаксис через запятую INSERT INTO advertisement (title, description, ...) VALUES (первая запись), (вторая запись), ...
Плохим решением будет инсертить каждую запись в цикле.
Для апдейтов сначала сгруппировать по кол-ву просмотров, и обновлять всю группу одним запросом UPDATE <таблица счетчиков> SET views_count = views_count + <кол-во просмотров> WHERE id IN (<id сущностей с одинаковым кол-вом просмотров>), как написано в статье мейлру.

>Тут очень много подводных камней


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

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

>Сначала попробовали реализовать «в лоб». Мы создали в таблице сущности поле views_count


Я тоже так сделал с самого начала, пока там default 0.

>Подумали-подумали, и решили, что количества просмотров объявлений (views_count) в листингах нам не нужны, а нужны они нам только в админке и в личном кабинете пользователя. А значит и не зачем это поле хранить в таблице сущности


У меня наоборот, никаких "листингов" не предвидится (хотя кто знает). Счетчик будет выводиться именно при просмотре страницы объявления, следовательно принадлежить к сущности объявления.
Ага, впрочем, в рабочем кабинете (который я еще не делал), как раз будет такой список "мои объявления", и там это число обязательно должно выводиться. По моей логике это лишний раз подтверждает, что счетчик принадлежит к сущности объявления, но может я ошибаюсь.
С другой стороны, во время апдейтов будут блокировки таблицы на выборку (пусть только конкретных строк в innodb, все равно это будет тормозить).
Значит да, нелишним будет перенести счетчик в отдельную таблицу. Ок, сделаю миграцию.

>теперь появилась очередь из апдейтов этой новой таблицы


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

>Еще один важный трюк, который мы применили — это отказались от транзакций MySQL и реализовали свою альтернативу для работы с таблицей-окном.


Ловко. Возьму на заметку.

>Какие альтернативы мы рассматривали


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


И я о том же.

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

Хорошо, попробую сделать так.
Что можешь сказать о триггерах и процедурах? Стоит ли их изучить, или после вставки в эту временную таблицу делать еще один запрос count, и если кол-во записей окажется больше допустимого, запустить из php запрос на обновление?
Очевидно, нужен еще класс для счетчика. Да, тут есть над чем подумать.
#368 #554639
>>554634

>Я буду использовать memcached, не вижу альтернатив.


Редис же. Он умеет бэкапить на диск.
Или можно просто парсить логи сервера раз в n секунд. Чем вообще будет заниматься отдельный скрипт по крону.

мимо нихуя не специалист
Я ведь правильно мыслю, ОП?
#369 #554640
>>554246
Если метод __set() в классе стоит, то такие трюки у тебя не выйдут. В любом случае напрямую в класс свойства присваивать - плохой стиль программирования.
#370 #554642
>>554437
>>554524
Костыли какие-то, лучше делать так:
https://ideone.com/qFsffd
#371 #554653
>>554634

>>почему мемкеш легко масштабируется а mysql нет


> Только что посмотрел в википедии, что такое масштабируемость.



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

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

Оно масштабируется примерно так: ты делаешь функцию, которая по ключу генерирует число от 1 до N и сохраняешь/загружаешь данные на сервер с соответствующим номером. То есть условно говоря, ключ «a» хранится на сервере 1, а «b» на сервере 2, и нагрузка
распределяется между ними.

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

В случае с mysql все не так. Данные в таблицах связаны друг с другом, а сами таблицы связаны внешними ключами. Ты можешь делать выборки как по таблице, так и по нескольким (с помощью джойна). И хотя есть решения (вроде slave-master репликации или mysql cluster) но они из-за этих особенностей (необходимость синхронизации данных) не могут получить такой выигрыш от масштабированяи который может иметь мемкеш и не могут масштабироваться больше чем на несколько серверов.

То есть именно простота мемкеша и дает ему возможность масштабирования.

>>что стоит и что не стоит хранить в кеше


> Часто запрашиваемые ресурсы : html, большие картинки,


Нет, так как для этого есть другие кеши (например файловый кеш ОС) и ты будешь зря их дублировать.

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

http://lib.custis.ru/images/6/6d/WebAppCache.pdf

(по названию можно наверно найти и виде этого доклада)

Чтобы хорошо разбираться в этом надо в том числе понимать как устроен веб-сервер и операционная система.
#371 #554653
>>554634

>>почему мемкеш легко масштабируется а mysql нет


> Только что посмотрел в википедии, что такое масштабируемость.



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

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

Оно масштабируется примерно так: ты делаешь функцию, которая по ключу генерирует число от 1 до N и сохраняешь/загружаешь данные на сервер с соответствующим номером. То есть условно говоря, ключ «a» хранится на сервере 1, а «b» на сервере 2, и нагрузка
распределяется между ними.

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

В случае с mysql все не так. Данные в таблицах связаны друг с другом, а сами таблицы связаны внешними ключами. Ты можешь делать выборки как по таблице, так и по нескольким (с помощью джойна). И хотя есть решения (вроде slave-master репликации или mysql cluster) но они из-за этих особенностей (необходимость синхронизации данных) не могут получить такой выигрыш от масштабированяи который может иметь мемкеш и не могут масштабироваться больше чем на несколько серверов.

То есть именно простота мемкеша и дает ему возможность масштабирования.

>>что стоит и что не стоит хранить в кеше


> Часто запрашиваемые ресурсы : html, большие картинки,


Нет, так как для этого есть другие кеши (например файловый кеш ОС) и ты будешь зря их дублировать.

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

http://lib.custis.ru/images/6/6d/WebAppCache.pdf

(по названию можно наверно найти и виде этого доклада)

Чтобы хорошо разбираться в этом надо в том числе понимать как устроен веб-сервер и операционная система.
#372 #554659
>>554634

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


Это в общем правильная мысль.

> Очевидно буду делать мультиинсерт новых объявлений,


А как ты будешь собирать данные из мемкеша? Там ведь нету запроса вроде SELECT FROM table.

> Других источников знаний кроме гугла и этого треда у меня нет.


Я напишу про подводные камни когда увижу алгоритм, абстрактно трудно говорить.

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

> Они решили использовать еще одну таблицу типа MEMORY, о которых я слышал


Это таблица которая хранится только в памяти и потому быстро работает. Обычные таблицы не так быстры так как при коммите транзакции mysql ждет подтверждения что данные записаны на диск (так как она отвечает за их сохранность).

> Что можешь сказать о триггерах и процедурах? Стоит ли их изучить


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

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

> Стоит ли их изучить, или после вставки в эту временную таблицу делать еще один запрос count,


Я думаю если на каждую вставку делать запрос COUNT то мы можем получить не ускорение, а замедление. Точнее можно будет сказать когда увидим алгоритм.
#373 #554662
>>554639

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

>>554246

Не надо добавлять свойства в объекты. Суть классов как раз в том что список свойств известен. Как можно надежно писать код если непонятно какие свойства есть у объекта, а каких нет?

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

Я считаю это ошибка проектирования, что PHP такое разрешает.

>>554437

И не надо.

>>554524

Кошмарный код. Почему ты используешь объект там где лучше подойдет массив?
#374 #554669
>>554634

> С другой стороны, во время апдейтов будут блокировки таблицы на выборку (пусть только конкретных строк в innodb, все равно это будет тормозить).


> Значит да, нелишним будет перенести счетчик в отдельную таблицу.



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

>>Еще один важный трюк, который мы применили — это отказались от транзакций MySQL и реализовали свою альтернативу для работы с таблицей-окном.


> Ловко. Возьму на заметку.


Однако в твоем проекте это будет лишнее усложнение на мой взгляд. Опять же прежде чем такие вещи делать надо как-то проверить и измерить разницу.
#375 #554671
>>554639

> парсить логи сервера раз в n секунд


Вот это как раз неэффективно, на нагруженных сервисах аксесс логи часто отключают. Плюс формат логов может меняться, это какое-то извращение получается. Плюс когда серверов много надо еще как-то собирать с них логи.
#376 #554682
Что-то на шаблоне Интерпретер я уже перестаю понимать, что печатаю...
#377 #554688
>>554617
какая еще клиента функции? вот так что ли надо было писать? или аж целый отдельный класс делать ради красивости?
function getPoem($word)
{
$length = count($word)-1;

$rand = rand(0, $length);

foreach($word as $key=>$value){

if($key == $rand && array_key_exists($rand, $word)){
return $word[$key];
}

}
}

echo getPoem($word1).' ';
#378 #554693
>>554688

А зачем там цикл? цикл не нужен для получения массива по ключу.

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

> какая еще клиента функции


Имеется в виду тот кто вызывает функцию
#379 #554760
>>554642
а что все-таки насчет магии, выглядит вроде бы удобнее
https://ideone.com/9ccJmc
бэд практис?
135 Кб, 581x371
#380 #554765
Почему вы учите пыху?

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

Каждый раз если я где-то скажу, что я учу php, то мне постоянно советуют учить что-то другое, например сишарп ASP.NET, но я все равно учу php, потому что мне я начитался, что он легкий хотя мне совсем так не кажется, после задачек ОПа, много вакансий, к тому же здесь уютно, понимаешь, что этот язык учат многие и по идее ты не проебешься, ОП помогает, да и четко знаешь, что нужно выучить, а вот другие треды и языки и я совсем не представляю как там все устроено и не было особого желания, но каждый раз когда мой выбор поливают говном, то у меня с каждым разом закладывается вопрос, а правильно ли я все делаю? Сделал ли я правильный выбор?

Вы можете ответить на мои вопросы и обосновать их?
#381 #554767
>>554765

>мой выбор поливают говном


Тебя троллят.
#382 #554777
>>554765
Быдло самоутверждается, очевидно же. Большинство местных петухов не знают ни одного языка, а заходят сюда посраться.
#383 #554782
Ну не только ведь быдло и мимоходы поливают дерьмом пыху. Еще в пабликах в Вконтактике для программистов.
#384 #554813
>>554653
Я понял насчет масштабирования.

>Кешируют то, что требует тяжелых вычислений, и то, к чему идут частые обращения


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

>>554659

>как ты будешь собирать данные из мемкеша


Вот я и говорил, что неудобно, и мейлрушники тоже отметили это в той статье.
Учитывая, что мне нужно сохранять достаточно короткую строку, храним все данные в ключе вида
visit|1234|127.0.0.1 то есть префикс|page_id|ip
Значения не нужны, кладем пустую строку.
Из мемкеша берем все ключи getAllKeys, в цикле отсеиваем лишние и парсим эту строку, выбирая только идентификаторы.
Подставляем в запрос в цикле.
Удаляем ключи из мемкеша. Но так теряется возможность отслеживать уникальных посетителей. Если я просто продлю время жизни элемента, то не знаю как отличить те просмотры, что уже были занесены в базу. Ну и мы уже обсудили, что мемкеш не нежно использовать как хранилище.

>главное что они сделали — это уменьшили число транзакций за счет сбора (аггрегации) данных и обновления их большими пачками по расписанию


Попытался это реализовать для скрипта, обновляющего счетчик.
https://gist.github.com/nsdvw/58a7d5385a118a5b4306
Давай уже свои камни.

>запрос COUNT


Это я к тому, что в статье при наполнении таблицы MEMORY до определенного количества записей запускалась скорее всего какая-то процедура.
Я не использую процедуры, значит я должен из php узнавать кол-во записей в этой таблице. Но это в случае, если нам нужно обновление счетчика в режиме реального времени, и при использовании таблицы типа memory.
Поскольку мы вроде бы опять переключились на memcached, то об этом можно забыть, просто запускаем вышеупомянутый скрипт по расписанию.
>>554669

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


Да я уже понял, что ты меня заставишь решить задачу тремя (в лучшем случае) способами.
Придется смириться, тем более что ты прав. Протестовать против такого дотошного изучения заставляет только нехватка времени.
#384 #554813
>>554653
Я понял насчет масштабирования.

>Кешируют то, что требует тяжелых вычислений, и то, к чему идут частые обращения


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

>>554659

>как ты будешь собирать данные из мемкеша


Вот я и говорил, что неудобно, и мейлрушники тоже отметили это в той статье.
Учитывая, что мне нужно сохранять достаточно короткую строку, храним все данные в ключе вида
visit|1234|127.0.0.1 то есть префикс|page_id|ip
Значения не нужны, кладем пустую строку.
Из мемкеша берем все ключи getAllKeys, в цикле отсеиваем лишние и парсим эту строку, выбирая только идентификаторы.
Подставляем в запрос в цикле.
Удаляем ключи из мемкеша. Но так теряется возможность отслеживать уникальных посетителей. Если я просто продлю время жизни элемента, то не знаю как отличить те просмотры, что уже были занесены в базу. Ну и мы уже обсудили, что мемкеш не нежно использовать как хранилище.

>главное что они сделали — это уменьшили число транзакций за счет сбора (аггрегации) данных и обновления их большими пачками по расписанию


Попытался это реализовать для скрипта, обновляющего счетчик.
https://gist.github.com/nsdvw/58a7d5385a118a5b4306
Давай уже свои камни.

>запрос COUNT


Это я к тому, что в статье при наполнении таблицы MEMORY до определенного количества записей запускалась скорее всего какая-то процедура.
Я не использую процедуры, значит я должен из php узнавать кол-во записей в этой таблице. Но это в случае, если нам нужно обновление счетчика в режиме реального времени, и при использовании таблицы типа memory.
Поскольку мы вроде бы опять переключились на memcached, то об этом можно забыть, просто запускаем вышеупомянутый скрипт по расписанию.
>>554669

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


Да я уже понял, что ты меня заставишь решить задачу тремя (в лучшем случае) способами.
Придется смириться, тем более что ты прав. Протестовать против такого дотошного изучения заставляет только нехватка времени.
#385 #554843
>>554612
or die() вызывается в той же строке.
У тебя ниже правильно написано.
#386 #554845
>>554765
Модно ругать вот и ругают, как ТНН, паркуристы и прочая шелупонь лезет, потому что модно.
#387 #554857
>>554760
Если у тебя в классе множества встроенных методов нет, то пойдет, конфликтов не будет.
Плюс при чтении кода
$functionHolder->run('printNumbers', [12, 'попугай']);

сразу понятно, что функция не встроенная и что-то тут не так, программисту придеться смотреть метод run, и он поймет, что функция создается где-то еще, проследит всю цепочку создания.

$functionHolder->printNumbers(12, 'попугай');
Тут он подумает, что функция встроена в класс и будет на нее полагаться, что может привести к непредсказуемым последствиям в крупных проектах.
#388 #554867
>>554760

Зачем это нужно? Чтобы код было сложнее читать, так как непонятно какие функции в объекте есть, а каких нет? Приведи пример где твой код принесет пользу.

Это ведь код не для реальной задачи, а просто от балды написано.
#389 #554868
>>554760

Конкретно в твоем случае код можно переписать так:

function printNumbers($number, $string) {
echo "Номер $number";
echo "\nСтрока $string";
}

printNumbers(12, 'попугай');

Теперь объясни чем твой код лучше моего если они делают одно и то же, но мой в несколько раз короче и проще читается.
#390 #554871
>>554760

Ну и наконец приведу примеры где магические функции (реализованные через __call) имеют смысл. Обычно это используется в фреймворках. Например в доктрине ты можешь написать так:

$user = $userRepository->findOneByName('Ivan');

И это будет искать в репозитории сущность у которой поле name == 'Ivan'. Тут используется магический метод так как автор доктрины разумеется не знает заранее какие поля будут у твоих сущностей. Аналогично можно писать findOneById, findOneByEmail и тд.

Но такие примеры редкие, если ты не автор фреймворка то тебе скорее всего магические методы не понадобятся. Ну и читабельность и понятность кода очень страдает от них (в случае с доктриной — это описано в документации).
13 Кб, 341x573
#391 #554976
Всем привет. Я совсем ньюфаг, прочитал какой-то учебник и решил перепилить свой интернет магазин (ASP.Net MVC) на php, тоже реализовав мвс. Нашел какие-то видеоуроки по этому, вроде ниче. Но сразу начались проблемы при написании роутера: файл .htaccess просто не работает, что бы я в нем не писал. Следуя советам с гугла, в конфиге апача везде где можно прописал AllowOverride All и все равно не работает. Как быть? Или можно как-то обойтись без этого файла?
#392 #554993
>>554976
Можно обойтись без файла, почитай про конфигурацию веб-сервера. Сама идея твоя....странновата, только ради самообучения стоит мутить.
#393 #555005
>>554993
Тогда такой вопрос, а кошерно вообще делать маршрутизацию обходным путем?

>почитай про конфигурацию веб-сервера


А где это почитать чтоб не сложно для ньюфага?

>идея твоя....странновата


Почему идея странновата? Ну для обучения пока, потом если что как портфолио показать на собеседовании, найти работку, слезть с мамкиной шеи, прийти к успеху.
#394 #555015
>>554976

Покажи конфиг апача и htaccess
#395 #555017
>>551625 (OP)
Посоны, напишите рабочий полный код пример, как доставать пароль из формы, переводить в md5, добавить соль, положить в бд, достать из бд, бурать соль, опять в мд5 и сверить с данными из формы? плз, именно коротенький код-пример нужен, потому что я читаю и нихера представить не могу, именно вот кодик-код напишите плз с этой солью. можно PDO, mysqli - неважно.
#396 #555023
А ниче если я интернет магазин с админкой на слиме сделаю? Просто я кроме слима еще ничего не учил...
#397 #555026
>>555015

>htaccess


AuthType Basic
AuthName admin
require valid-user

AddDefaultCharset utf-8

RewriteEngine on
RewriteBase /
RewriteRule ^(.*)$ index.php

>конфиг апача


https://www.dropbox.com/s/hrx5acjy1hes6yr/Apache-2.2_server.conf?dl=0
#398 #555027
посоны, я нюфаня, который на слиме файлообменник не доделал, как думаете я уже смогу инет-магаз сделать?
#399 #555040
ПОЧЕМУ У МЕНЯ ИМЯ ФАЙЛА В КРАКОЗЯБРАХ СОХРАНЯЕТСЯ - ЭТО НОРМАЛЬНО?
#400 #555045
>>555040
Значит у тебя не совпадает кодировка. Можешь описать свою проблему подробнее, и возможно получишь более подробный ответ.
#401 #555060
Я наверное совсем нуб.
Не понимаю простой вещи... Как в условии задать промежуток, например нужно узнать ровняется ли $a числам от 5 до 7. Я по всякому уже пробовал прописать, все неверно
if ($a == [5-7]){...
неверно же
пробовал переменную задать в виде

$numbers = '/[5-7]/u';
if ($a == [$numbers]){...
все равно не идет
как быть
#402 #555062
>>555040

ОС какая? Винда? Она принимает имена в кодировке cp1251. соответственно твой код должен выглядеть так:

если (винда) {
перевести имя в cp1251;
сохранить под этим именем;
} иначе {
сохранить под именем в кодировке utf-8 (которую ты надеюсь по умолчанию и используешь)
}
#403 #555066
>>555060

> if ($a == [5-7]){...


С точки зрения PHP квадратные скобки значат создание массива. То есть твой код равносилен

if ($a == array(5-7))

5-7 PHP вычислит как выражение, которое равно -2 и получается в итоге

if ($a == array(-2))

То есть идет сравнение $a с массивом содержащим число -2.

> if ($a == [$numbers]){


Та же ерунда, ты сравниваешь $a и массив из 1 элемента содержащий строку.

Почему ты вообще используешь знак равенства? Он используется для проверки на равенство знаений, а тебе надо использовать больше и меньше.
#404 #555067
>>555060

также рекомендую показать решения своих задач на проверку, может тебе еще дадут советы по улучшению.
#405 #555071
>>555066
то есть правильно будет
if(5<$a<7){
?
#406 #555074
>>554813
Бамп теме обновления счетчика посещений через memcached.
Одобряешь алгоритм?
https://gist.github.com/nsdvw/58a7d5385a118a5b4306

Я пока пойду почитаю про редис, мемкеш конечно не годится для долговременного хранения данных, когда нужно отслеживать уникальных посетителей.
#407 #555080
>>555026

После правок конфига Апач перезапускал? Имя файла htaccess написано правильно? В какой папке он лежит?

Да и то что ты скинул по моему не конфиг а только шаблон когнфига. Openserver из него видимо как-то генерирует настоящий конфиг.

Похоже что это ты что-то в настройках опенсервера напутал либо файл htaccess не там создал или не так назвал.

Вообще лучше бы самому ставить Апач и PHP, это не так сложно, но зато ты будешь иметь стандартную конфигурацию. А что там разработчики опенсервера нахимичили, я не знаю, это у них надо спрашивать.
#408 #555103
>>555071

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

Тебе надо писать так:

если a большеравно чем X и a меньшеравно чем Y то ....

Про то как объединять условия с помощью И/ИЛИ написано в уроке про if и кубики.

>>555074

А, я вспомнил одну особенность мемкеша, не знаю в курсе ты или нет:

https://www.adayinthelifeof.nl/2011/02/06/memcache-internals/

Пункт «LRU algorithm»

Мемкеш при старте выделяет фиксированный объем памяти, и при ее нехватке удаляет (eviction) ключи к которым давно не обращались. Это тоже стоит помнить.

> $rawVisits = $memcached->getAllKeys();


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

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

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

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

> if (substr($v, 0, 5) != 'visit') {


Ненадежно, вдруг там есть еще (или будет) 'visitor' или что-то такое. Хотя если у тебя отдельный мемкеш только под посещения, это не так страшно.

> } catch(Exception $e) {


> $connection->rollback();


В таких случаях надо не терять исключение а прокидывать дальше через throw

> $memcached->deleteMulti($rawVisits);


тут надо проверить есть ли у memcached ограничение на длину команды и у клиентской библиотеки ограничения на число параметров. Возможно что есть.

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

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

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

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

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

Ну и в заключение, для того чтобы как следует изучить мемкеш было бы полезно реализовать свой вариант мемкеш-демона на PHP (совместимного со стандартным протоколом мемкеша). Но я понимаю, что времени у тебя на это нет, так что не буду предлагать.
#408 #555103
>>555071

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

Тебе надо писать так:

если a большеравно чем X и a меньшеравно чем Y то ....

Про то как объединять условия с помощью И/ИЛИ написано в уроке про if и кубики.

>>555074

А, я вспомнил одну особенность мемкеша, не знаю в курсе ты или нет:

https://www.adayinthelifeof.nl/2011/02/06/memcache-internals/

Пункт «LRU algorithm»

Мемкеш при старте выделяет фиксированный объем памяти, и при ее нехватке удаляет (eviction) ключи к которым давно не обращались. Это тоже стоит помнить.

> $rawVisits = $memcached->getAllKeys();


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

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

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

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

> if (substr($v, 0, 5) != 'visit') {


Ненадежно, вдруг там есть еще (или будет) 'visitor' или что-то такое. Хотя если у тебя отдельный мемкеш только под посещения, это не так страшно.

> } catch(Exception $e) {


> $connection->rollback();


В таких случаях надо не терять исключение а прокидывать дальше через throw

> $memcached->deleteMulti($rawVisits);


тут надо проверить есть ли у memcached ограничение на длину команды и у клиентской библиотеки ограничения на число параметров. Возможно что есть.

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

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

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

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

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

Ну и в заключение, для того чтобы как следует изучить мемкеш было бы полезно реализовать свой вариант мемкеш-демона на PHP (совместимного со стандартным протоколом мемкеша). Но я понимаю, что времени у тебя на это нет, так что не буду предлагать.
#409 #555106
>>555074

Ну и вообще, очередь в кеше это стандартный способ снижения нагрузки на запись в базу данных, например ее же можно использовать если какие-то логи пишутся в базу, для защиты от перегрузки запросами. За это мы платим некоторым снижением надежности и задержкой между добавлением в очередь и попаданием в базу.
#410 #555112
>>555074

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

Ну то есть ключ вида views:1234 в котором указан id объявления.

Но тут есть риск получить расхождения с реальным числом.

Допустим у нас в базе 20 просмотров, и в очереди на добавление еще 5 (их пока не внесли в базу). Приходит новый пользователь, мы добавляем 6-е посещение в очередь, а также инициализируем счетчик числом из базы (20) и увеличиваем на 1 (21).

Затем запускается скрипт сброса данных в базу, он увеличивает в базе значение до 26 но ключ со счетчиком остается на 21. Вот мы и получили отставание на 5 просмотров.

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

Допустим у нас в базе 20 просмотров, и в очереди на добавление еще 5 (их пока не внесли в базу). Приходит еще 5 пользователей, мы инициализируем счетчик числом из базы (20), 5 раз увеличиваем и имеем на счетчике 25 (а в базе 20, а в очереди 10 просмотров).

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

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

Ты можешь поломать голову над проблемой отображения актуального числа просмотров но не могу обещать что ты его найдешь.
#411 #555127
>>555017
я напишу, если после этого я за тебя и бабу твою ебать буду, идет?
#412 #555131
>>555127
Я еще ночью написал ему, только запостить не мог.

>>555017
http://ideone.com/yfNEOh
#413 #555144
>>553939
Привет, ОП, спасибо большое, что посмотрел мои задачки. Вроде поисправлял:
1) Поиск ошибок - сделал как ты написал, слово (так проще увидеть ошибку), до пробела (1 или больше), потом союз, после которого любой символ кроме букв - потому что не придумал, как иначе границу слова обозначить. В твоём хитром примере ошибок не находит теперь. http://ideone.com/qhTqFM
2) Автоисправление ошибок - не знаю, правильно ли я тебя понял, получилось собрать в массив все правила с функциями, и пройтись по ним циклом, кода сильно меньше не стало, зато теперь нет однообразных вызовов preg_replace_callback. Смущает, что коллбеки эти у меня похожи, но отличаются по тому, что они должны возвращать вместо найденного совпадения -

>fixGrammar('/..../', function () {...});


эту подсказку я совсем не понял, как использовать, может как раз ты имел в виду какую-то универсальную функцию замены вместо кучи коллбеков, но я в ступоре, как это сделать. И как без массива обойтись вообще, если у меня на каждое слово разное правило. Вот что получилось http://ideone.com/jtrD4e
#414 #555155
>>555080
Перезапускал, файл лежит в корне сайта, рядом с индексом и он не txt. Да вот он https://www.dropbox.com/s/k873xkuzlc9g3vl/.htaccess?dl=0
А вот похоже то что опенсервер сгенерировал https://www.dropbox.com/s/5vi3tj4roit5bul/httpd.conf?dl=0

Пару лет назад пытался вручную все опставить и ничего не вышло, тогда я забил. Боюсь, что и сейчас меня это дело выбесит
#415 #555163
Поговорим про нелицеприятные стороны PHP. Я всегда говорил что обработка ошибок в PHP безнадежно сломана и не похоже что ее исправят.

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

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

http://ideone.com/5fopIE

Если мы вместо массива кладем в переменную false то никакой ошибки не происходит. Нормально? Смотрите к чему это приводит на практике: есть неработающий код. Я трачу 10 минут времени на то чтобы найти и исправить баг, попутно удивляясь что никаких ошибок нет, а данные выводятся неверные. А если бы в PHP при такой ситуации вылетало исключение — мне бы не пришлось исправлять этот баг вообще так как тот разработчик что вписал неправильный код увидел бы ошибку и сам ее исправил. Я бы сэкономил 10 минут. И это только сегодня.

Неправильная обработка ошибок съедает ваше время, и я ее вижу во многих проектах на PHP. Вот то, что вы должны использовать:

error_reporting = E_ALL
превращение ошибок в исключения: http://php.net/manual/ru/class.errorexception.php (нормальные фреймворки вроде Slim или Symfony делают это за вас)
fail fast: http://habrahabr.ru/post/218325/

Алсо на сайте PHP этот баг висит с 2006 года, отписался там: https://bugs.php.net/bug.php?id=37676

Алсо, хак: если отключить яваскрипт, то ссылки в гугле открываются в том же окне, а не в новом.
#416 #555164
>>555144

> как иначе границу слова обозначить


Ты про \\b в курсе? Этот символ значит «граница слова», то есть место где с одной стороны стоит буква или цифра, а с другой не буква или цифра.
#417 #555173
Поясните как в YII2 в версии advanced зайти на стартовую страницу, в basic это http://basic/web/index.php а в advanced как?
#418 #555178
>>555173

А по коду посмотреть нельзя?
#420 #555217
Как насчет держать резервный тред на 8ch?
Хотя там наверное тоже cloudflare.
#421 #555233
>>555103

>многопоточность


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

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

>реализовать свой вариант мемкеш-демона


А?
Это тред для начинающих, не увлекайся. Если бы я мог написать сервер, я бы тут не сидел.
#422 #555234
>>555164

>\\b


Чукча не читатель, чукча писатель. Спасибо. А то прочитал старую статью про регекспы и успокоился, там такого не было.
#423 #555256
Почему бы вместо того, чтобы тупо считать число просмотров, не считать среднее время между просмотрами и уже потом его переводить в число просмотров?
#424 #555258
>>555256
Число просмотров 1 переменная. Среднее время между просмотрами сколько переменных?
#425 #555262
>>555258

>Среднее время между просмотрами


>сколько переменных


Одна, же.
#426 #555265
>>555256
Если не нужна точность, и просмотры равномерно распределены между сущностями, то почему бы и нет.
#427 #555279
>>555256

Равномерного распределения не бывает.

Ночью число падает почти до нуля, днем поднимается. В случае с объявлением, которое живет неделю там динамика еще сложнее. Теперь опиши алгоритм вычисления этого числа.
#428 #555287
Ну хуй знает.
Я такой алгоритм где-то видел в дозиметрах где нужно было быстро считать количество попадающих частиц в детектор и БЫСТРО выдавать результат. Он работал лучше чем тупой счет попавших частиц за минуту.
#429 #555288
Оп, посоветуй?
делаю фотогалерею на yii2, прогружаю картинки с помощью pjax.
И вот такая ситуация, например:
Есть экшн, который отображает текущую выбранную картинку и стрелочки для перелистывания, как мне узнать предыдущий и следущий айди, чтобы повесить на эти самые стрелочки?(это чтобы передать айди в контроллер для прогрузки следующей, или предыдущей картинки)

чето не могу сообразить
#430 #555312
Осваиваю ООП.

Классы целесообразно использовать только когда предполагается работа с несколькими объектами этого класса, или даже тогда, когда объект будет всего один?
21 Кб, 768x295
#431 #555322
Правильно ли я действую, или я совсем отшибленный и лучше мне в это не лезть? Как правильно поставить условие, чтобы во второй строке не было повторов?
#432 #555323
>>555322

>скриншот кода на айдеоне


>Правильно ли я действую, или я совсем отшибленный


Я больше склоняюсь ко второму.
#433 #555324
>>555322
повторов чего?
ссылку вбрось, растроман
#434 #555326
>>555323
Лол, действительно.
>>555324
http://ideone.com/gAOpLQ
#435 #555329
>>555326
Ну и что тебя не устраивает? Если тебе не нравится копипаста, можешь упаковать это в функцию.
#436 #555330
верстаю и блюю. неудивительно, что каждого школьника тут пытаются обучить верстке, какой программист на такое подпишется? жиес - это вообще нечто, я чуть с ума не сошел, пока код слайдера разбирал, а в одном плагине вообще зачем-то алерт был прикручен по клику. Сколько же оно времени жрет , я бы уже бэкенд с админкой для трех магазинов и одного файлообменника написал.
#437 #555333
>>555326
Да, кстати, у тебя там ошибка с индексами. В каждом массиве индексов меньше, чем чисел, которые прописаны в mt_rand.
#438 #555336
>>555329
Понял, но как поставить условие, чтобы не было повторов во второй строке?
>>555333
Точно, с нуля же начинается, затупил.
#439 #555338
>>555336
Каких повторов?
#440 #555340
Веб-макаки, вы в гит умеете, или лучше в прыщетред в /s идти?

Есть ветка. Шла параллельно мастеру. Мастер обновлялся, обновлялся, решил вмерджить его себе. Т.к. изменений много, без конфликтов не обошлось. я их хуёво порешал, и теперь, когда я хочу влить свою ветку в мастер, я не могу этого сделать из-за криво решенных конфликтов.
Нужно как-то откатить мою ветку в состояние до мерджа, сохранить мои коммиты, и вмерджить в нее мастер еще раз, грамотно решив конфликты. Как?
#441 #555341
>>551625 (OP)
Аноны, у меня вопрос, проходил первое задание с урока с функциями из шапки. Если у одного из трёх банков, комиссия равна нулю, уместно ли писать просто значение "0" в аргумент? (getCreditTotal($creditSum, 1.03, 0, $payout, 0) Ведь дальше по формуле подсчета общей выплаты, в фунции, будут умножения на этот процент, просто тогда в формуле этой переменной просто не будет?
31 Кб, 258x350
#442 #555342
>>555341
пикча отклеилась
#443 #555346
>>555131
Ахуенно объяснил, ну и что такое config salt? Это просто рандомно генерированный набор символов, как токен что ли?
#444 #555349
>>555341
>>555342
А, сам разобрался, что скажите по коду?
http://ideone.com/Rud3MG
#445 #555350
Почему на идеоне не сделают так, чтобы код копировался без циферок строки?
#446 #555352
>>555338
Ну, чтобы во второй строке не рандомилось то, что уже было выведено в первой.
#447 #555353
Пацаны, срочно!
Еду узнавать на счёт удалённой работы на симфони. Какие то доработки и парсер ы сделать
Сколько денег просит, что бы не послали и не продешивить?
Сам я хуй учился по тредам, полгода в офисе работал, на симфони 3 месяца.
8 Кб, 809x88
#448 #555354
>>555350
дегенерат блять
18 Кб, 509x509
#449 #555359
Реквестирую задачки по массивам. Только без матана, шоб было максимально тупое, но технологически сложное для новичка.
#450 #555363
>>555233

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

==============

Процессор может выполнять параллельно столько потоков инструкций, сколько в нем ядер. На серверах например может стоять два 8-ядерных процессора. В древних компьютерах процессоры были однаядерные, а сейчас даже в смартфонах несколько ядер. Это по той причине, что наращивать скорость работы одного ядра уже не получается, приходится брать количеством.

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

В общем ОС может выполнять программы как бы параллельно даже на одном ядре.

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

В процессе может быть 1 или более потоков (threads, нитей). Их можно создавать на ходу и они могут завершаться. Меньше одного быть не может, если последний поток завершается, то и вся программа завершается тоже, и операционная система забирает выделенную память и другие ресурсы (например закрываются созданные программой сетевые соединения, снимаются блокировки с файлов и тд).

Создание нового потока это если проводить аналогии с PHP, вызов какой-то функции или include какого-то скрипта. То есть программа может взять функцию и запустить ее выполнение отдельным потоком параллельно с основным потоком. В PHP так не делают, PHP программы однопоточные, но так делают в других языках.

Если потоков в процессе несколько, то они все имеют доступ к одной и той же области памяти. То есть если это бы была программа на PHP то все потоки видят одни и те же переменные и функции.

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

-------

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

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

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

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

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

Если провести аналогию, то это огромный супермаркет с всего одной работающей кассой и очередью к ней. Согласись, этот супермаркет мог бы продавать больше?
#450 #555363
>>555233

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

==============

Процессор может выполнять параллельно столько потоков инструкций, сколько в нем ядер. На серверах например может стоять два 8-ядерных процессора. В древних компьютерах процессоры были однаядерные, а сейчас даже в смартфонах несколько ядер. Это по той причине, что наращивать скорость работы одного ядра уже не получается, приходится брать количеством.

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

В общем ОС может выполнять программы как бы параллельно даже на одном ядре.

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

В процессе может быть 1 или более потоков (threads, нитей). Их можно создавать на ходу и они могут завершаться. Меньше одного быть не может, если последний поток завершается, то и вся программа завершается тоже, и операционная система забирает выделенную память и другие ресурсы (например закрываются созданные программой сетевые соединения, снимаются блокировки с файлов и тд).

Создание нового потока это если проводить аналогии с PHP, вызов какой-то функции или include какого-то скрипта. То есть программа может взять функцию и запустить ее выполнение отдельным потоком параллельно с основным потоком. В PHP так не делают, PHP программы однопоточные, но так делают в других языках.

Если потоков в процессе несколько, то они все имеют доступ к одной и той же области памяти. То есть если это бы была программа на PHP то все потоки видят одни и те же переменные и функции.

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

-------

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

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

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

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

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

Если провести аналогию, то это огромный супермаркет с всего одной работающей кассой и очередью к ней. Согласись, этот супермаркет мог бы продавать больше?
#451 #555364
>>555322
Половину задачи сделал. Как сделать условие? Можешь брать случайное число, записывать его в переменную, потом во второй строке генерировать ещё число, сравнивать с первым, чтобы не совпало ( конструкция if (условие) {действие} )...,
Но как то неудобно, правда? Есть функция , возвращающая длину массива, её можно использовать, чтобы знать в каком диапазоне генерировать случайное число.(вдруг в массивах будет сделаешь больше/меньше слов). Есть функция, которая удаляет из массива элемент.
В итоге можно так - выбрали слово из массива, вставили в строку, удалили из массива слово. Потом во второй строке снова выбрали из массива элемент ( старого слова там уже нет, повтора точно не будет) . и так далее.

Наверное можно ещё изящнее, я не знаю, я нубас.
продолжение пасты #452 #555365
>>555233

Много однопоточных процессов

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

В такой системе все гораздо лучше. Если один рабочий застрял на обработке запроса, например ждет данных с диска, или из сети, то другие рабочие продолжают обрабатывать запросы и клиенты не страдают. Более того, операционная система передает процессор тем, кому он нужен и если число рабочих больше числа ядер то процессор оказывается задействован почти на 100%. И это отлично: мы для того и покупали процессор чтобы он выполнял вычисления а не простаивал зря.

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

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

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

По такой схеме работает веб-сервер Апач в режиме mpm-prefork. Он создает определенное число рабочих процессов (пул воркеров - worker pool) и даже умеет создавать новые при повышении нагрузки (или при падении рабочего из-за ошибки) и убивать лишние при снижении. Аналогично работает PHP в сочетании с Апачом: каждый скрипт работает в отдельном процессе.

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

Допустим PHP-скрипт генерирует главную за 200 мс (вполне обычная цифра).

1 рабочий обслуживает 5 запр/сек.
10 рабочих = 50 запр/сек
100 рабочих = 500 запр/сек.
1000 рабочих - тяжело переключаться между ними, много памяти расходуется, так что 5 000 мы можем и не увидеть, а увидим например 1000-3000.

Ну, 500 запросов в секунду это довольно нагруженный сайт с миллионом посетителей в день. Если один сервер такое тянет то это отличное приложение. На практике 500 может и не выйти, так как 100 параллельно работающих скриптов будут создавать 100 параллельных соединений с базой, делать запросы, она может не успеть им всем ответить, и тд, но это ведь не вина Апача, правда? 500 это скорее высокая планка к которой стоит стремиться.

В общем для веба она подходит, если это не совсем хайлоад.

Она не подходит для случаев когда у нас много параллельных слабоактивных соединений. Например у нас сервер который раздает файлы с диска большому числу клиентов на не очень быстрых каналах. Ну к примеру отдача одной картинки занимает 3 секунды (так как у клиента медленный интернет), картинка весит 100 Кб, это значит что:

1 рабочий может обслужить 1/3 запроса в секунду, трафик 33 кб/с (это значит что ты зря заплатил хостеру за гигабитный канал, он используется менее чем на 0.1% ).
10 рабочих - 10/3 = 3.33 запроса в секунду, трафик 330 кб/с
100 рабочих - 33.3 запроса в секунду, трафик 3.3 Мб/с
1000 рабочих - 333 запр/сек., 33Мбита/с, но они будут есть много памяти и операционная система замучается переключать процессор между ними
10 000 рабочих - 3333 запрс/сек мы не получим, получим условно говоря 1000 и 100 Мбит/с.

Смотри, какие печальные цифры: наш Апач на раздаче картинок загружает гигабитный канал лишь на 10% (значит нам надо купить еще 9 дорогущих серверов чтобы загрузить его полностью), жрет тонны памяти (10 000 рабочих × 10 Мб каждый = 100 Гб ), процессор расходуется в основном на переключения контекста, быстрые клиенты не могут скачивать файл на полной скорости.

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

Один многопоточный процесс

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

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

По такой схеме работает mysql: он создает пул потоков, и когда подсоединяется новый клиент, выделяет ему свободный поток, который принмимает и обрабатывает запросы. Также, многие службы и фоновые программы под Windows используют потоки. Апач под Windows тоже может использовать эту схему.

Проблему раздачи статики, описанную выше, это не решает.

Как это описать аналогией, я не знаю.
продолжение пасты #452 #555365
>>555233

Много однопоточных процессов

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

В такой системе все гораздо лучше. Если один рабочий застрял на обработке запроса, например ждет данных с диска, или из сети, то другие рабочие продолжают обрабатывать запросы и клиенты не страдают. Более того, операционная система передает процессор тем, кому он нужен и если число рабочих больше числа ядер то процессор оказывается задействован почти на 100%. И это отлично: мы для того и покупали процессор чтобы он выполнял вычисления а не простаивал зря.

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

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

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

По такой схеме работает веб-сервер Апач в режиме mpm-prefork. Он создает определенное число рабочих процессов (пул воркеров - worker pool) и даже умеет создавать новые при повышении нагрузки (или при падении рабочего из-за ошибки) и убивать лишние при снижении. Аналогично работает PHP в сочетании с Апачом: каждый скрипт работает в отдельном процессе.

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

Допустим PHP-скрипт генерирует главную за 200 мс (вполне обычная цифра).

1 рабочий обслуживает 5 запр/сек.
10 рабочих = 50 запр/сек
100 рабочих = 500 запр/сек.
1000 рабочих - тяжело переключаться между ними, много памяти расходуется, так что 5 000 мы можем и не увидеть, а увидим например 1000-3000.

Ну, 500 запросов в секунду это довольно нагруженный сайт с миллионом посетителей в день. Если один сервер такое тянет то это отличное приложение. На практике 500 может и не выйти, так как 100 параллельно работающих скриптов будут создавать 100 параллельных соединений с базой, делать запросы, она может не успеть им всем ответить, и тд, но это ведь не вина Апача, правда? 500 это скорее высокая планка к которой стоит стремиться.

В общем для веба она подходит, если это не совсем хайлоад.

Она не подходит для случаев когда у нас много параллельных слабоактивных соединений. Например у нас сервер который раздает файлы с диска большому числу клиентов на не очень быстрых каналах. Ну к примеру отдача одной картинки занимает 3 секунды (так как у клиента медленный интернет), картинка весит 100 Кб, это значит что:

1 рабочий может обслужить 1/3 запроса в секунду, трафик 33 кб/с (это значит что ты зря заплатил хостеру за гигабитный канал, он используется менее чем на 0.1% ).
10 рабочих - 10/3 = 3.33 запроса в секунду, трафик 330 кб/с
100 рабочих - 33.3 запроса в секунду, трафик 3.3 Мб/с
1000 рабочих - 333 запр/сек., 33Мбита/с, но они будут есть много памяти и операционная система замучается переключать процессор между ними
10 000 рабочих - 3333 запрс/сек мы не получим, получим условно говоря 1000 и 100 Мбит/с.

Смотри, какие печальные цифры: наш Апач на раздаче картинок загружает гигабитный канал лишь на 10% (значит нам надо купить еще 9 дорогущих серверов чтобы загрузить его полностью), жрет тонны памяти (10 000 рабочих × 10 Мб каждый = 100 Гб ), процессор расходуется в основном на переключения контекста, быстрые клиенты не могут скачивать файл на полной скорости.

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

Один многопоточный процесс

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

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

По такой схеме работает mysql: он создает пул потоков, и когда подсоединяется новый клиент, выделяет ему свободный поток, который принмимает и обрабатывает запросы. Также, многие службы и фоновые программы под Windows используют потоки. Апач под Windows тоже может использовать эту схему.

Проблему раздачи статики, описанную выше, это не решает.

Как это описать аналогией, я не знаю.
завершение пасты #453 #555366
>>555233

Один асинхронный процесс с 1 потоком

Есть еще одна интересная архитектура. Здесь используется один поток, но используются неблокирующие (асинхронные) обращения к внешним ресурсам вроде файлов или сети. Все описанные выше архитектуры используют блокирующие вызовы. Это значит что когда поток просит ОС прочитать файл с диска или отправить пакет по сети, или хочет получить пакет из сети, он делает системный вызов и блокируется до тех пор пока не будут получены данные.

Асинхронный вызов работает по другому: поток просит ОС начать операцию ввода-вывода, и не блокируется, а продолжает выполняться, а позже может спрашивать у ОС каков статус операции и пришли ли данные. Очевидно что код для работы с асинхронными вызовами будет сложнее. Обычно он строится на так называемом событийном программировании (event-driven programming). То есть внутри программы ведется список выполняющихся операций и список функций которые надо вызвать по их завершении. Например, когда придет новый запрос от клиента, вызвать функцию processRequest. Когда прочитается в память файл X, вызвать функцию Y.

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

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

Минусы: обработчики должны работать быстро и не имеют права блокироваться (так как у нас 1 поток и все остальные будут его ждать). Блокироваться имеет право только основная функция, которая получает события от ОС. Так как на высоконагруженном сервере блокировку может вызвать даже операция выделения памяти, часто приходится применять разные трюки, например выделять всю нужную память при старте сервера.
Код надо писать в асинхронной манере.
Если происходит ошибка, то падает весь сервер, так как он весь в одном потоке. Все необработанные запросы теряются.
Если какой-то обработчик выделил память и забыл ее освободить, никто уже ее не освободит. Будет утечка памяти, если они повторяются то процесс рано или поздно займет всю доступную память и будет убит. В случае с процессами-рабочими проблема менее вероятна, так как рабочих можно периодически прибивать, освобождая память.
То есть требуется высокий уровень грамотности и ответственности разработчика.

Плюсы: расходы памяти на один зеленый тред могут быть в сотни раз меньше чем на поток/процесс. Также нет накладных расходов на переключение между ними. Это дает нам возможность иметь сотни тысяч или даже миллион зеленых потоков, хватило бы памяти (естественно при условии что каждый поток не использует много памяти). Используется 100% процессора.

По такой схеме работает веб-сервер nginx, кеш memcached, хранилище redis, платформа Node.JS (реализует веб-сервер на яваскрипте).

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

Заметь что все эти сервера (кроме node.js) не содержат в себе сложной логики, которая может долго выполняться и замедлять обработку запросов. nginx просто раздает файлы с диска по сети или проксирует данные из одного соединения в другое, мемкеш просто кладет небольшие кусочки данных в память или отдает их в сеть. А вот в случае с Node.js все зависит от умения разработчика, и там получить тормоза, утечки памяти довлоьно легко.

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

Эта архитектура стала ответом на проблему C10K - «как поддерживать 10 000 параллельных соединений».

Для PHP есть фреймворк - ReactPHP http://reactphp.org/ который позволяет на PHP реализовать асинхронную обработку большого числа запросов. Если ты хочешь помучаться с написанием правильного асинхронного кода, не прощающего ошибки.

Ссылочки для чтения:

http://www.moodle.ipm.kstu.ru/mod/page/view.php?id=49
https://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%BE%D0%B1%D0%BB%D0%B5%D0%BC%D0%B0_10000_%D1%81%D0%BE%D0%B5%D0%B4%D0%B8%D0%BD%D0%B5%D0%BD%D0%B8%D0%B9
http://uinc.ru/articles/34/ (может быть сложно все понять)
завершение пасты #453 #555366
>>555233

Один асинхронный процесс с 1 потоком

Есть еще одна интересная архитектура. Здесь используется один поток, но используются неблокирующие (асинхронные) обращения к внешним ресурсам вроде файлов или сети. Все описанные выше архитектуры используют блокирующие вызовы. Это значит что когда поток просит ОС прочитать файл с диска или отправить пакет по сети, или хочет получить пакет из сети, он делает системный вызов и блокируется до тех пор пока не будут получены данные.

Асинхронный вызов работает по другому: поток просит ОС начать операцию ввода-вывода, и не блокируется, а продолжает выполняться, а позже может спрашивать у ОС каков статус операции и пришли ли данные. Очевидно что код для работы с асинхронными вызовами будет сложнее. Обычно он строится на так называемом событийном программировании (event-driven programming). То есть внутри программы ведется список выполняющихся операций и список функций которые надо вызвать по их завершении. Например, когда придет новый запрос от клиента, вызвать функцию processRequest. Когда прочитается в память файл X, вызвать функцию Y.

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

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

Минусы: обработчики должны работать быстро и не имеют права блокироваться (так как у нас 1 поток и все остальные будут его ждать). Блокироваться имеет право только основная функция, которая получает события от ОС. Так как на высоконагруженном сервере блокировку может вызвать даже операция выделения памяти, часто приходится применять разные трюки, например выделять всю нужную память при старте сервера.
Код надо писать в асинхронной манере.
Если происходит ошибка, то падает весь сервер, так как он весь в одном потоке. Все необработанные запросы теряются.
Если какой-то обработчик выделил память и забыл ее освободить, никто уже ее не освободит. Будет утечка памяти, если они повторяются то процесс рано или поздно займет всю доступную память и будет убит. В случае с процессами-рабочими проблема менее вероятна, так как рабочих можно периодически прибивать, освобождая память.
То есть требуется высокий уровень грамотности и ответственности разработчика.

Плюсы: расходы памяти на один зеленый тред могут быть в сотни раз меньше чем на поток/процесс. Также нет накладных расходов на переключение между ними. Это дает нам возможность иметь сотни тысяч или даже миллион зеленых потоков, хватило бы памяти (естественно при условии что каждый поток не использует много памяти). Используется 100% процессора.

По такой схеме работает веб-сервер nginx, кеш memcached, хранилище redis, платформа Node.JS (реализует веб-сервер на яваскрипте).

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

Заметь что все эти сервера (кроме node.js) не содержат в себе сложной логики, которая может долго выполняться и замедлять обработку запросов. nginx просто раздает файлы с диска по сети или проксирует данные из одного соединения в другое, мемкеш просто кладет небольшие кусочки данных в память или отдает их в сеть. А вот в случае с Node.js все зависит от умения разработчика, и там получить тормоза, утечки памяти довлоьно легко.

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

Эта архитектура стала ответом на проблему C10K - «как поддерживать 10 000 параллельных соединений».

Для PHP есть фреймворк - ReactPHP http://reactphp.org/ который позволяет на PHP реализовать асинхронную обработку большого числа запросов. Если ты хочешь помучаться с написанием правильного асинхронного кода, не прощающего ошибки.

Ссылочки для чтения:

http://www.moodle.ipm.kstu.ru/mod/page/view.php?id=49
https://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%BE%D0%B1%D0%BB%D0%B5%D0%BC%D0%B0_10000_%D1%81%D0%BE%D0%B5%D0%B4%D0%B8%D0%BD%D0%B5%D0%BD%D0%B8%D0%B9
http://uinc.ru/articles/34/ (может быть сложно все понять)
#454 #555368
>>555366

Сорри, мой пост был комбо-брейкером
#455 #555371
>>555233

Очередь тут это структура данных, в которую с одного конца можно класть данные, а с другого снимать:

https://ru.wikipedia.org/wiki/%D0%9E%D1%87%D0%B5%D1%80%D0%B5%D0%B4%D1%8C_(%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5)

http://informatics.mccme.ru/mod/book/view.php?id=580

http://neerc.secna.ru/Algor/algo_base_ds_lists.html

Реализовать очередь можно по-разному: таблица в базе данных (как у мейл ру), список в редисе или даже отдельный сервер очередей вроде ZeroMQ, RabbitMQ.

Соответственно идея в том что новые посещения кладутся с одной стороны очереди, а скрипт-сборщик периодически вынимает их с другой. Скрипты друг другу не мешают, данные не теряются.
#456 #555374
>>555349
Неудобно с планшета глядеть,
if ($sum<0) break;
Не очень полезная конструкция,ничего не делает, а место занимает.
Лучше в своём условии точно задачей границы с помощью && :
if ($sum>0 && $sum <400)
#457 #555375
>>555359
Напиши компонент для 1с-битрикс
#458 #555377
>>555374
*задай
#459 #555380
>>555375

>1с-битрикс


Не хочу зашквариться.
#460 #555381
>>555374
Спасибо.
#461 #555383
>>555380
Ну тогда соси хуи, зашквар у него,блядь. Тут в соседнем треде задача про матрицы висит, сделай на пхп,
#462 #555384
>>555364
Спасибо.
#463 #555386
>>555330

Вот я уже не первый раз такое слышу. Верстку почему-то очень не любят те, кто HTML/CSS не знает. Естественно не зная этих языков верстать не получится.

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

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

Так что советую открыть ОП-пост и пройти все задачки по HTML там, и показать решения. Может быть узнаешь много нового.

По JS, DOM, jQuery задания у нас тоже есть.
#464 #555388
>>555340

Ты надеюсь в командной строке git pull делал, а не в графическом интерфейсе? ибо ГУИ можно пользоваться только если знаешь гит на 5 с плюсом, иначе через него легко что-нибудь сломать.

Ты ведь не закоммитил пока состояние с конфликтом? Тогда можно все сбросить через

git reset --hard HEAD

После этого снова делаешь merge и вдумчиво решаешь конфликты, вникая в каждый слуай.

Для разрешения конфликтов нужна программа умеющая 3-way merge. Я пользуюсь наверно самой неудобной — KDiff (или как-то так, не помню точно). Она пытается помочь и мерджит код, разрывая функции на куски и склеивая в произвольном порядке.

Но в других GUI программах для гита есть более удобные средства. Главное, что это должно быть 3way merge, то есть отображается 3 версии файла сразу.

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

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

Ну и еще надо чаще мерджиться чтобы такого не было. Это ты наверно уже понял и так.
#465 #555397
Аноны, я знаю что там лежат непроверенные задачки, но вы потерпите еще немного, работа волк, нету времени сегодня. Решайте пока другие, я пока быстро пробегусь по кому успею.

>>555383

Цыц, не ругайся.

>>555364

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

>>555354

Не ругайся.

>>555359

Задачи из урока «повторим» в нашем учебнике решал уже? Там почти все на массивы.

>>555350

У меня есть выделить только код копируется только код. Хромиум.

>>555349

> $paymentTotal = $paymentTotal + $creditSum;


> $creditSum = ( $creditSum x $percent )


Это повторяется 2 раза, убери повторы

> if ($creditSum < 0) {


Это вряд ли выполнится. Логично проверять достижение нуля после выплаты части долга, а не после начисления комиссий и процентов.

>>555341

Можно конечно.

> Ведь дальше по формуле подсчета общей выплаты, в фунции, будут умножения на этот процент, просто тогда в формуле этой переменной просто не будет?


Если умножить на ноль то ноль наверно и получится? А вот если прибавлять то другое дело.

>>555340

Коммиты в гите не исчезают, если не лезть руками в папку .git и не делать rebase, так что я бы не паниковал.

>>555323

Вообще мне иногда скриншот удобен так как не надо открывать новую вкладку и ждать ideone.

В идеале конечно лучше иметь и скриншот и ссылку :)

>>555322

> [mt_rand(0,6)]


Надо цифры не считать руками, а автоматически, а то с ума сойти можно. Как это проверять? Я не хочу пересчитывать все.

Ты ж программист, автоматизируй.

чтобы не было повторов, нужен array_rand
#465 #555397
Аноны, я знаю что там лежат непроверенные задачки, но вы потерпите еще немного, работа волк, нету времени сегодня. Решайте пока другие, я пока быстро пробегусь по кому успею.

>>555383

Цыц, не ругайся.

>>555364

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

>>555354

Не ругайся.

>>555359

Задачи из урока «повторим» в нашем учебнике решал уже? Там почти все на массивы.

>>555350

У меня есть выделить только код копируется только код. Хромиум.

>>555349

> $paymentTotal = $paymentTotal + $creditSum;


> $creditSum = ( $creditSum x $percent )


Это повторяется 2 раза, убери повторы

> if ($creditSum < 0) {


Это вряд ли выполнится. Логично проверять достижение нуля после выплаты части долга, а не после начисления комиссий и процентов.

>>555341

Можно конечно.

> Ведь дальше по формуле подсчета общей выплаты, в фунции, будут умножения на этот процент, просто тогда в формуле этой переменной просто не будет?


Если умножить на ноль то ноль наверно и получится? А вот если прибавлять то другое дело.

>>555340

Коммиты в гите не исчезают, если не лезть руками в папку .git и не делать rebase, так что я бы не паниковал.

>>555323

Вообще мне иногда скриншот удобен так как не надо открывать новую вкладку и ждать ideone.

В идеале конечно лучше иметь и скриншот и ссылку :)

>>555322

> [mt_rand(0,6)]


Надо цифры не считать руками, а автоматически, а то с ума сойти можно. Как это проверять? Я не хочу пересчитывать все.

Ты ж программист, автоматизируй.

чтобы не было повторов, нужен array_rand
#466 #555404
>>555312

Важно не сколько будет объектов, а является ли что-то отдельной сущностью требующей отдельного класса.

Вот паста (на примере задачи про вектор):

--------------

Когда ты решаешь задачу на ООП, ты должен ответить на вопросы:

— какие есть сущности, для которых мы сделаем классы? (Сотрудник и Департамент)
— какие у них есть свойства (у Сотрудника есть ранг, базовая ставка, профессия, является ли боссом). Потребление кофе или зарплата не являются свойствами так как они вычисляются из других свойств и хранить их не надо.
— что мы хотим от них получить (какие у них должны быть методы). Например мы хотим узнать сколько сотрудник заработал или сколько он пьет кофе. От департамента мы наверно хотим получить сколько всего выпито кофе и заплачено денег.
— как сущности связаны? Очевидно, Сотрудник работает в каком-то Департаменте.

--------------

>>555288

А при чем тут pjax? Как я понимаю он реализует ту же логику что и обычный переход по ссылкам и ссылки без него формируются так же.

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

Ну и мое мнение, галереи на яваскрипте дрянь с точки зрения удобства пользования, вот смотри как делают галереи нормальные люди: http://www.tema.ru/travel/spb.2011.10/

Чтобы получить следующую картинку, достаточно сделать запрос

WHERE x > ? ORDER BY x LIMIT 1

Где x это поле по которому отсортированы картинки.

В твоем случае тебе наверно логичнее получить полный список фотграфий в галерее, закодировать в JSON и внедрить в тело страницы. А скрипт на клиенте пусть берет оттуда данные и переключает картинки.

Ну и надеюсь ты выучил JS/DOM/jQery перед тем как за это браться .
#466 #555404
>>555312

Важно не сколько будет объектов, а является ли что-то отдельной сущностью требующей отдельного класса.

Вот паста (на примере задачи про вектор):

--------------

Когда ты решаешь задачу на ООП, ты должен ответить на вопросы:

— какие есть сущности, для которых мы сделаем классы? (Сотрудник и Департамент)
— какие у них есть свойства (у Сотрудника есть ранг, базовая ставка, профессия, является ли боссом). Потребление кофе или зарплата не являются свойствами так как они вычисляются из других свойств и хранить их не надо.
— что мы хотим от них получить (какие у них должны быть методы). Например мы хотим узнать сколько сотрудник заработал или сколько он пьет кофе. От департамента мы наверно хотим получить сколько всего выпито кофе и заплачено денег.
— как сущности связаны? Очевидно, Сотрудник работает в каком-то Департаменте.

--------------

>>555288

А при чем тут pjax? Как я понимаю он реализует ту же логику что и обычный переход по ссылкам и ссылки без него формируются так же.

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

Ну и мое мнение, галереи на яваскрипте дрянь с точки зрения удобства пользования, вот смотри как делают галереи нормальные люди: http://www.tema.ru/travel/spb.2011.10/

Чтобы получить следующую картинку, достаточно сделать запрос

WHERE x > ? ORDER BY x LIMIT 1

Где x это поле по которому отсортированы картинки.

В твоем случае тебе наверно логичнее получить полный список фотграфий в галерее, закодировать в JSON и внедрить в тело страницы. А скрипт на клиенте пусть берет оттуда данные и переключает картинки.

Ну и надеюсь ты выучил JS/DOM/jQery перед тем как за это браться .
#467 #555406
>>555352
Тогда надо записывать выпавший рандом в переменную и делать unset для массива с тем же индексом.
#468 #555409
>>555287

А погрешность какая? Это используется только для оценки есть превышение определенного порога (так что тебе не стоит ждать окончания подсчета) или нет.

Анон, не разбираешься в статистике - лучше спроси у тех кто разбиаретя. Или напиши программу имитирующую посещения и посмотри что она насчитает.

>>555265

Если не нужна точность, почему бы сразу не вписать в HTML коде число 100500?

>>555258

Что такое среднее? чтобы его посчитать надо сделать N измерений. Кстати это N ты не написал, по скольки числам среднее?

>>555155

Может тогда в поддержку open server стоит писать? htaccess верный.

Алсо,

> c:/openserver/modules/php/PHP-5.3


Ты представляешь насколько ты древний PHP используешь? Хотя бы до 5.4 или 5.5 надо бы обновиться. Ну спасибо что не 5.2 где анонимных функций не было.

В логах сервера ничего интересного нет?

В общем тебе надо либо разобраться как работает и устроен этот опен сервер либо снести его и все поставить с нуля.
#468 #555409
>>555287

А погрешность какая? Это используется только для оценки есть превышение определенного порога (так что тебе не стоит ждать окончания подсчета) или нет.

Анон, не разбираешься в статистике - лучше спроси у тех кто разбиаретя. Или напиши программу имитирующую посещения и посмотри что она насчитает.

>>555265

Если не нужна точность, почему бы сразу не вписать в HTML коде число 100500?

>>555258

Что такое среднее? чтобы его посчитать надо сделать N измерений. Кстати это N ты не написал, по скольки числам среднее?

>>555155

Может тогда в поддержку open server стоит писать? htaccess верный.

Алсо,

> c:/openserver/modules/php/PHP-5.3


Ты представляешь насколько ты древний PHP используешь? Хотя бы до 5.4 или 5.5 надо бы обновиться. Ну спасибо что не 5.2 где анонимных функций не было.

В логах сервера ничего интересного нет?

В общем тебе надо либо разобраться как работает и устроен этот опен сервер либо снести его и все поставить с нуля.
#469 #555410
>>555404
А чем он не подходит?
Идеально же. А засорение истории это то, что мне нужно, там красивые ссылочки, люди будут иметь возможность нажать кнопочку ПОДЕЛИТЬСЯ именно этой картинкой, на которую приведет ссылка

Спасибо за запрос, это то, что нужно
#470 #555411
>>555374
кокой хипстер, с планшета сидит. поди еще и из старбакса?
#471 #555412
Оп, не хочешь копирайтером поработать? Там авторы таких стен текста приветствуются.
#472 #555416
>>555017

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

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

>>555144

> (?:а|но)[^а-яё]


границу слова можно обозначить как \\b

Это описано вроде ведь в моем уроке по регуляркам? посмотри, может ты еще что-то не знал?

В остальном верно.

> Автоисправление ошибок - не знаю, правильно ли я тебя понял


А код где? Не написан? Трудно тогда комментировать.

> эту подсказку я совсем не понял, как использовать,


Массив + цикл можно заменить на несколько вызовов функции, ну например:

$data = [
[1,2],
[3,4]
];

foreach ($data ..)
...

можно заменить на

doSomething(1, 2);
doSomething(3, 4);

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

У тебя есть слова капслоком писать, регистр искажается: http://ideone.com/p7Ltcz

В остальном, замечаний нет.

А! Я придумал как чуть упростить эти коллбеки и убрать из них if. Смотри, там во всех 3 случаях нам надо заменить одну букву на другую, сохранив регистр:

з -> c, З -> С

Ну так сделай функцию которая возвращает данную букву, копируя ее регистр с другой буквы:

$letter = copyCase('c', $matches[2]); // вернет либо c либо С в зависимости от matches

Хотя бы от этого if избавишься и укоротишь код.
#472 #555416
>>555017

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

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

>>555144

> (?:а|но)[^а-яё]


границу слова можно обозначить как \\b

Это описано вроде ведь в моем уроке по регуляркам? посмотри, может ты еще что-то не знал?

В остальном верно.

> Автоисправление ошибок - не знаю, правильно ли я тебя понял


А код где? Не написан? Трудно тогда комментировать.

> эту подсказку я совсем не понял, как использовать,


Массив + цикл можно заменить на несколько вызовов функции, ну например:

$data = [
[1,2],
[3,4]
];

foreach ($data ..)
...

можно заменить на

doSomething(1, 2);
doSomething(3, 4);

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

У тебя есть слова капслоком писать, регистр искажается: http://ideone.com/p7Ltcz

В остальном, замечаний нет.

А! Я придумал как чуть упростить эти коллбеки и убрать из них if. Смотри, там во всех 3 случаях нам надо заменить одну букву на другую, сохранив регистр:

з -> c, З -> С

Ну так сделай функцию которая возвращает данную букву, копируя ее регистр с другой буквы:

$letter = copyCase('c', $matches[2]); // вернет либо c либо С в зависимости от matches

Хотя бы от этого if избавишься и укоротишь код.
#473 #555417
>>555131

Анон, это плохой учюбный пример:

- простыня кода без разбиения на функции с кучей оступов. Так нельзя писать.
- смешана работа с формой (которая тут не нужна) и хеширование

Видимо ты сам еще начинающий. Не хочешь наши задачки из оп-поста про студентов и файлообменник решить?

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

ну и если погуглить, то выяснится что в PHP5.5. уже есть такие готовые функции: http://habrahabr.ru/post/194972/

Соль маленькая, пиши 40 символов минимум, включая специсмволы, пусть хакеры процессоры себе сожгут пытаясь разгадать.
#474 #555418
>>555411
Планшет- рандомандроид от DNS, пишу тебе этот пост, сидя на толчке.

Откуда такие стереотипы то, тоже мой.
#475 #555419
>>555027
>>555023

Интернет-магазин я могу сделать за 10 минут. Скачать CMS и установить. Объясни теперь зачем какой смысл писать свой?

Алсо для магазинов нужен фреймворк мощнее. Если у тебя не магазин на 3 товара, то минимум Yii 2.

Не забудь файлообменник на проверку показать.
#476 #555422
>>555005

> А где это почитать чтоб не сложно для ньюфага?


В случае апача надо читать документацию по mod_rewrite (то есть тот же htaccess):

https://beget.ru/articles/htaccess#mod_rewrite
http://habrahabr.ru/company/sprinthost/blog/129560/

+ офиуиальный сайт апача на англ, раздел mod_rewrite

>>554993

У него опен сервер и там конфиг поменять еще сложнее. Ему надо снести этот опен сервер просто.
#477 #555425
>>555412

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

Копирайтинг это очень странная вещь, я всем советую бросать эту дрянь и либо перквалифицтроваться в полноценного журналиста/сценариста/автора статей/книг либо заняться чем-то другим.

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

>>555410

А если больше одной галереи на странице?

pjax это оверкилл так как ты делаешь лишние запросы чтобы скачать кусок hTML в то время как ссылку на картинку и описание проще заложить в тело страницы сразу.
20 Кб, 1338x212
#478 #555428
Охуенный цдн у бутстрапа. Заебись, чотко.
#479 #555436
>>555428

Если часто пользоваться интернетом такое можно наблюдать у большинства сторонних серверов. Яндекс-карты бывает тупят по 15 секунд, я помню yandex.st падал ненадолго, итд.

Статику надо размещать на своем сервере а не слушать клоунов-хипстеров которые сложнее туду листа ничего не верстали.
#480 #555437
>>555428

Алсо 120 кб CSS кода это кошмар конечно. Бедный браузер.
#481 #555440
А у меня в оупенсервере не работает курл на последней версии пхп.
Не хочет отправлять файлы.
На предпоследней версии отправляет, но не работает что-то другое. И через некоторое время работы сервера все равно перестает отправлять.
#482 #555441
>>555428

Алсо если ты будешь делать что-то не для себя а для заказчика, то писать вот так вот:

cdn/jquery.min.js

Это верный способ слоамть сайт при каком-нибудь очередном обновлении jQuery. если тебе там принципиально сэкономить 100 кб на жестком диске то хотя бы указывай конкретную версию библиотеки а не «какая выпадет».
#483 #555443
>>555440

Ни кода ни текста ошибки = ничем помочь не можем.
#484 #555445
>>555443
Я пока не разбирался. Так, просто, говорю.
#485 #555447
Посоветуйте книги по Javascript типа Шлосснгейла и Зандстры для PHP, т.е. чтобы все на очень профессиональном уровне разбирали, а не обучалки для новичков. Есть такие вообще?
#486 #555448
>>555346
Ну $config[] - это массив твоих настроек в который все вот такие вот штуки обычно и выносят, путь к базе, соли, сколько юзеров/предметов выводится на странице, всевозможные другие штуки сразу влияющие на весь скрипт. Хотя соль это конечно более низкоуровневая хуйня чем простые настройки, и после того как твой скрипт уже заработал, то её лучше не править, а то никто не сможет больше залогиниться при вот такой реализации. Но для тестового задания или в учебых целях сойдет.

Ну тип это как бы дополнительное шифрование паролей.
Даже если кто-то вскроет твою базу, то он всё равно не сможет залогиниться под юзверями, не спиздив твой php код. Ведь он не сможет понять каким образом из "qwer123" получается 32-х значная хуита которая там хранится.

Спрашивай еще если что непонятно, постараюсь пояснить.
#487 #555449
>>555448

У тебя общая соль для всех пользователей? Неправильно, соль должна быть индивидуальной иначе пароли можно перебирать параллельно.
#488 #555452
>>555447

>жабаскрипт


>профессиональное обучение


кекеке
#489 #555454
>>555441
Тащемта полная ссылка - ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js
#490 #555455
>>555452
Это какой-то профессиональный юмор жаваскриптеров?
#491 #555457
>>555449
Т.е. нужно еще доп. поле, куда эта соль для каждог юзера записывается? как токен в куки?
#492 #555458
>>555448
так эта соль (рандомно сгенерированная строка) в какое место должна быть записана, если в бд ее хранить нельзя из-за угрозы взлома?
#493 #555460
>>555449
Ну вообще-то не должна. Но этот господин тоже говорит дело. Вместо соли можно использовать email или login самого же юзера. А именно тот параметр, который юзер в своем профиле не может поменять. Пусть это будет даже id его записи в базе.

$login = "vasya"; //неизменяемый, юзаем для соли без страха
$pass = "qwer123"; //
$mail = "[email protected]" //пользователь может заменить, юзать для соли нельзя

$saltyPass = $login . $pass;

$hash = md5($saltyPass); // это идет в базу собственно

Ну и когда юзер пытается залогиниться, ты дергаешь из базы по юзернейму того кто там лежит, и сравниваешь точно так же соленые пароли друг с другом.
91 Кб, 600x450
#494 #555465
>>555412
Сколько платишь за тысячу знаков? Ты ебанутый?
#495 #555468
Как сверстать, чтобы контент выводился вот так в два столбика? По два запроса в бд что ли делать?
#497 #555470
>>555457

да, либо отдельное поле либо в кеш дописывать

>>555458

в БД конечно. В твоем случае можно сделать 2 части соли, 1 постоянная из конфига, вторая из базы. Та что в базе генерируется рандомно для каждого юзера.

>>555460

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

В твоем случае комбинация vasya123456 очень слабая.

Лучше 20-40 рандомных символов.
36 Кб, 400x480
#498 #555472
>>555460
заебись, мастера кибер безопасности. добавлять логин к паролю, ну надо же, кто еще до этого додумается.
#499 #555474
>>555472
ну блин, ну для объяснения же чисто, и с упором на подводные камни, ну что вы :(
#500 #555478
>>555460
>>555346
Не ебите мозг своими кривыми солями, юзайте
$hash = password_hash($password, PASSWORD_DEFAULT);
#501 #555487
ой не могу, прямо с утра до вечера сижу сайт клепаю, так тянет в игори поиграть или по шитпостить.
#502 #555497
>>554843
>>554843
Нет, я так тоже проверил, все равно ошибка.
Пишет 'Syntax error, unexpected ')', expected , or ;'
Вроде бы ошибка в синтаксисе, но я не могу понять в чем именно.
sage #503 #555501
>>555469
ты ебонутый
>>555468
заюзай бутстрап

или смотри в сторну float
или фиксированной ширины
можно ещё flexbox использовать
два inline-block тебе нужно
#504 #555502
>>555501
>>555501
Чего это за палец ко мне приклеился ?
#505 #555506
>>555353
Ну трипл же, посоветовали бы чего
#506 #555507
>>555506
Ну квадрипл же, посоветовали чего
#507 #555508
>>555497
Значение по умолчанию может быть только скалярной величиной (строка, число, boolean, null), а также массив.
http://php.net/manual/ru/functions.arguments.php#functions.arguments.default

И это неправильно, что ты пытаешься намертво зашить соединение только на конкретную конфигурацию.
Класс должен принимать объект соединения в конструкторе, например.
#508 #555523
Аноны, как "набрать форму" если 6 недель по больничкам валялся? Даже не ожидал, что все так из головы вылетит. Может учебник прорешать по новой. Так то я уже начинал студентов делать.
#509 #555530
>>555523
То чувство, когда ты ничего не знал, и спустя год ничего-не-делания твои знания ничуть не преуменьшились.
#510 #555561
>>555489
но я пообещал сделать быстро-быстро.
#511 #555566
>>555501
Нет, ты не понял, как мне выводить их в два столбика. вот если пишешь. foreach ($files as $key =>$value) { print $files[$value];}

А верстка у меня такая

<div style="float:right"></div>
<div style="float:left"></div>

Вот как мне напечатать files[value] поровну в обоих этих дивах с различной версткой, классами и стилями?? Т.е если просто печатать массив, то он печатается В СТОЛБИК БЛЯТЬ. ОН НЕ ПЕЧАТАЕТСЯ В ДВА СТОЛБИКА МНЕ НУЖНО В ДВА.
#512 #555586
Привет, помоги мне, анон.
мне нужно сделать что-то вроде такого:
<?php
echo date('i:s'); sleep(1); echo date('i:s');
echo date('i:s');
?>
И получится:
00:00 00:01
00:00

Что-то вроде многопоточности, помоги мне анон :3
#513 #555590
4-100500 байтовые символы в utf, запись в мускул
Мускул в utf8_classic_epta символы жирнее 3х байтов не жрет и режет строку к хуям собачим
Как делать без костылей и чтоб сравнивать было норм и кракозябр не было?
#514 #555591
>>555586
Нихуя непонятно, нахуй тебе многопоточность и какая задача? Поможешь с удовольствием епта, только поясни
#515 #555593
>>555590
Ну или перехуячить в какой-нить бинарный формат и в бд. А в пхп перехуячить. Только хз как, в пхп 5.5 нихуя кроме кодинга-енкодинга для утф8 не сделали падлы
#516 #555594
>>555591
да цикл у меня есть, а в нем нужно выполнить задачу с задержкой, а после задержки еще одну задачу, но это должно не влиять на сам цикл
#518 #555605
>>555590

> utf8mb4, a UTF-8 encoding of the Unicode character set using one to four bytes per character.



Не подойдет?

>>555594

PHP так не работает.
#519 #555615
Поссал на опа-отброса с его говносайтом на народе, который еще учит других, как эти сайты клепать.
#520 #555621
Привет, Анон.
Вот допустим есть сервер и сайт.
На сервере работает скрипт, который должен отправлять на сайт текст и картинку к нему и ждать ответа пользователя на данный текст, скрипт ждет ответа пользователя, на сайте автообновление этого есть
Мне нужен скрипт с сайтом и как это использовать
Спасибо
#521 #555643
>>555523
У меня на такие случаи самые важные моменты во время обучения в файлик записаны, а куски кода со сложными конструкциями по мелким файликам раскиданы. Можно просмотреть быстро и подтянуться.
#522 #555656
>>555566
учи html, css. типограф, блядь.
почитай что чел выше тебе говорил. foreach просто перебирает информацию, он тебе ее не должен выстравивать. Чтобы блоки переносились нужно правильно сверстать.
Гуглить не умеешь? http://stackoverflow.com/questions/6385293/simple-two-column-html-layout-without-using-tables
#523 #555675
>>555425
ок, я подумал и ты прав, pjax не нужен. Допустим, я могу в data-аттрибут положить ссылку на изображение и по клику формировать на его основании тег img, но как быть, если мне нужно большой кусок html кода вхуячить по клику? Например, управление и возможность посмотреть комментарии. В js его сувать некрасиво.
#524 #555695
https://github.com/V3N0m21/Uppu3

Привет ОП, посмотри мой файлообменник, я туда прикрутил jQuery и поправил твои замечания. С версткой беда, знаю, но сейчас хочу разобраться до конца с бэкендом, а потом уже наводить красоту.
#525 #555697
>>555695
21 в нике это размер члена?
#526 #555707
>>555566

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

Что касается массива, если ты умеешь работать с массивами то легко разобьешь массив на 2 нужных либо выберешь из него элементы. Если нет то стоит начать с теории и изучить работу с массивами.

>>555501

флексбокс? При чем это тут?

>>555675

Тогда так:

- по простому: грузить с сервера HTML
- по сложному: делать шаблонизацию на стороне клиента, грузить комментарии аяксом и не уверен стоит ли оно того

А какой смысл в комментариях которые спрятаны где-то за фоткй и которые мало кто увидит? Комментарии проще сделать общие, если конечно их у тебя там не сотни будут.
#527 #555733
>>555707
спасибо, нужно отдельно к каждой, скорее всего сделаю, чтобы изначально количество комментариев отображалось, а по клику аяксом подгружу. в догонку вопрос: если я использую pushState, как сделать, чтобы, допустим, айди не добавлялся 2 раза к юрл?
#528 #555739
Что то я так и не могу понять как вставлять в таблицу базы данных какие либо данные, например из формы, в YII2. Я создал формы, создал таблицу, могу вывести введённые данные в формы, но никак не могу найти метода для базы данных при помощи которого их можно туда вставить. Как это сделать?
4206 Кб, Webm
Общая валидация для Create и Update #529 #555787
Антоши, как в Yii2 грамотно сделать общую валидацию для Create и Update действий?

У меня есть 2 класса: CreateAuthorForm и UpdateAuthorForm с практически одинаковыми правилами валидации и сообщениями, например:

['phone', 'filter', 'filter' => 'trim'],
['phone', 'required', "message" => "Номер телефона обязателен."],
['phone', 'unique', 'targetClass' => '\app\models\User', 'message' => '"Этот номер телефона уже используется.'],
['phone', 'string', 'length' => [10, 12], 'tooShort' => '...', 'tooLong' => '...'],
['phone', function ($attribute, $params) {
if (!ctype_digit($this->$attribute)) {
$this->addError($attribute, Только числа.');
}
}]

Эти все правила будут одинаковы как для создания, так и для редактирования, дублировать, конечно, не хочется.
#530 #555790
>>555787

А зачем ты сделал 2 формы когда можно сделать одну форму и 2 сценария? Это и есть решение.

Алсо почитай теорию например https://github.com/yiisoft/yii2/blob/master/docs/guide-ru/structure-models.md#Сценарии-
#531 #555792
>>555787

Алсо

> Только числа


надеюсь это только для примера написано и в реальном коде такого позора не будет.

Телефон должен приниматься в привычном человеку формате.
#532 #555793
Делаю файлообменник, вопрос по Доктрине.
Есть двунаправленная связь один-ко-многим (юзер => файлы).
Стоит задача: имея на руках id юзера получить все его файлы.
Как сделать это правильно, не заставляя Доктрину генерировать кучу лишних запросов? В гугле советуют поставить либо fetch="EAGER" в аннотациях (нам это не подходит, т. к. далеко не всегда нужен юзер в связке со своими файлами), либо писать запрос ручками.
Я ведь правильно понимаю, что конструкции вида:
$files = $em->getRepository("File")->findBy(array('user' => $user->getId()));
и
$files = $user->getFiles();
загрузят лишь массив прокси-объектов, и последующий проход по нему с вызовами геттеров сгенерирует много однотипных запросов?
9 Кб, 485x104
15 Кб, 684x132
#533 #555794
>>555793
Вот.
Слева User. Справа - File.
4313 Кб, Webm
#534 #555848
>>555790
Спасибо, почитал, я правильно понимаю, что стоит сделать один класс типа AuthorForm, где будет написано примерно это:

class AuthorForm extends Model{
public $name;
public $email;
public $password;
public $phone;

public function scenarios()
{
return [
'create' => ['username', 'phone'],
'update' => ['username', 'phone', 'password'],
];
}
public function rules()
{
return [
...
]

public function create(){
if($this->validate(){}else{}
}

public function update(){
if($this->validate(){}else{}
}

И в этом случае для $model->update будет вызвана валидация и на телефон? (пример вымышлен, конечно)
>>555792
Надо подтвердить телефон автора, выслав смс, поэтому только числа и будет ещё ограничение на +7/8. Хотя сейчас подумал, что, может быть, лучше сделать свободный формат и потом выделять оттуда числа и уже с этим работать.
4313 Кб, Webm
#534 #555848
>>555790
Спасибо, почитал, я правильно понимаю, что стоит сделать один класс типа AuthorForm, где будет написано примерно это:

class AuthorForm extends Model{
public $name;
public $email;
public $password;
public $phone;

public function scenarios()
{
return [
'create' => ['username', 'phone'],
'update' => ['username', 'phone', 'password'],
];
}
public function rules()
{
return [
...
]

public function create(){
if($this->validate(){}else{}
}

public function update(){
if($this->validate(){}else{}
}

И в этом случае для $model->update будет вызвана валидация и на телефон? (пример вымышлен, конечно)
>>555792
Надо подтвердить телефон автора, выслав смс, поэтому только числа и будет ещё ограничение на +7/8. Хотя сейчас подумал, что, может быть, лучше сделать свободный формат и потом выделять оттуда числа и уже с этим работать.
#535 #556020
123
#536 #556028
#537 #556039
У нас теперь есть стата. И она показывает, что в треде 109 - 1 лалок. Много. Но почему это никак не отражается на количестве выкладывающих свои поделки? Их от силы человек 15.
#538 #556042
>>555793

> имея на руках id юзера получить все его файлы.



1) $fileFepository->findByUser($user); (findByUser это магия доктрины, также там есть методы вида findOneByXXX)

Если использовать findBy(...) то можно также указать сортировку и лимит. Не знаю можно ли указать их с findByUser.

2) $user->getFiles() если у тебя настроена связь между сущностями (если нет, настрой)

Насчет прокси. Доктрина создает для каждого твоего класса сущности прокси-класс который от него наследуется (и потому совместим с ним и содержит все поля и методы). Также есть прокси-коллекции. Прокси подставляются вместо связанных сущностей. Допустим у тебя есть класс User и у юзера есть файлы и комментарии, файлы хранятся в поле $files, комментарии в $comments:

class User
{
...
@ORM\OneToMany(....)
...
private $files;
...

Когда ты загружаешь объект User, допустим через find('User', $id) доктрина должна что-то записать в эти поля, логично? Но выбирать список всех комментариев и файлов для каждого пользователя — накладно, потому она вместо коллекции файлов и комментариев вставляет туда прокси-коллекции. При обращении к этим прокси-коллекциями (например попытке получить элемент из них, или число элементов в них) происходит загрузка сущностей через SQL запрос.

Ну к примеру если мы напишем

foreach ($this->files as $file) {

То в момент начала foreach, когда он попытается взять первый элемент, будет выполнен запрос

SELECT × FROM files WHERE user_id = ?

И коллекция заполнится нужными файлами. И в дальнейшем уже эта коллекция не будет обращаться к базе.

Это называется ленивая загрузка. Ленивая загрузка требует по 1 запросу для каждой коллекции, то есть есть у тебя 5 юзеров и ты хочешь у каждого получить файлы, будет 5 SQL запросов.

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

SELECT u, f
FROM User u
LEFT JOIN u.files f // обрати внимание, если ты напишешь JOIN File f то в SQL получится JOIN без ON и запрос будет очень медленный
WHERE u.name LIKE '%Ivan%'

Это заставит доктрину сделать запрос вида

SELECT u.×, f.× FROM user u LEFT JOIN file f ON f.user_id = u.id ...

И во всех юзерах заполнить поле $files.

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

Другой вариант - писать в классе аннотацию fetch="EAGER" ( http://doctrine-orm.readthedocs.org/projects/doctrine-orm/en/latest/reference/annotations-reference.html#onetomany ) у связи, которая будет всегда принудительно загружать ее жадно. Не уверен что это хорошая идея так как оно не отключается.

Также, прокси можно запросить у доктрины явно:

http://doctrine-orm.readthedocs.org/projects/doctrine-orm/en/latest/reference/advanced-configuration.html#proxy-objects

$item = $em->getReference('Item', $itemId);

Это либо вернет объект Item если объект с таким id уже ранее загружался и хранится в Identity Map, либо создаст прокси (класса-наследника Item). В прокси хранится только id сущности. При вызове любого метода модели кроме getId произойдет ленивая загрузка и прокси будет заполнен данными из базы.

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

зачем это нужно? Ну например чтобы удалить сущность не загружая ее в память:

$item = $em->getReference('Item', $itemId);
$em->remove($item);
$em->flush();

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

А, и надеюсь ты в курсе других особенностей доктрины вроде Identity Map или Unit Of Work. Это надо знать чтобы эффективно ей пользоваться и уметь разбираться в случае багов.

http://odiszapc.ru/doctrine/working-with-objects/#882
http://odiszapc.ru/doctrine/working-with-objects/#82

Ну и английский мануал тут:

http://doctrine-orm.readthedocs.org/projects/doctrine-orm/en/latest/

Надеюсь что концепция прокси тебе понятна.

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

> Я ведь правильно понимаю, что конструкции вида:


> $files = $em->getRepository("File")->findBy(array('user' => $user->getId()));


> и


> $files = $user->getFiles();


> загрузят лишь массив прокси-объектов


Нет, неправильно.
#538 #556042
>>555793

> имея на руках id юзера получить все его файлы.



1) $fileFepository->findByUser($user); (findByUser это магия доктрины, также там есть методы вида findOneByXXX)

Если использовать findBy(...) то можно также указать сортировку и лимит. Не знаю можно ли указать их с findByUser.

2) $user->getFiles() если у тебя настроена связь между сущностями (если нет, настрой)

Насчет прокси. Доктрина создает для каждого твоего класса сущности прокси-класс который от него наследуется (и потому совместим с ним и содержит все поля и методы). Также есть прокси-коллекции. Прокси подставляются вместо связанных сущностей. Допустим у тебя есть класс User и у юзера есть файлы и комментарии, файлы хранятся в поле $files, комментарии в $comments:

class User
{
...
@ORM\OneToMany(....)
...
private $files;
...

Когда ты загружаешь объект User, допустим через find('User', $id) доктрина должна что-то записать в эти поля, логично? Но выбирать список всех комментариев и файлов для каждого пользователя — накладно, потому она вместо коллекции файлов и комментариев вставляет туда прокси-коллекции. При обращении к этим прокси-коллекциями (например попытке получить элемент из них, или число элементов в них) происходит загрузка сущностей через SQL запрос.

Ну к примеру если мы напишем

foreach ($this->files as $file) {

То в момент начала foreach, когда он попытается взять первый элемент, будет выполнен запрос

SELECT × FROM files WHERE user_id = ?

И коллекция заполнится нужными файлами. И в дальнейшем уже эта коллекция не будет обращаться к базе.

Это называется ленивая загрузка. Ленивая загрузка требует по 1 запросу для каждой коллекции, то есть есть у тебя 5 юзеров и ты хочешь у каждого получить файлы, будет 5 SQL запросов.

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

SELECT u, f
FROM User u
LEFT JOIN u.files f // обрати внимание, если ты напишешь JOIN File f то в SQL получится JOIN без ON и запрос будет очень медленный
WHERE u.name LIKE '%Ivan%'

Это заставит доктрину сделать запрос вида

SELECT u.×, f.× FROM user u LEFT JOIN file f ON f.user_id = u.id ...

И во всех юзерах заполнить поле $files.

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

Другой вариант - писать в классе аннотацию fetch="EAGER" ( http://doctrine-orm.readthedocs.org/projects/doctrine-orm/en/latest/reference/annotations-reference.html#onetomany ) у связи, которая будет всегда принудительно загружать ее жадно. Не уверен что это хорошая идея так как оно не отключается.

Также, прокси можно запросить у доктрины явно:

http://doctrine-orm.readthedocs.org/projects/doctrine-orm/en/latest/reference/advanced-configuration.html#proxy-objects

$item = $em->getReference('Item', $itemId);

Это либо вернет объект Item если объект с таким id уже ранее загружался и хранится в Identity Map, либо создаст прокси (класса-наследника Item). В прокси хранится только id сущности. При вызове любого метода модели кроме getId произойдет ленивая загрузка и прокси будет заполнен данными из базы.

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

зачем это нужно? Ну например чтобы удалить сущность не загружая ее в память:

$item = $em->getReference('Item', $itemId);
$em->remove($item);
$em->flush();

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

А, и надеюсь ты в курсе других особенностей доктрины вроде Identity Map или Unit Of Work. Это надо знать чтобы эффективно ей пользоваться и уметь разбираться в случае багов.

http://odiszapc.ru/doctrine/working-with-objects/#882
http://odiszapc.ru/doctrine/working-with-objects/#82

Ну и английский мануал тут:

http://doctrine-orm.readthedocs.org/projects/doctrine-orm/en/latest/

Надеюсь что концепция прокси тебе понятна.

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

> Я ведь правильно понимаю, что конструкции вида:


> $files = $em->getRepository("File")->findBy(array('user' => $user->getId()));


> и


> $files = $user->getFiles();


> загрузят лишь массив прокси-объектов


Нет, неправильно.
#539 #556046
>>555793

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

$firstFileComments = $comment->getAuthor()->getFiles()->first()->getComments();

заметь что код не очень правильный: если у автора нет файлов то один из этапов вернет null. Исправить это предалгаю тебе самостоятельно.

Если тебе интересно, откуда я взял метод first(), то отсюда, из интерфейса который реализуют коллекции доктрины (а список файлов пользователя это коллекция): http://www.doctrine-project.org/api/common/2.1/class-Doctrine.Common.Collections.Collection.html

(рекомендую тебе иногда смотреть описание классов и какие у них есть методы, полезно).

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

Потому доктрина при загрузке объекта вставляет прокси-объекты и прокси-коллекции вместо связанных сущностей. А при обращении к ним лениво грузит данные для них.

А что происходит когда мы создаем объект, например User, что впишется в поля files и comments? В этом случае доктрина сделать ничего не может и заполнить их должен ты. У только что созданной сущности нет ни файлов ни комментариев потому просто впиши туда пустые коллекции:

use ...ArrayCollection;

class User
{
...
public function __construct()
{
$this->files = new ArrayCollection();
$this->comments = new ArrayCollection();
}
....

Таким образом если мы создаем объект, мы вписываем туда пустую ArrayCollection. Если мы загружаем объект, доктрина вписывает туда прокси-коллекции. Если мы загружаем юзера + его файлы, доктрина вписывает туда коллекцию с файлами. Таким образом в поле files всегда будет что-то что реализует интерфейс Collection и мы можем смело обращаться к этому полю не боясь что там окажется null или что-то еще.

И таким образом создается ощущение что все объекты находятся у нас в памяти и мы можем двигаться по их связям.
#539 #556046
>>555793

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

$firstFileComments = $comment->getAuthor()->getFiles()->first()->getComments();

заметь что код не очень правильный: если у автора нет файлов то один из этапов вернет null. Исправить это предалгаю тебе самостоятельно.

Если тебе интересно, откуда я взял метод first(), то отсюда, из интерфейса который реализуют коллекции доктрины (а список файлов пользователя это коллекция): http://www.doctrine-project.org/api/common/2.1/class-Doctrine.Common.Collections.Collection.html

(рекомендую тебе иногда смотреть описание классов и какие у них есть методы, полезно).

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

Потому доктрина при загрузке объекта вставляет прокси-объекты и прокси-коллекции вместо связанных сущностей. А при обращении к ним лениво грузит данные для них.

А что происходит когда мы создаем объект, например User, что впишется в поля files и comments? В этом случае доктрина сделать ничего не может и заполнить их должен ты. У только что созданной сущности нет ни файлов ни комментариев потому просто впиши туда пустые коллекции:

use ...ArrayCollection;

class User
{
...
public function __construct()
{
$this->files = new ArrayCollection();
$this->comments = new ArrayCollection();
}
....

Таким образом если мы создаем объект, мы вписываем туда пустую ArrayCollection. Если мы загружаем объект, доктрина вписывает туда прокси-коллекции. Если мы загружаем юзера + его файлы, доктрина вписывает туда коллекцию с файлами. Таким образом в поле files всегда будет что-то что реализует интерфейс Collection и мы можем смело обращаться к этому полю не боясь что там окажется null или что-то еще.

И таким образом создается ощущение что все объекты находятся у нас в памяти и мы можем двигаться по их связям.
#540 #556047
>>556039

109 я думаю это число уникальных IP. А ведь есть еще стесняши, которые только читают но не пишут.

Алсо 100 людям я и отвечать не буду успевать, пока уже доделывать робота для проверки. Вот надо с работой только разобраться.
#541 #556071
>>555794

> cascade = persist



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

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

Ну и помни что эти cascade не бесплатные, если для связи прописано persist, доктрина рекурсивно обходит связанные сущности в поисках не отслеживаемых, если связей с cascade=persist много то это потребует допольнительного времени.

Ну в твоем случае вряд ли, но просто имей в виду.
#542 #556074
Какой клиент выбрать для редиса? Что-то их больно много.
http://redis.io/clients#php

Еще проблема с faker: не могу понять в чем дело, но генерируемые им realText и password приводят к ошибке
Invalid parameter number: no parameters were bound
Вероятно дело в экранировании спецсимволов. Использую dao yii, странно что там не экранируется запрос.
Пришлось использовать скучный lorem text.
А жаль, realText выдает цитаты из "Мертвых душ".

Советы опа по оптимизации говнокода тоже не помешают.
https://github.com/nsdvw/classifieds/blob/master/protected/controllers/FakerController.php
Не могу сгенерировать больше 200000 объявлений, занимает почти час. Хотелось бы 10-20 миллионов.
Как бы ускорить? Могу выложить файл cachegrind, но там не очень понятно что можно сделать, видно только что 80% времени занимают обращения к faker.
http://rghost.ru/6n6FZlMVw

>>555363
Хорошая паста про многопоточность, понятно объяснил.
https://github.com/someApprentice/Cat-and-Mouse/ #543 #556079
>>553095

Ой, что-то я про тебя подзабыл, надеюсь ты не тратил зря время в ожидании.

https://github.com/someApprentice/Cat-and-Mouse/blob/master/index.php#L21

> <?php $cat->move(); ?>


> <?php $mouse->move(); ?>


Лучше вынести это в отдеьную функцию и сделать так:

foreach ($world->getAllAnimals() as $animal) {
$animal->move();
}

Ну только добавь тут еще проверку живое ли животное (оно могло быть съедено кем-то на одном из предыдущих шагов). Если список животных это массив то foreach делает копию и итерирует по ней и удаление животных по ходу дела не повлияет на цикл. Если же спсиок животных это SplObjectStorage то копии не делается, и удаленные животные не попадают в цикл.

Ну то есть надежнее сделать проверку живое ли оно еще.

Теперь по поводу алгоритма выбора хода. Он состоит из нескольких частей:

1. Получить список возможных ходов
2. Оценить каждый с помощью оценочной функции
3. Выбрать лучший
4. Выполнить его

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

Ну а сама последовательность этих 4 действий общая для всех.

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

- алгоритм выполнения хода из 4 шагов, функция выбора лучшего хода - можно в классе Animal
- получение списка ходов, оценочная функция, выполнение хода - в классах соответствующих животных.

У тебя как-то все не так. Например функция оценки одного хода, у тебя не вынесена отдельно, а намертво впаяна в цикл оценки ходов, и она почему-то в базовом классе: https://github.com/someApprentice/Cat-and-Mouse/blob/master/Classes/Animal.php#L94

Из-за этого метод получился немного запутанным, он мог бы быть чище.

По самой оценке замечания такие:

Ты странно учитываешь сумму расстояний до кошек. В чем смысл именно суммирования? получаются странные результаты:

- рядом 1 кошка до которой 3 клетки: 3 балла
- рядом 4 кошки до которых 1 клетка: 4 балла
- вдали 2 кошки до которых 10 клеток: 20 баллов

Самый плохой ход тут второй — фактически в лапы кошек. Но по баллам это не очевидно. Если уж и складывать расстояния, то надо складывать обратные расстояния, 1/d, чтобы близкие кошки (как более опасные) давали большой вклад в сумму, а далекие — маленький.

Далее, само расстояние считается неверно: sqrt. Это декартово расстояние применимо в нашем мире где кошки ходят во все стороны с одинаковой скоростю. Но тут кошка по горизонтали ходит на расстояние 1, а по диагонали на sqrt(2) = 1.41, то есть игровой мир не изотропный. Тут надо считать не декартово расстояние а за сколько ходов до нас доберется кошка.

Наконец одного фактора маловато. Предлагаю взять три, с разными весами (то есть некоторые факторы вносят больший вклад в сумму):

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

Также, ты в базовый класс поместил свойства:

> protected $fears = array();


> protected $tracks = array();


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

> public $symbol;


Я бы сделал абстрактный метод getSymbol. Это позволяет легко менять вид животного в зависимости от состояния, а также заставляет всех потомков класса реализовать этот метод. В твоем случае, что если кто-то унаследует класс и не переопределит поле symbol, что будет? Ведь в коде нет никаких намеков что его надо переопределить.

> abstract public function chooseTheMovement($move);


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

> https://github.com/someApprentice/Cat-and-Mouse/blob/master/Classes/Animal.php#L97


> for ($x = $this->getX() - $this->getSpeed(); $x <= $this->getX() + $this->getSpeed(); $x++) {


Ты слишком много команд засунул в строку и ее тяжело читать. Тут надо вынести выражения врожде $this->getX() - $this->getSpeed() в переменные.

> if ($this->getWorld()->validateCoordinates($x, $y) or $this->getWorld()->determineTheObject($x, $y)) {


> continue


Во-первых странно что при ошибке validate вернет true, обычно true возвращают когда все ок. Далее, я бы назвал функцию более конкретно: isInsideMap, находится ли точка внутри карты. Вторая часть мне непонятна, она не позволяет кошке рассматривать занятые мышкой клетки. С другой стороны мышка не может ходить на занятые клетки. Как тут поступить? Есть 2 варианта:

- сделать отдельную, свою для каждого животного функцию, определяющую может ли оно сходить на данную клетку или нет. Плохо, так как добавляется еще одна функция вдобавок к оценочной.
- перенести проверку в метод определения возможных ходов
- перенести проверку в оценочную функцию. Сделать специальную оценку, например const CANNOT_MOVE = -1000; которая говорит что ход на эту клетку запрещен и его не надо рассматривать.

Также у тебя не учтено что мышка не ходит по диагонали.

Наверно я тебя запутал, потому задавай вопросы, думаю тут есть о чем поговорить.
https://github.com/someApprentice/Cat-and-Mouse/ #543 #556079
>>553095

Ой, что-то я про тебя подзабыл, надеюсь ты не тратил зря время в ожидании.

https://github.com/someApprentice/Cat-and-Mouse/blob/master/index.php#L21

> <?php $cat->move(); ?>


> <?php $mouse->move(); ?>


Лучше вынести это в отдеьную функцию и сделать так:

foreach ($world->getAllAnimals() as $animal) {
$animal->move();
}

Ну только добавь тут еще проверку живое ли животное (оно могло быть съедено кем-то на одном из предыдущих шагов). Если список животных это массив то foreach делает копию и итерирует по ней и удаление животных по ходу дела не повлияет на цикл. Если же спсиок животных это SplObjectStorage то копии не делается, и удаленные животные не попадают в цикл.

Ну то есть надежнее сделать проверку живое ли оно еще.

Теперь по поводу алгоритма выбора хода. Он состоит из нескольких частей:

1. Получить список возможных ходов
2. Оценить каждый с помощью оценочной функции
3. Выбрать лучший
4. Выполнить его

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

Ну а сама последовательность этих 4 действий общая для всех.

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

- алгоритм выполнения хода из 4 шагов, функция выбора лучшего хода - можно в классе Animal
- получение списка ходов, оценочная функция, выполнение хода - в классах соответствующих животных.

У тебя как-то все не так. Например функция оценки одного хода, у тебя не вынесена отдельно, а намертво впаяна в цикл оценки ходов, и она почему-то в базовом классе: https://github.com/someApprentice/Cat-and-Mouse/blob/master/Classes/Animal.php#L94

Из-за этого метод получился немного запутанным, он мог бы быть чище.

По самой оценке замечания такие:

Ты странно учитываешь сумму расстояний до кошек. В чем смысл именно суммирования? получаются странные результаты:

- рядом 1 кошка до которой 3 клетки: 3 балла
- рядом 4 кошки до которых 1 клетка: 4 балла
- вдали 2 кошки до которых 10 клеток: 20 баллов

Самый плохой ход тут второй — фактически в лапы кошек. Но по баллам это не очевидно. Если уж и складывать расстояния, то надо складывать обратные расстояния, 1/d, чтобы близкие кошки (как более опасные) давали большой вклад в сумму, а далекие — маленький.

Далее, само расстояние считается неверно: sqrt. Это декартово расстояние применимо в нашем мире где кошки ходят во все стороны с одинаковой скоростю. Но тут кошка по горизонтали ходит на расстояние 1, а по диагонали на sqrt(2) = 1.41, то есть игровой мир не изотропный. Тут надо считать не декартово расстояние а за сколько ходов до нас доберется кошка.

Наконец одного фактора маловато. Предлагаю взять три, с разными весами (то есть некоторые факторы вносят больший вклад в сумму):

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

Также, ты в базовый класс поместил свойства:

> protected $fears = array();


> protected $tracks = array();


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

> public $symbol;


Я бы сделал абстрактный метод getSymbol. Это позволяет легко менять вид животного в зависимости от состояния, а также заставляет всех потомков класса реализовать этот метод. В твоем случае, что если кто-то унаследует класс и не переопределит поле symbol, что будет? Ведь в коде нет никаких намеков что его надо переопределить.

> abstract public function chooseTheMovement($move);


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

> https://github.com/someApprentice/Cat-and-Mouse/blob/master/Classes/Animal.php#L97


> for ($x = $this->getX() - $this->getSpeed(); $x <= $this->getX() + $this->getSpeed(); $x++) {


Ты слишком много команд засунул в строку и ее тяжело читать. Тут надо вынести выражения врожде $this->getX() - $this->getSpeed() в переменные.

> if ($this->getWorld()->validateCoordinates($x, $y) or $this->getWorld()->determineTheObject($x, $y)) {


> continue


Во-первых странно что при ошибке validate вернет true, обычно true возвращают когда все ок. Далее, я бы назвал функцию более конкретно: isInsideMap, находится ли точка внутри карты. Вторая часть мне непонятна, она не позволяет кошке рассматривать занятые мышкой клетки. С другой стороны мышка не может ходить на занятые клетки. Как тут поступить? Есть 2 варианта:

- сделать отдельную, свою для каждого животного функцию, определяющую может ли оно сходить на данную клетку или нет. Плохо, так как добавляется еще одна функция вдобавок к оценочной.
- перенести проверку в метод определения возможных ходов
- перенести проверку в оценочную функцию. Сделать специальную оценку, например const CANNOT_MOVE = -1000; которая говорит что ход на эту клетку запрещен и его не надо рассматривать.

Также у тебя не учтено что мышка не ходит по диагонали.

Наверно я тебя запутал, потому задавай вопросы, думаю тут есть о чем поговорить.
#544 #556082
>>553095

> Остается актуальной проблема


Я там написал 3 варианта решения. Насчет tracks — я предлагаю убрать ее из базового класса.

Мне нравится идея поместить проверку занятости клетки либо в метод получения списка ходов, который уникален для животного (хорошо), либо в оценочную функцию (не так хорошо, это же не ее дело, но на практике не всегда все гладко выходит).
#545 #556086
>>556042
Спасибо за подробное объяснение. То, что коллекции грузятся целиком, стоит лишь запросить хотя бы 1 её элемент, я упустил. А в целом как работают прокси, зачем нужны Identity Map и Unit of Work, какие возможности они дают и какие ограничения накладывают вроде понимаю.

>>556071

>У тебя же наверно файлы можно загружать только для существующих пользователей?


Теперь уже да. Но когда я начинал делать фалообменник, у меня при загрузке на сервер к файлу цеплялся объект-юзер созданный на основе кук, которого могло и не быть в базе (новый пользователь = объект с пустыми полями, если кук нет).
Теперь cascade=persist не нужен, т. к. теперь первое, что я делаю при заходе пользователя на сайт - это идентифицирую его по кукам, а если они пустые - то создаю запись в базе с cookie-токеном.

Вообще, наверно выложу-ка я его уже на гитхаб. Основной функционал в принципе готов.
#546 #556104
https://github.com/blackberryJam/filehosting
Вот. Файлообменник. ОП, посмотри пожалуйста.

Так-то ещё сыровато. На некоторые действия ответы пока не в виде html-страничек, а просто текста (а кое-где и вовсе редирект).

Что есть: регистрация, простой личный кабинет с файлами пользователя и возможностью отредактировать личную информацию, возможность загружать и удалять (если ты владелец) файлы, загрузка файлов драг-н-дропом (можно пачками).
Чего ещё нет: комментариев и превьюшек к изображениям.
68 Кб, 550x413
#547 #556117
>>555363

>Процессор может выполнять параллельно столько потоков инструкций, сколько в нем ядер.


Опять тупой оп обосрался и не знает про Hyper-threading. Дальше даже не читал этот нубский высер.
Аноны, валите из треда, у этого школьника куча ошибок в пастах и заданиях.
#548 #556125
>>556117
А чо ты тута делаешь, м?
#549 #556163
>>553769

> ни одного готового решения


хе-хе-хе это хорошо, пусть люди сами думают

По твоему решению: немного запутанно получилось. Ты собираешь 2 строки, буквы слева и буквы справа, но можно ведь сделать проще. Заводишь переменную, кладешь в нее изначально допустим, 1, а если встречаешь 2 несовпадающие буквы, кладешь 0 и выходишь из цикла.

В конце проверяешь, 0 там или 1.

Ну и тут еще можно исправить:

> if ($symbol1 == $symbol2){


> } else {


> break;


> }



if ($symbol1 != $symbol2)

!= значит «не равно»

>>553815

Неплохо для начала, но структура стиха не та, и вот тут вот:

> foreach($word as $key=>$value){



Вместо цикла надо брать элемент массива с помощью [$key]

Ну и еще, есть функция array_rand() с которой будет проще.
#549 #556163
>>553769

> ни одного готового решения


хе-хе-хе это хорошо, пусть люди сами думают

По твоему решению: немного запутанно получилось. Ты собираешь 2 строки, буквы слева и буквы справа, но можно ведь сделать проще. Заводишь переменную, кладешь в нее изначально допустим, 1, а если встречаешь 2 несовпадающие буквы, кладешь 0 и выходишь из цикла.

В конце проверяешь, 0 там или 1.

Ну и тут еще можно исправить:

> if ($symbol1 == $symbol2){


> } else {


> break;


> }



if ($symbol1 != $symbol2)

!= значит «не равно»

>>553815

Неплохо для начала, но структура стиха не та, и вот тут вот:

> foreach($word as $key=>$value){



Вместо цикла надо брать элемент массива с помощью [$key]

Ну и еще, есть функция array_rand() с которой будет проще.
#550 #556165
>>553839

> http://ideone.com/7WoeiH



> foreach($splitText as $key => $value){


Что-то у тебя там аж 3 цикла, не многовато ли? Предлагаю оставить 1 цикл, а функции переделать чтобы они принимали не массив предложений, а одно предложение за раз. Тогда например функция makeFirstLetterUppercase сократится до пары строчек.

> $encoding = 'utf-8'


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

> /[,]/


То же самое что /,/ - запятая не спецсимвол (их список по моему перечислен в конце урока а также есть тут: http://php.net/manual/ru/regexp.reference.meta.php (проверь себя: все ли ты знаешь?) )

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

В остальном, верно.

> http://ideone.com/wtioNY



> $splitText


Лучше назвать $sentences - предложения.

> foreach ($splitText as $key => $value){


$key не используется и потому не нужно его писать
$value ничего не значит. Нужно давать нормальные имена, например $sentence, иначе тяжело понять код.

> preg_split('/[,?!;]?\\s/'


По идее ?! там встретиться не может, мы же по ним разбиваем на предложения

> $value = preg_split('/[,?!;]?\\s/', $value, 0, PREG_SPLIT_NO_EMPTY);


Надо называть переменные нормально, например $words = preg_split(... $sentence) - смотри, насколько понятнее.

> return implode('', makeFirstletterUppercase($splitText));


Это лучше разбить на 2 строчки, и сделать чтобы makeFirstletterUppercase принимала одно предложение а не массив.

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

> http://ideone.com/OL6z7l



> }


> elseif


мелкая придирка: else/elseif пишутся на одной строке со скобками, то есть

} elseif (...) {

> else { return $word5; }


Пиши в 3 строчки, не жалей место.

> $number = floor($number/1000%100);


Порядок действий неправильный. Ты делишь $number на 1000, получаешь дробь и дальше пытаешься найти остаток от деления. А надо сначала округлять а потом брать остаток.

> function checkFemale($number) {


Эта функция не нужна. В женском роде пишутся тысячи (1 тысяча), а рубли и миллионы всегда в мужском. Тебе просто надо, если дали значение $isFemale == 1 заменять в массиве $spelling значения для чисел 1 и 2. А далее уже работать с этим массивом как обычно.

> return preg_replace('/ноль/','',$spelling[floor($number/100)100]." ".$spelling[floor($number%100/10)10]." ".$femaleSpelling[$number%10]);


Так писать нельзя. Это же невозможно прочесть, и ошибку тут допустить, например перепутав скобку, очень легко. Ну и preg_replace выглядит как костыль. Это надо переделать.

Вообще, есть мягкое ограничение в 80 символов на длину строки - придерживайся его.

Ну и как я выше написал, для женского рода надо просто заменить 2 элемента в $spelling и все.

> smallNumberToText($number, $isFemale) {


Эта функция слишком запутанная и в ней слишком много условий, надо упростить. Например, так:

список слов = [];
Если (в числе есть сотни) {
добавить в список число сотен;
}
...

Костыли с preg_replace надо везде убрать, они затрудняют понимание кода.

> elseif($number == 1000) {


> return "одня тысяча рублей";


Тут незачем делать отдельный случай.

> numberToText($number) {


тут очень много копипасты, надо всю ее убрать и сделать общий алгоритм, по типу:

если (есть миллионы) {
добавить в список число миллионов;
}

В общем, то, что есть, никуда не годится. Код тяжело понять и потому я не могу даже сказать правильно он работает или нет.
#550 #556165
>>553839

> http://ideone.com/7WoeiH



> foreach($splitText as $key => $value){


Что-то у тебя там аж 3 цикла, не многовато ли? Предлагаю оставить 1 цикл, а функции переделать чтобы они принимали не массив предложений, а одно предложение за раз. Тогда например функция makeFirstLetterUppercase сократится до пары строчек.

> $encoding = 'utf-8'


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

> /[,]/


То же самое что /,/ - запятая не спецсимвол (их список по моему перечислен в конце урока а также есть тут: http://php.net/manual/ru/regexp.reference.meta.php (проверь себя: все ли ты знаешь?) )

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

В остальном, верно.

> http://ideone.com/wtioNY



> $splitText


Лучше назвать $sentences - предложения.

> foreach ($splitText as $key => $value){


$key не используется и потому не нужно его писать
$value ничего не значит. Нужно давать нормальные имена, например $sentence, иначе тяжело понять код.

> preg_split('/[,?!;]?\\s/'


По идее ?! там встретиться не может, мы же по ним разбиваем на предложения

> $value = preg_split('/[,?!;]?\\s/', $value, 0, PREG_SPLIT_NO_EMPTY);


Надо называть переменные нормально, например $words = preg_split(... $sentence) - смотри, насколько понятнее.

> return implode('', makeFirstletterUppercase($splitText));


Это лучше разбить на 2 строчки, и сделать чтобы makeFirstletterUppercase принимала одно предложение а не массив.

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

> http://ideone.com/OL6z7l



> }


> elseif


мелкая придирка: else/elseif пишутся на одной строке со скобками, то есть

} elseif (...) {

> else { return $word5; }


Пиши в 3 строчки, не жалей место.

> $number = floor($number/1000%100);


Порядок действий неправильный. Ты делишь $number на 1000, получаешь дробь и дальше пытаешься найти остаток от деления. А надо сначала округлять а потом брать остаток.

> function checkFemale($number) {


Эта функция не нужна. В женском роде пишутся тысячи (1 тысяча), а рубли и миллионы всегда в мужском. Тебе просто надо, если дали значение $isFemale == 1 заменять в массиве $spelling значения для чисел 1 и 2. А далее уже работать с этим массивом как обычно.

> return preg_replace('/ноль/','',$spelling[floor($number/100)100]." ".$spelling[floor($number%100/10)10]." ".$femaleSpelling[$number%10]);


Так писать нельзя. Это же невозможно прочесть, и ошибку тут допустить, например перепутав скобку, очень легко. Ну и preg_replace выглядит как костыль. Это надо переделать.

Вообще, есть мягкое ограничение в 80 символов на длину строки - придерживайся его.

Ну и как я выше написал, для женского рода надо просто заменить 2 элемента в $spelling и все.

> smallNumberToText($number, $isFemale) {


Эта функция слишком запутанная и в ней слишком много условий, надо упростить. Например, так:

список слов = [];
Если (в числе есть сотни) {
добавить в список число сотен;
}
...

Костыли с preg_replace надо везде убрать, они затрудняют понимание кода.

> elseif($number == 1000) {


> return "одня тысяча рублей";


Тут незачем делать отдельный случай.

> numberToText($number) {


тут очень много копипасты, надо всю ее убрать и сделать общий алгоритм, по типу:

если (есть миллионы) {
добавить в список число миллионов;
}

В общем, то, что есть, никуда не годится. Код тяжело понять и потому я не могу даже сказать правильно он работает или нет.
#551 #556168
Рейт верстку.
http://namefuctionstar.esy.es/AmericaVip/

Алсо, наткнулся на статью на хабре про авто отправку смс клиенту при обработке заявки. Каким способом можно автоматом смски на номера слать, есть какой-то сайт, к апи которого нужно подключиться?
#552 #556183
>>553907

Я не знаю, не делал такое.

>>553993

Сделай свою компанию и работай так как нравится. Ну или просто найди другую работу.

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

>>554107

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

>>554111

Немного слоупочное дополнение, но если посмотреть код вот тут:

https://github.com/iAchilles/eavactiverecord/blob/master/EavActiveRecord.php#L78

Ты увидишь что там есть методы

> if ($this->hasEavAttribute($name))


> return $this->getEavAttribute($name);



То есть делать свои методы, как я посоветовал, не надо.

Соответственно пиши в шаблоне так:

{% if model.hasEavAttribute('price') %}
Price: {{ model.getEavAttribute('price') }}
...

> Но в случае если свойство равно null, и иссет пролетает мимо.


Тогда надо писать

{% if model.hasEavAttribute('price') and model.getEavAttribute('price') %}
...

Вообще, я тебе советую меньше полагаться на такую вот магию, которую дает твиг, и больше на явные вызовы, так как магия твига, как мы видим, не очень совмещается с магическими методами.
#552 #556183
>>553907

Я не знаю, не делал такое.

>>553993

Сделай свою компанию и работай так как нравится. Ну или просто найди другую работу.

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

>>554107

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

>>554111

Немного слоупочное дополнение, но если посмотреть код вот тут:

https://github.com/iAchilles/eavactiverecord/blob/master/EavActiveRecord.php#L78

Ты увидишь что там есть методы

> if ($this->hasEavAttribute($name))


> return $this->getEavAttribute($name);



То есть делать свои методы, как я посоветовал, не надо.

Соответственно пиши в шаблоне так:

{% if model.hasEavAttribute('price') %}
Price: {{ model.getEavAttribute('price') }}
...

> Но в случае если свойство равно null, и иссет пролетает мимо.


Тогда надо писать

{% if model.hasEavAttribute('price') and model.getEavAttribute('price') %}
...

Вообще, я тебе советую меньше полагаться на такую вот магию, которую дает твиг, и больше на явные вызовы, так как магия твига, как мы видим, не очень совмещается с магическими методами.
#553 #556185
>>554115

В общем верно.

>>554131

В JS любая функция при создании захватывает переменные вокруг и таким образом становится замыканием (замыкание = функция + захваченные ей внешние переменные). Может тебе тоже стоит наши задачки из ОП-поста на JS порешать?

>>554134

У меня есть получше ссылки:

http://habrahabr.ru/post/208442/
http://blog.byndyu.ru/2009/10/solid.html (хорошо и подробно описано)

Имей в виду что паттерны и SOLID это для тех у кого уже есть опыт работы с кодом, особенно с большим. Такой человек увидит в них ответы на вопросы «как улучшить этот код», а вот начинающему будет сложновато. НО ты попробуй, что-нибудь да усвоишь. Принцип подстановки Лисков например вполне понятный.

>>554362

Это штука типа генератора URL?

public function getNewsUrl($newsId)
{
return "/news/{$newsId}";
}

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

>>554445

Ты прав.

>>554532

На CSS

>>554560

> Клуб изучающих PHP



>>554682

А зачем ты перепечатываешь код? Шаблоны проектирования не совсем для начинающих, а для тех кто работал с кодом большого объема. Тебе надо сначала сам ООП нормально выучить (сделать наши задачи на кошки-мышки и вектор), проекты какие-то поделать, например наших студентов и файлообменник, а на них уже можно шаблоны применять.

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

>>554765

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

>>554782

> паблики


> программисты


Там наверно программисты уровня «вчера установил новую тему на винду». Попроси их своими словами описать что им не нравится в PHP.

>>555217

Первый раз слышу про этот сайт. У нас пока были версии про доброчан и конфа в слаке (но там нужна регистрация).

>>555353

Не знаю. Поищи похожие вакансии и сравни.
#553 #556185
>>554115

В общем верно.

>>554131

В JS любая функция при создании захватывает переменные вокруг и таким образом становится замыканием (замыкание = функция + захваченные ей внешние переменные). Может тебе тоже стоит наши задачки из ОП-поста на JS порешать?

>>554134

У меня есть получше ссылки:

http://habrahabr.ru/post/208442/
http://blog.byndyu.ru/2009/10/solid.html (хорошо и подробно описано)

Имей в виду что паттерны и SOLID это для тех у кого уже есть опыт работы с кодом, особенно с большим. Такой человек увидит в них ответы на вопросы «как улучшить этот код», а вот начинающему будет сложновато. НО ты попробуй, что-нибудь да усвоишь. Принцип подстановки Лисков например вполне понятный.

>>554362

Это штука типа генератора URL?

public function getNewsUrl($newsId)
{
return "/news/{$newsId}";
}

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

>>554445

Ты прав.

>>554532

На CSS

>>554560

> Клуб изучающих PHP



>>554682

А зачем ты перепечатываешь код? Шаблоны проектирования не совсем для начинающих, а для тех кто работал с кодом большого объема. Тебе надо сначала сам ООП нормально выучить (сделать наши задачи на кошки-мышки и вектор), проекты какие-то поделать, например наших студентов и файлообменник, а на них уже можно шаблоны применять.

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

>>554765

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

>>554782

> паблики


> программисты


Там наверно программисты уровня «вчера установил новую тему на винду». Попроси их своими словами описать что им не нравится в PHP.

>>555217

Первый раз слышу про этот сайт. У нас пока были версии про доброчан и конфа в слаке (но там нужна регистрация).

>>555353

Не знаю. Поищи похожие вакансии и сравни.
#554 #556186
>>555454

my bad

>>555523

Пиши код.

>>555561

Режим работы себе установи. Иначе у тебя будет постоянно режим студента накануне экзамена.

>>555593

Банально перекодировать между UTF-32 и UTF-8.

>>555621

> Мне нужен скрипт с сайтом и как это использовать


Это долго объяснять, так как непонятно что ты знаешь, а что нет, если ничего то тут на целый учебник выйдет.

>>555733

> если я использую pushState, как сделать, чтобы, допустим, айди не добавлялся 2 раза к юрл?


пушить абсолютный, а не относительный URL (работают телепаты угадывающие суть вопроса по смутному описанию).

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


Вот это плохая идея: ты прячешь комментарии за 2 клика, ты как бы говоришь этим пользователям что их мнению тут не особо и рады. Я тебе советую сделать общие комментарии на галерею, если только у тебя их не сотни.

>>555739

Ты знаешь что такое Active Record? Ты читал документацию Юи 2?

> но никак не могу найти метода для базы данных


У модели есть метод save но ты должен сначала прочесть документацию. Не только по ACtive Record, а в принципе весь официальный туториал.

>>555848

> И в этом случае для $model->update будет вызвана валидация и на телефон? (пример вымышлен, конечно)


Наверно да

> Надо подтвердить телефон автора,


Я бы не стал вводить телефон на левом сайте.

Почитай еще и про формы: https://github.com/yiisoft/yii2/blob/master/docs/guide-ru/input-forms.md

И вообще, найди время весь этот гайд пролистать.
#554 #556186
>>555454

my bad

>>555523

Пиши код.

>>555561

Режим работы себе установи. Иначе у тебя будет постоянно режим студента накануне экзамена.

>>555593

Банально перекодировать между UTF-32 и UTF-8.

>>555621

> Мне нужен скрипт с сайтом и как это использовать


Это долго объяснять, так как непонятно что ты знаешь, а что нет, если ничего то тут на целый учебник выйдет.

>>555733

> если я использую pushState, как сделать, чтобы, допустим, айди не добавлялся 2 раза к юрл?


пушить абсолютный, а не относительный URL (работают телепаты угадывающие суть вопроса по смутному описанию).

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


Вот это плохая идея: ты прячешь комментарии за 2 клика, ты как бы говоришь этим пользователям что их мнению тут не особо и рады. Я тебе советую сделать общие комментарии на галерею, если только у тебя их не сотни.

>>555739

Ты знаешь что такое Active Record? Ты читал документацию Юи 2?

> но никак не могу найти метода для базы данных


У модели есть метод save но ты должен сначала прочесть документацию. Не только по ACtive Record, а в принципе весь официальный туториал.

>>555848

> И в этом случае для $model->update будет вызвана валидация и на телефон? (пример вымышлен, конечно)


Наверно да

> Надо подтвердить телефон автора,


Я бы не стал вводить телефон на левом сайте.

Почитай еще и про формы: https://github.com/yiisoft/yii2/blob/master/docs/guide-ru/input-forms.md

И вообще, найди время весь этот гайд пролистать.
https://github.com/nsdvw/classifieds/ #555 #556188
>>556074

> Какой клиент выбрать для редиса?


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

С остальными не работал. Ты бы посмотрел, мои знания может уже устарели.

> Еще проблема с faker: не могу понять в чем дело, но генерируемые им realText и password приводят к ошибке


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

> Вероятно дело в экранировании спецсимволов. Использую dao yii, странно что там не экранируется запрос.


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

> Не могу сгенерировать больше 200000 объявлений, занимает почти час.


Что именно тормозит? Профайлинг делал? mysql вставит 200 000 записей за минут 5-15.

Алсо почитал бы: https://dev.mysql.com/doc/refman/5.5/en/optimizing-innodb-bulk-data-loading.html (англ)

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

Алсо проверь не в генераторе ли случайных чисел (или array_rand) проблема. Проверь объем текстов, советую делать поменьше, ибо база забивается, а разницы особой нет.

> видно только что 80% времени занимают обращения к faker.


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

> Delete this file on production!


Это значит что файл там будет аж в нескольких экземплярах. Лучше сделать отдельную папку для таких файлов либо поставить там проверку что окркжение имеет тип dev а не production.

> set_time_limit(3600 * 3);


В CLI режиме ограничения нет, а через браузер никто не запускает скрипты работающие больше 10 секунд. Пиши CLI-скрипт: http://www.yiiframework.com/doc/guide/1.1/ru/topics.console

Гайд по ком. строке: http://www.yiiframework.com/doc/guide/1.1/ru/topics.console
Еще больше: https://gist.github.com/codedokode/420c8c12a1edae25f0ec#file-linux1-md

Методы великоваты, посмотри что можно вынести в отдельные функции.

> https://github.com/nsdvw/classifieds/blob/master/protected/controllers/FakerController.php#L41


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

> echo date('H:i:s') . ' Finish!<br>';


Там наверно что-то готовое есть для логгирования в командах.

> $user['password'] = $faker->word . $faker->word;


им всем можно ставить один пароль, тебе же логиниться проще будет

> createLegion(Faker\Generator $faker,


$faker лучше сделать полем класса

> ошибка при использовании realText:


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

Подготовленные запросы кстати позволяют экономить время базы на парсинг SQL кода, так как он парсится только первый раз.

> private function attachEavAttributes()


тут надо разбить на более мелкие методы

Вместо того чтобы добавлять EAV отдельным блоком, лучше добавлять их при создании объявления, тогда не нужна будет куча селектов.

Насчет профайлинга: если у тебя функция работает очень быстро, но вызывается очень много раз, то профайлер может не дать тебе точных чисел. Придется делать «профайлер бедного человека». Посмотри, из каких шагов состоит создание записей (генерация случайных данных, создание команды, выполнение), и протестируй каждй шаг отдельно, просто вызывая его в цикле N раз и меряя общее время. Таким образом попробуй понять сколько времени на что уходит.

Простор для разгона однозначно есть.

Проверь не включен ли логгер запросов Юи/отладчик Юи и не логгирует ли он все тысячи запросов. Проверь на сколько загружен процессор во время работы скрипта. Проверь не съел ли твой скрипт всю память (в линуксе это команда top, а лучше установить htop, он цветной). Проверь сильно ли нагружен диск программой iostat и iotop: http://serverfault.com/questions/9428/how-can-i-monitor-hard-disk-load-on-linux

Алсо держи мой генератор (тоже лапша та еще так как писалось на 1 раз): https://github.com/codedokode/board-test-scripts (inb4: где faker? я тогда не знал про него)
https://github.com/nsdvw/classifieds/ #555 #556188
>>556074

> Какой клиент выбрать для редиса?


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

С остальными не работал. Ты бы посмотрел, мои знания может уже устарели.

> Еще проблема с faker: не могу понять в чем дело, но генерируемые им realText и password приводят к ошибке


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

> Вероятно дело в экранировании спецсимволов. Использую dao yii, странно что там не экранируется запрос.


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

> Не могу сгенерировать больше 200000 объявлений, занимает почти час.


Что именно тормозит? Профайлинг делал? mysql вставит 200 000 записей за минут 5-15.

Алсо почитал бы: https://dev.mysql.com/doc/refman/5.5/en/optimizing-innodb-bulk-data-loading.html (англ)

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

Алсо проверь не в генераторе ли случайных чисел (или array_rand) проблема. Проверь объем текстов, советую делать поменьше, ибо база забивается, а разницы особой нет.

> видно только что 80% времени занимают обращения к faker.


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

> Delete this file on production!


Это значит что файл там будет аж в нескольких экземплярах. Лучше сделать отдельную папку для таких файлов либо поставить там проверку что окркжение имеет тип dev а не production.

> set_time_limit(3600 * 3);


В CLI режиме ограничения нет, а через браузер никто не запускает скрипты работающие больше 10 секунд. Пиши CLI-скрипт: http://www.yiiframework.com/doc/guide/1.1/ru/topics.console

Гайд по ком. строке: http://www.yiiframework.com/doc/guide/1.1/ru/topics.console
Еще больше: https://gist.github.com/codedokode/420c8c12a1edae25f0ec#file-linux1-md

Методы великоваты, посмотри что можно вынести в отдельные функции.

> https://github.com/nsdvw/classifieds/blob/master/protected/controllers/FakerController.php#L41


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

> echo date('H:i:s') . ' Finish!<br>';


Там наверно что-то готовое есть для логгирования в командах.

> $user['password'] = $faker->word . $faker->word;


им всем можно ставить один пароль, тебе же логиниться проще будет

> createLegion(Faker\Generator $faker,


$faker лучше сделать полем класса

> ошибка при использовании realText:


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

Подготовленные запросы кстати позволяют экономить время базы на парсинг SQL кода, так как он парсится только первый раз.

> private function attachEavAttributes()


тут надо разбить на более мелкие методы

Вместо того чтобы добавлять EAV отдельным блоком, лучше добавлять их при создании объявления, тогда не нужна будет куча селектов.

Насчет профайлинга: если у тебя функция работает очень быстро, но вызывается очень много раз, то профайлер может не дать тебе точных чисел. Придется делать «профайлер бедного человека». Посмотри, из каких шагов состоит создание записей (генерация случайных данных, создание команды, выполнение), и протестируй каждй шаг отдельно, просто вызывая его в цикле N раз и меряя общее время. Таким образом попробуй понять сколько времени на что уходит.

Простор для разгона однозначно есть.

Проверь не включен ли логгер запросов Юи/отладчик Юи и не логгирует ли он все тысячи запросов. Проверь на сколько загружен процессор во время работы скрипта. Проверь не съел ли твой скрипт всю память (в линуксе это команда top, а лучше установить htop, он цветной). Проверь сильно ли нагружен диск программой iostat и iotop: http://serverfault.com/questions/9428/how-can-i-monitor-hard-disk-load-on-linux

Алсо держи мой генератор (тоже лапша та еще так как писалось на 1 раз): https://github.com/codedokode/board-test-scripts (inb4: где faker? я тогда не знал про него)
http://namefuctionstar.esy.es/AmericaVip/ #556 #556191
>>556086

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


Советую создавать только при первом действии (файл/комментарий), чтобы не забивать базу бесполезными пользователями-пустышками.

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

>>556168

http://namefuctionstar.esy.es/AmericaVip/

> Каким способом можно автоматом смски на номера слать, есть какой-то сайт, к апи которого нужно подключиться?


Гугли «API SMS шлюз». Там есть куча своих аспектов, например не у всех СМС хорошо доходят на все операторы и в разные страны, не все дают указать произвольный номер отправителя, итд. Все это платно разумеется, но не дорого.

Имей в виду что некоторые ориентированы на спам и с такими лучше не работать: можно попасть под фильтры операторов и сообщения будут теряться. Лучше брать тех что поизвестнее и покрупнее, давно на рынке и не ориентированы на спам рассылки (это часто по цене видно). Стоит также протестировать отправку самому.

По верстке:

- Стрелки на слайдере не по центру вертикально
- почта не кликабельна
- картинка с корзиной пикселизованная (дно тележки)
- в главном меню кликабельна только надпись, а черный косой блок на фоне - нет
- на втором слайдере зона для клика маленькая, да и по моему 2 слайдера перебор (по мне так и один это перебор, я их не люблю)
- в блоке «Голливудская улыбка» слева кликабельна только крошечная ссылка в которую еще попасть надо, а должен быть весь блок. Ты знаешь как неудобно в такие маленьие ссылки тыкать с планшета, на тачпаде, с заевшей мышкой? А ведь это все твои клиенты.
- блок «Голливудская улыбка» должен быть не только кликаьельным но и выделяться при наведении, давая обратную связь и намекая что можно на него нажать
- иконки соцсетей не становятся цветными при наведении
- некоторые тексты нереально мелкие (претензия к дизайнеру, вообще дизайн слабоват)
- сумма в корзине подчеркнута как будто это ссылка, но она не кликабельна (претензия к дизайну)
- на карточке товара некликабельна ни картинка, ни заголовок. Нет ссылки для перехода на страницу товара. Зато есть кнопка добавления, но ведь никто не добавит товар в корзину не почитав подробно о нем. Бред же. Открой например http://www.lamoda.ru/c/369/clothes-platiya/?genders=women и поищи здесь кнопку добавления в корзину. Так же обрати внимание на кликабельные зоны на карточке товара. Дизайнер и верстальщик оба не имеют понятия о поведении пользователя на сайте. Интерфейс я бы оценил на тройку с минусом, такие огрехи приведут к потере покупателей.
- сайт помечен как адаптивный в коде, но если посмотреть его в режиме эмуляции смартфона или планшета, никакой адаптивности нет, все разъезжается. Не копипасть тег meta viewport если ты не сделал адаптивную верстку.
- //maxcdn.bootstrapcdn.com/ - надежнее размещать библиотеки у себя, не надо подключать внещние скрипты, а то твой сайт ляжет вместе с CDN

> @font-face {


Сделано по моему неправильно, там нет разных форматов, только один формат.

HTML код это кошмар. Я ждал аккуратную лаконичную семантичную разметку. Но ощущение что откуда-то накопировали тегов и свалили в кучу.

> <img class="flag" src="bootstrap/images/flag.png" alt="flag">


Элементы оформления (в отличие от контента) надо делать через background-image.

> <p class="sliderTitle">


Надо hN использовать

> <h1><span class="sideYellow">/</span> Fitness одежда молодежной американской марки </h1>


Спан можно заменить на псевдоэлемент

> <div class="border"> </div>


Этого не должно быть в HTML коде, должно быть в CSS

Разметка карточки товара замусорена тегами, надо выкинуть оттуда все что относится к оформлению.

На странице может быть только один тег h1

> <div class="sticker small teeth">


> <div class="sticker small hair">


При натяжке на CMS будут проблемы если категории берутся из базы

> Голливудская <br>улыбка


br тут признак неквалифицированности верстальщика.

jQuery зачем-то подключен 2 раза.

Тег </html> потеряли.

CSS и JS я не смотрел, нет смысла тратить мое время на это. Это некачественная верстка на тройку с минусом, за которую тебе, как человеку который у нас учился (так ведь?) должно быть стыдно.
http://namefuctionstar.esy.es/AmericaVip/ #556 #556191
>>556086

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


Советую создавать только при первом действии (файл/комментарий), чтобы не забивать базу бесполезными пользователями-пустышками.

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

>>556168

http://namefuctionstar.esy.es/AmericaVip/

> Каким способом можно автоматом смски на номера слать, есть какой-то сайт, к апи которого нужно подключиться?


Гугли «API SMS шлюз». Там есть куча своих аспектов, например не у всех СМС хорошо доходят на все операторы и в разные страны, не все дают указать произвольный номер отправителя, итд. Все это платно разумеется, но не дорого.

Имей в виду что некоторые ориентированы на спам и с такими лучше не работать: можно попасть под фильтры операторов и сообщения будут теряться. Лучше брать тех что поизвестнее и покрупнее, давно на рынке и не ориентированы на спам рассылки (это часто по цене видно). Стоит также протестировать отправку самому.

По верстке:

- Стрелки на слайдере не по центру вертикально
- почта не кликабельна
- картинка с корзиной пикселизованная (дно тележки)
- в главном меню кликабельна только надпись, а черный косой блок на фоне - нет
- на втором слайдере зона для клика маленькая, да и по моему 2 слайдера перебор (по мне так и один это перебор, я их не люблю)
- в блоке «Голливудская улыбка» слева кликабельна только крошечная ссылка в которую еще попасть надо, а должен быть весь блок. Ты знаешь как неудобно в такие маленьие ссылки тыкать с планшета, на тачпаде, с заевшей мышкой? А ведь это все твои клиенты.
- блок «Голливудская улыбка» должен быть не только кликаьельным но и выделяться при наведении, давая обратную связь и намекая что можно на него нажать
- иконки соцсетей не становятся цветными при наведении
- некоторые тексты нереально мелкие (претензия к дизайнеру, вообще дизайн слабоват)
- сумма в корзине подчеркнута как будто это ссылка, но она не кликабельна (претензия к дизайну)
- на карточке товара некликабельна ни картинка, ни заголовок. Нет ссылки для перехода на страницу товара. Зато есть кнопка добавления, но ведь никто не добавит товар в корзину не почитав подробно о нем. Бред же. Открой например http://www.lamoda.ru/c/369/clothes-platiya/?genders=women и поищи здесь кнопку добавления в корзину. Так же обрати внимание на кликабельные зоны на карточке товара. Дизайнер и верстальщик оба не имеют понятия о поведении пользователя на сайте. Интерфейс я бы оценил на тройку с минусом, такие огрехи приведут к потере покупателей.
- сайт помечен как адаптивный в коде, но если посмотреть его в режиме эмуляции смартфона или планшета, никакой адаптивности нет, все разъезжается. Не копипасть тег meta viewport если ты не сделал адаптивную верстку.
- //maxcdn.bootstrapcdn.com/ - надежнее размещать библиотеки у себя, не надо подключать внещние скрипты, а то твой сайт ляжет вместе с CDN

> @font-face {


Сделано по моему неправильно, там нет разных форматов, только один формат.

HTML код это кошмар. Я ждал аккуратную лаконичную семантичную разметку. Но ощущение что откуда-то накопировали тегов и свалили в кучу.

> <img class="flag" src="bootstrap/images/flag.png" alt="flag">


Элементы оформления (в отличие от контента) надо делать через background-image.

> <p class="sliderTitle">


Надо hN использовать

> <h1><span class="sideYellow">/</span> Fitness одежда молодежной американской марки </h1>


Спан можно заменить на псевдоэлемент

> <div class="border"> </div>


Этого не должно быть в HTML коде, должно быть в CSS

Разметка карточки товара замусорена тегами, надо выкинуть оттуда все что относится к оформлению.

На странице может быть только один тег h1

> <div class="sticker small teeth">


> <div class="sticker small hair">


При натяжке на CMS будут проблемы если категории берутся из базы

> Голливудская <br>улыбка


br тут признак неквалифицированности верстальщика.

jQuery зачем-то подключен 2 раза.

Тег </html> потеряли.

CSS и JS я не смотрел, нет смысла тратить мое время на это. Это некачественная верстка на тройку с минусом, за которую тебе, как человеку который у нас учился (так ведь?) должно быть стыдно.
#557 #556192
>>556168

Кнопка «все спецпредложения» при первом наведении на нее мигает так как нужно время на загрузку второй картинки. такие вещи надо делать через CSS спрайты.
https://github.com/nsdvw/file-sharing #558 #556195
Ну что анон, дошла и до тебя очередь.

> https://github.com/nsdvw/file-sharing/blob/master/public_html/index.php#L11


> define('UPLOAD_DIR', 'upload');


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

> define('BASE_DIR', '..');


Лучше использовать абсолтный путь например с использованием dirname(_ _ DIR _ _)

> return new PDO(


Где строгий режим? Где ERRMODE_EXCEPTION? По умолчанию PDO по моему ничего не делает при ошибках от базы и ты о них не узнаешь.

> if (!Token::issetToken()) $token = Token::generateToken();


Не экономь строки и не пиши if в 1 строку

https://github.com/nsdvw/file-sharing/blob/master/public_html/index.php#L46
Этот код стоит куда-нибудь вынести, хотя бы в функцию в классе Token.

JSON надо отдавать с правильным типом и с помощью метода-хелпера как тут: http://stackoverflow.com/questions/6807404/slim-json-outputs/18070349#18070349

>https://github.com/nsdvw/file-sharing/blob/master/public_html/index.php#L72


Логично отдавать либо ошибку 404 либо JSON {"error": "File not found"}, а твой вариант ничего не говорит о причине проблемы.

> https://github.com/nsdvw/file-sharing/blob/master/public_html/index.php#L80


> if ($app->request->isGet()) {


> $app->render('upload_form.tpl');


Где тут логика? Почему в методе login мы выводим форму загрузки файла?

> https://github.com/nsdvw/file-sharing/blob/master/public_html/index.php#L85


> 'email'=>$_POST['login']['email'],


Надо использовать $app->request. Можно сразу в форме сделать метод принимающий Request.

> https://github.com/nsdvw/file-sharing/blob/master/public_html/index.php#L90


> if ($user = $app->userMapper->findByEmail($loginForm->email)) {


Проверку логина/пароля надо сделать либо частью валидации либо методом в loginManager.

Алсо не вижу где у тебя выводится сообщение о том что пароль введен неправильно.

> https://github.com/nsdvw/file-sharing/blob/master/public_html/index.php#L105


Эту простыню надо разбить на методы и вынести в какой-нибудь FileUploader. Метода должно быть минимум 2: валидация и загрузка. Ну как и в любой другой форме.

> https://github.com/nsdvw/file-sharing/blob/master/public_html/index.php#L165


> $app->get('/reg'


Надо сделать по стандартному алгоритму обработки форм.

Валидацию CSRF можно тоже поместить в формы.

> https://github.com/nsdvw/file-sharing/blob/master/public_html/index.php#L252


> foreach ($comments as $comment) {


> $comment->level = Comment::getLevel($comment->materialized_path);


Это должно быть в маппере.

> https://github.com/nsdvw/file-sharing/blob/master/public_html/index.php#L254


> $comment->author_id = $app->userMapper->findById($comment->author_id);


Вообще, если тебе нужны комменты + авторы, а доктрины у нас нет, можно попробовать вернуть массив пар вида

[
['comment' => ..., 'author' => ....],
....
]

> https://github.com/nsdvw/file-sharing/blob/master/public_html/index.php#L262


> $captcha = new Storage\Model\FormWithCaptcha(


Капча должна быть частью формы коммента. Надо просто у класса CommentForm сделать метод setCaptchaRequired(true|false) который отключает ее проверку и вывод.

Хуже, ты там зачем-то CommentForm аж 2 раза создаешь. такого быть не должно.

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

> https://github.com/nsdvw/file-sharing/blob/master/app/Auth/LoginManager.php#L11


> public $loggedUser = null;


Это лчше сделать методом

logout/login должны менять состояние loggedUser.

> https://github.com/nsdvw/file-sharing/blob/master/app/Auth/LoginManager.php#L38


> public function authorizeUser(User $user)


Где гарантия что нам передадут пользователя у которого непустой id и hash? Я бы поставил ассерты или if + throw:

assert(!!$user->id);
....

Модели форм логично бы вынести в неймспейс Form.

> https://github.com/nsdvw/file-sharing/blob/master/app/Model/Comment.php#L17


> protected $mapper;


В модели не должно быть ссылок на маппер.

> https://github.com/nsdvw/file-sharing/blob/master/app/Model/Comment.php#L19


> public function fromForm(CommentForm $form, CommentMapper $mapper)


Это в форме должен быть метод getModel(), причем логичнее всего чтобы форма содержала модель внутри себя.

> https://github.com/nsdvw/file-sharing/blob/master/app/Model/Comment.php#L44


> protected static function incrementPath


Это должно быть наверно в маппере.

> https://github.com/nsdvw/file-sharing/blob/master/app/Model/File.php#L103


> if ($propertyValue instanceof MediaInfo) {


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

> https://github.com/nsdvw/file-sharing/blob/master/app/Model/File.php#L16


> protected function getSafeFields()


название неудачное, надо называть getPublicFields()

> https://github.com/nsdvw/file-sharing/blob/master/app/Model/CommentForm.php


Логичнее внутри CommetnForm хранить сущность Comment и в нее и прописывать данные, чем заводить параллельный набор полей.

> https://github.com/nsdvw/file-sharing/blob/master/app/Model/FormWithCaptcha.php


капчу логичнее сделать элементом формы, а не типом формы

> https://github.com/nsdvw/file-sharing/blob/master/app/Model/FormWithCaptcha.php#L19


> session_start();


Лучше использовать сессии Слима

> https://github.com/nsdvw/file-sharing/blob/master/app/Model/Form.php#L8


> public function __construct(array $fields)


Не, это плохая идея передавать значения в конструктор. Лучше передавать их в метод handle(Request/array $request) который проставялет их и вызвыает validate().

> https://github.com/nsdvw/file-sharing/blob/master/app/Helper/HashGenerator.php


Для соли надо испльзовать еще и спецсимволы. Иначе она мало добавляет защиты от предвыисленных таблиц хешей.

> https://github.com/nsdvw/file-sharing/blob/master/app/Helper/Pager.php


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

> https://github.com/nsdvw/file-sharing/blob/master/app/Mapper/FileMapper.php#L84


> $sth->fetch(\PDO::FETCH_ASSOC);


есть fetchColumn() или как-то так
https://github.com/nsdvw/file-sharing #558 #556195
Ну что анон, дошла и до тебя очередь.

> https://github.com/nsdvw/file-sharing/blob/master/public_html/index.php#L11


> define('UPLOAD_DIR', 'upload');


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

> define('BASE_DIR', '..');


Лучше использовать абсолтный путь например с использованием dirname(_ _ DIR _ _)

> return new PDO(


Где строгий режим? Где ERRMODE_EXCEPTION? По умолчанию PDO по моему ничего не делает при ошибках от базы и ты о них не узнаешь.

> if (!Token::issetToken()) $token = Token::generateToken();


Не экономь строки и не пиши if в 1 строку

https://github.com/nsdvw/file-sharing/blob/master/public_html/index.php#L46
Этот код стоит куда-нибудь вынести, хотя бы в функцию в классе Token.

JSON надо отдавать с правильным типом и с помощью метода-хелпера как тут: http://stackoverflow.com/questions/6807404/slim-json-outputs/18070349#18070349

>https://github.com/nsdvw/file-sharing/blob/master/public_html/index.php#L72


Логично отдавать либо ошибку 404 либо JSON {"error": "File not found"}, а твой вариант ничего не говорит о причине проблемы.

> https://github.com/nsdvw/file-sharing/blob/master/public_html/index.php#L80


> if ($app->request->isGet()) {


> $app->render('upload_form.tpl');


Где тут логика? Почему в методе login мы выводим форму загрузки файла?

> https://github.com/nsdvw/file-sharing/blob/master/public_html/index.php#L85


> 'email'=>$_POST['login']['email'],


Надо использовать $app->request. Можно сразу в форме сделать метод принимающий Request.

> https://github.com/nsdvw/file-sharing/blob/master/public_html/index.php#L90


> if ($user = $app->userMapper->findByEmail($loginForm->email)) {


Проверку логина/пароля надо сделать либо частью валидации либо методом в loginManager.

Алсо не вижу где у тебя выводится сообщение о том что пароль введен неправильно.

> https://github.com/nsdvw/file-sharing/blob/master/public_html/index.php#L105


Эту простыню надо разбить на методы и вынести в какой-нибудь FileUploader. Метода должно быть минимум 2: валидация и загрузка. Ну как и в любой другой форме.

> https://github.com/nsdvw/file-sharing/blob/master/public_html/index.php#L165


> $app->get('/reg'


Надо сделать по стандартному алгоритму обработки форм.

Валидацию CSRF можно тоже поместить в формы.

> https://github.com/nsdvw/file-sharing/blob/master/public_html/index.php#L252


> foreach ($comments as $comment) {


> $comment->level = Comment::getLevel($comment->materialized_path);


Это должно быть в маппере.

> https://github.com/nsdvw/file-sharing/blob/master/public_html/index.php#L254


> $comment->author_id = $app->userMapper->findById($comment->author_id);


Вообще, если тебе нужны комменты + авторы, а доктрины у нас нет, можно попробовать вернуть массив пар вида

[
['comment' => ..., 'author' => ....],
....
]

> https://github.com/nsdvw/file-sharing/blob/master/public_html/index.php#L262


> $captcha = new Storage\Model\FormWithCaptcha(


Капча должна быть частью формы коммента. Надо просто у класса CommentForm сделать метод setCaptchaRequired(true|false) который отключает ее проверку и вывод.

Хуже, ты там зачем-то CommentForm аж 2 раза создаешь. такого быть не должно.

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

> https://github.com/nsdvw/file-sharing/blob/master/app/Auth/LoginManager.php#L11


> public $loggedUser = null;


Это лчше сделать методом

logout/login должны менять состояние loggedUser.

> https://github.com/nsdvw/file-sharing/blob/master/app/Auth/LoginManager.php#L38


> public function authorizeUser(User $user)


Где гарантия что нам передадут пользователя у которого непустой id и hash? Я бы поставил ассерты или if + throw:

assert(!!$user->id);
....

Модели форм логично бы вынести в неймспейс Form.

> https://github.com/nsdvw/file-sharing/blob/master/app/Model/Comment.php#L17


> protected $mapper;


В модели не должно быть ссылок на маппер.

> https://github.com/nsdvw/file-sharing/blob/master/app/Model/Comment.php#L19


> public function fromForm(CommentForm $form, CommentMapper $mapper)


Это в форме должен быть метод getModel(), причем логичнее всего чтобы форма содержала модель внутри себя.

> https://github.com/nsdvw/file-sharing/blob/master/app/Model/Comment.php#L44


> protected static function incrementPath


Это должно быть наверно в маппере.

> https://github.com/nsdvw/file-sharing/blob/master/app/Model/File.php#L103


> if ($propertyValue instanceof MediaInfo) {


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

> https://github.com/nsdvw/file-sharing/blob/master/app/Model/File.php#L16


> protected function getSafeFields()


название неудачное, надо называть getPublicFields()

> https://github.com/nsdvw/file-sharing/blob/master/app/Model/CommentForm.php


Логичнее внутри CommetnForm хранить сущность Comment и в нее и прописывать данные, чем заводить параллельный набор полей.

> https://github.com/nsdvw/file-sharing/blob/master/app/Model/FormWithCaptcha.php


капчу логичнее сделать элементом формы, а не типом формы

> https://github.com/nsdvw/file-sharing/blob/master/app/Model/FormWithCaptcha.php#L19


> session_start();


Лучше использовать сессии Слима

> https://github.com/nsdvw/file-sharing/blob/master/app/Model/Form.php#L8


> public function __construct(array $fields)


Не, это плохая идея передавать значения в конструктор. Лучше передавать их в метод handle(Request/array $request) который проставялет их и вызвыает validate().

> https://github.com/nsdvw/file-sharing/blob/master/app/Helper/HashGenerator.php


Для соли надо испльзовать еще и спецсимволы. Иначе она мало добавляет защиты от предвыисленных таблиц хешей.

> https://github.com/nsdvw/file-sharing/blob/master/app/Helper/Pager.php


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

> https://github.com/nsdvw/file-sharing/blob/master/app/Mapper/FileMapper.php#L84


> $sth->fetch(\PDO::FETCH_ASSOC);


есть fetchColumn() или как-то так
#559 #556196
По поводу тормозов: профайлер указывает на Faker, я бы померял время генерации простым тестом. Также проверил бы текст какой длины ты генерируешь.

Если проблема в Faker то можно сгенерировать пул случайных значений, а затем брать из оттуда, дописывая цифры.
#560 #556197
Анон, который пишет сайт объявлений, а ты видел такой интересный сайт? http://sfbay.craigslist.org/

Это довольно изветсная в США доска объявлений.

Ну а у нас крупнейший авито, это ты наверно и сам знаешь.
#561 #556198
Если кого-то пропустил, напомните о себе плиз
#562 #556201
>>554111

Немного поздно наверно, но все же.

> Если я правильно понял, то твиг проверяет if ($object instanceof ArrayAccess && isset($object[$arrayItem])). Но в случае если свойство равно null, и иссет пролетает мимо.



Баг https://github.com/twigphp/Twig/issues/1557 не имеет отношения к твоей проблеме. Он о баге в каком-то стороннем фреймворке.

http://ideone.com/g9CD7o

Для объектов ArrayAccess там используется isset, который вызвыает offsetExists. null на это не влияет. И строчка которую ты процитировал, она корректная.

Другой вопрос что в Юи offsetExists вызывает __isset и там возможно что-то криво реализовано. А возможно и нет.

Мораль в том что при реализации магических методов легко сделать ошибку. Также мораль в том что явное лучше неявного и стоит поменьше полагаться на магию по поиску полей в твиге.
#563 #556203
Более точный пример http://ideone.com/Ewyt27 показывает что offsetGet не вызывается при обращении isset($a[$b]) и значит наличие null никак не влияет на результат (в отличие от настоящего массива где null в элементе приводит к провалу теста isset).
75 Кб, 800x600
78 Кб, 800x600
#564 #556285
>>556079

>Ой, что-то я про тебя подзабыл, надеюсь ты не тратил зря время в ожидании.


Да, эта неделя была для меня кошмарной, но я знал что ты наверно очень устаешь помогая нам и то что чем меньше помогаешь мне тем больше отдыхаешь сам. Я понимаю какой титаническими вещами ты здесь занимаешься поэтому считаю что ты заслуживаешь как можно больше отдыха. Так что это даже к лучшему произошло, потому что за эту неделю я осознал как сильно я хочу писать код и как я люблю это дело. Может быть было бы лучше если бы ты мне подкидывал какой-нибудь информации, которая расширяла мой кругозор, на самостоятельное изучение, чтобы мне было чем заняться в свободное время? Что-нибудь по информационной безопасности или по администрированию систем (я с линуксом плохо знаком, стоит ли мне сначала начать с самостоятельного изучения каких-то азов?).

>Ну только добавь тут еще проверку живое ли животное (оно могло быть съедено кем-то на одном из предыдущих шагов). Если список животных это массив то foreach делает копию и итерирует по ней и удаление животных по ходу дела не повлияет на цикл. Если же спсиок животных это SplObjectStorage то копии не делается, и удаленные животные не попадают в цикл.


А где лучше делать эту проверку? В функции оценки ходов или в функции получение всех возможных ходов?
По моему если животное мертво, то его вообще не должно быть на карте (в смысле мире), и из этого бы вытекало все остальное.

>- получение списка ходов, оценочная функция, выполнение хода - в классах соответствующих животных.


Получение списка ходов можно тоже в Animal сделать. Просто взять все возможные ходы вокруг и потом работать с ними с помощью оценочной функции. Мне кажется так не придется в будущем не придется писать больше кода. Что скажешь?

>>556079

>Ты странно учитываешь сумму расстояний до кошек. В чем смысл именно суммирования?


Сложно объяснить, попробую показать наглядно. На первом пике мышка типо такая "ОМГ! Мне нужно сматываться как можно дальше" и выбирает самую дальнюю точку от всех кошек. На втором пике происходит тоже самое и самое главное по тому же самому алгоритму. Я писал программу которая могла бы доказать то что происходит на пиках, но идеоне не открыл страницу при субмите и код не сохранился. Однако, там было тоже самое что и в моем коде, и со временем, когда код будет работать исправно, ты сможешь убедиться в этом своими глазами. Если я прав насчет этой функции. Я просто не знаю как еще проще можно сделать в случае если кошек будет несколько.
75 Кб, 800x600
78 Кб, 800x600
#564 #556285
>>556079

>Ой, что-то я про тебя подзабыл, надеюсь ты не тратил зря время в ожидании.


Да, эта неделя была для меня кошмарной, но я знал что ты наверно очень устаешь помогая нам и то что чем меньше помогаешь мне тем больше отдыхаешь сам. Я понимаю какой титаническими вещами ты здесь занимаешься поэтому считаю что ты заслуживаешь как можно больше отдыха. Так что это даже к лучшему произошло, потому что за эту неделю я осознал как сильно я хочу писать код и как я люблю это дело. Может быть было бы лучше если бы ты мне подкидывал какой-нибудь информации, которая расширяла мой кругозор, на самостоятельное изучение, чтобы мне было чем заняться в свободное время? Что-нибудь по информационной безопасности или по администрированию систем (я с линуксом плохо знаком, стоит ли мне сначала начать с самостоятельного изучения каких-то азов?).

>Ну только добавь тут еще проверку живое ли животное (оно могло быть съедено кем-то на одном из предыдущих шагов). Если список животных это массив то foreach делает копию и итерирует по ней и удаление животных по ходу дела не повлияет на цикл. Если же спсиок животных это SplObjectStorage то копии не делается, и удаленные животные не попадают в цикл.


А где лучше делать эту проверку? В функции оценки ходов или в функции получение всех возможных ходов?
По моему если животное мертво, то его вообще не должно быть на карте (в смысле мире), и из этого бы вытекало все остальное.

>- получение списка ходов, оценочная функция, выполнение хода - в классах соответствующих животных.


Получение списка ходов можно тоже в Animal сделать. Просто взять все возможные ходы вокруг и потом работать с ними с помощью оценочной функции. Мне кажется так не придется в будущем не придется писать больше кода. Что скажешь?

>>556079

>Ты странно учитываешь сумму расстояний до кошек. В чем смысл именно суммирования?


Сложно объяснить, попробую показать наглядно. На первом пике мышка типо такая "ОМГ! Мне нужно сматываться как можно дальше" и выбирает самую дальнюю точку от всех кошек. На втором пике происходит тоже самое и самое главное по тому же самому алгоритму. Я писал программу которая могла бы доказать то что происходит на пиках, но идеоне не открыл страницу при субмите и код не сохранился. Однако, там было тоже самое что и в моем коде, и со временем, когда код будет работать исправно, ты сможешь убедиться в этом своими глазами. Если я прав насчет этой функции. Я просто не знаю как еще проще можно сделать в случае если кошек будет несколько.
1186 Кб, 2560x1600
#565 #556328
>>556183

>>Ох уж эти замыкания в JS. Голова трещит от них.


Надеюсь на практике они не так часто применяются?

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



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

>и реши наши задачки на JS


Знания первой части учебника достаточно для решения этих задач? Или стоит и вторую часть перед ними тоже пройти?
506 Кб, 672x1023
#566 #556329
>>556328

>и реши наши задачки на JS


>Знания первой части учебника достаточно для решения этих задач? Или стоит и вторую часть перед ними тоже пройти?



Хотя, глупый вопрос. Лучше не разрываться, а весь учебник закончить, тем более там и свои задачи имеются.
#567 #556331
>>556198
Файлообменник можешь посмотреть, я две недели назад сбрасывал.
>>551633

Там же сайт объявлений на yii, наверняка тоже много ошибок.
#568 #556339
Странно, но у меня постится без капчи.

>>556197
Выглядит как земля, зато работает быстро.

>>556195
>>556331
А, ты уже ответил выше. Теперь мне будет с чем возиться на неделю.
#569 #556349
>>556188

>Где плейсхолдеры?


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

>Подготовленные запросы кстати позволяют экономить время базы на парсинг SQL кода, так как он парсится только первый раз.


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

>запрос раскидан по всему методу кусками, так что его надо собирать в уме


Так я же добивался мультиинсерта, он вроде работает быстрее, чем если каждую запись вставлять по отдельности.
Или сделать одной транзакцией все 100 000 - 1 000 000 вставок? Это будет быстро?
Как вообще работает транзакция? Можно ли вставить миллион записей одной транзакцией, или оно пишется куда-то (в память, на диск, во временную таблицу), где есть лимит?

Черт, ничего не понимаю, за что хоть хвататься. Пойду поем.
#570 #556498
Не могу, бесит меня эта верстка и ЖАБАСКРИПТ, что без них совсем никак?
#571 #556568
А как делать адаптивным (он у меня резиновый, кстати)? Нужно просто высчитывать размеры окна в эмуляторе планшета и телефона и прописывать верстку в тегах amedia для таких размеров??
#572 #556578
ОП, а что у тебя есть по парсерам? Поясни хотя бы по логике, а лучше конечно подскажи библиотеку\фреймворк конкретно под эти цели. А цели в духе спарсить базу фрилансеров, порно комиксов, рецептов, да чего угодно и записать ее в свою. В пхп вообще есть функции в духе "кликнуть на кнопку", "заполнить форму", итд? С одной страничкой то еще понятно, тянем страничку и ебемся с регулярками, а если нужно пройти n страниц?
#573 #556583
>>556578

>В пхп вообще есть функции в духе "кликнуть на кнопку", "заполнить форму", итд?


Это есть в js.
#574 #556586
>>556583
Это я знаю. С нодой ковырялся, там такое и увидел. В пхп как подобное сделать?
Большая паста #575 #556597
>>556349

> Мне казалось, что подготовленные запросы нужно использовать только если есть опасность инъекции от пользователя. Зачем мне здесь плейсхолдеры, если нужно только заэкранировать?


во-первых если в тексте содержится одиначная кавычка то она закрывает строку и запрос становится невалидным:

$x = "test'test";
$sql = "SELECT '$x'"; // ошибка синтаксиса

Чтобы этого не было, ты например в случае с PDO должен вызывать функцию $pdo->quote

во-вторых, твой код без плейсхолдеров выглядит, как написали выше «как земля». Мне надо по функции глазами бегать и в голове собирать этот запрос по частям. Да и куча кавычек, скобочек лишних.

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

> Не понимаю, как это работает. Мне казалось наоборот, они должны замедлять выполнение,


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

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

> И как я буду биндить параметры, если у меня мультиинсерт на 10000 записей


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

> Или сделать одной транзакцией все 100 000 - 1 000 000 вставок? Это будет быстро?


Не факт

> Как вообще работает транзакция? Можно ли вставить миллион записей одной транзакцией, или оно пишется куда-то (в память, на диск, во временную таблицу), где есть лимит?


Транзакция это изолированный набор изменений, соответствующий принципам 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, которая (допустим) давно закоммичена.

(далее....)
Большая паста #575 #556597
>>556349

> Мне казалось, что подготовленные запросы нужно использовать только если есть опасность инъекции от пользователя. Зачем мне здесь плейсхолдеры, если нужно только заэкранировать?


во-первых если в тексте содержится одиначная кавычка то она закрывает строку и запрос становится невалидным:

$x = "test'test";
$sql = "SELECT '$x'"; // ошибка синтаксиса

Чтобы этого не было, ты например в случае с PDO должен вызывать функцию $pdo->quote

во-вторых, твой код без плейсхолдеров выглядит, как написали выше «как земля». Мне надо по функции глазами бегать и в голове собирать этот запрос по частям. Да и куча кавычек, скобочек лишних.

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

> Не понимаю, как это работает. Мне казалось наоборот, они должны замедлять выполнение,


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

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

> И как я буду биндить параметры, если у меня мультиинсерт на 10000 записей


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

> Или сделать одной транзакцией все 100 000 - 1 000 000 вставок? Это будет быстро?


Не факт

> Как вообще работает транзакция? Можно ли вставить миллион записей одной транзакцией, или оно пишется куда-то (в память, на диск, во временную таблицу), где есть лимит?


Транзакция это изолированный набор изменений, соответствующий принципам 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, которая (допустим) давно закоммичена.

(далее....)
Большая паста 2/2 #576 #556599
(продолжение)

Допустим 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 - блокировалась вообще вся база) на время записи, но там и транзакций нет.

Обрати внимание что речь тут шла о блокировках для модификации данных. 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), как запретить другим в это время их менять?
Большая паста 2/2 #576 #556599
(продолжение)

Допустим 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 - блокировалась вообще вся база) на время записи, но там и транзакций нет.

Обрати внимание что речь тут шла о блокировках для модификации данных. 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), как запретить другим в это время их менять?
#577 #556606
>>556328

> Знания первой части учебника достаточно для решения этих задач? Или стоит и вторую часть перед ними тоже пройти?



А ты посмотри сам. Первые задачи очень простые, и еще у нас
для первых 10 задач есть робот-проверяльщик!

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

Задачи в конце на DOM и jQuery требуют побольше знаний, но зато они уже ближе к жизни.

И еще большая задача на SPA которую я хочу написать уже 3 недели.
#578 #556614
>>556498

Надо в них разобраться и тогда бесить не будет. Теорию почитай, наши задачки на HTML/CSS порешай (там кстати и ссылочка хорошая есть).

>>556568

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

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

Обычно выбирается 1 или 2 порога ширины (например 480 и 900 пикс), при переходе через которые верстка меняется. Реализуется это правилом @media

Между порогами верстка должна быть резиновой.

Вот справочник который поможет тебе выбрать пороги:

http://mydevice.io/devices/

Если у тебя нет адаптивной версии ты должен убрать метатег (viewport) который заявляет о ее наличии. Либо сделать.

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

Примеры адаптивных сайтов: http://habrahabr.ru/post/141059/

Если у тебя есть уточняющие вопросы то задавай.

ТЕстировать адаптивность можно открыв инспектор Хрома (Ctrl + Shift + I ) и нажав иконку смартфона. Ну и если у тебя есть смартфон, проверь еще и на нем .

Также можно сделать скриншоты сайта на реальных устройствах тут:

https://www.browserstack.com/screenshots
https://www.browserstack.com/responsive

(это коммерческий сайт но там есть бесплатные возможности).
#578 #556614
>>556498

Надо в них разобраться и тогда бесить не будет. Теорию почитай, наши задачки на HTML/CSS порешай (там кстати и ссылочка хорошая есть).

>>556568

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

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

Обычно выбирается 1 или 2 порога ширины (например 480 и 900 пикс), при переходе через которые верстка меняется. Реализуется это правилом @media

Между порогами верстка должна быть резиновой.

Вот справочник который поможет тебе выбрать пороги:

http://mydevice.io/devices/

Если у тебя нет адаптивной версии ты должен убрать метатег (viewport) который заявляет о ее наличии. Либо сделать.

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

Примеры адаптивных сайтов: http://habrahabr.ru/post/141059/

Если у тебя есть уточняющие вопросы то задавай.

ТЕстировать адаптивность можно открыв инспектор Хрома (Ctrl + Shift + I ) и нажав иконку смартфона. Ну и если у тебя есть смартфон, проверь еще и на нем .

Также можно сделать скриншоты сайта на реальных устройствах тут:

https://www.browserstack.com/screenshots
https://www.browserstack.com/responsive

(это коммерческий сайт но там есть бесплатные возможности).
#579 #556616
>>556578

Есть библиотеки. Регулярки не нужны, надо использовать DOM + XPath или библиотеки вроде phpquery.

Ну и надо знать хотя бы основы протокола HTTP.

Мне не нравится твоя идея потому посоветую лучше выучиться и стать нормальным разработчиком, а парсеры оставить школьникам с фриланса.
#580 #556622
>>556616
Какая такая моя идея тебе не нравится? Я просто хочу сделать пару интересных сайтов для портфолио так сказать, не наполнять же их лоремиспумом. Ну да ладно, я уже догадался что нужно сначала взять все ссылки из меню допустим, потом собрать с каждой такой ссылки все ссылки на сами элементы, чем бы они ни были, а потом уже проходить сами элементы. Да и библиотеки уже нагуглил. Черт знает зачем спрашивал, нужно было просто подумать. Скучно поди.

А что если пагинация? Что если сайт с аяксом, и там просто кнопка "загрузить еще", или что еще хуже - элементы добавляются по мере скролла?

Кстати, оп, давно хочу спросить у тебя. А где ты сам-то работаешь? Сколько получаешь сейчас \ получал больше всего? Сколько лет разработкой занимаешься? Над чем сейчас работаешь?
#581 #556648
>>556622

Достаточно нагенерировать данных с помощью faker.
#582 #556778
>>556285

> Может быть было бы лучше если бы ты мне подкидывал какой-нибудь информации, которая расширяла мой кругозор, на самостоятельное изучение,



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

https://gist.github.com/codedokode/420c8c12a1edae25f0ec

После того как установишь, надо разобраться с bash и сопустствующими утилитами (cat, grep, find), чтобы научиться делать простые вещи вроде «взять лог веб-сервера и посчитать сколько процентов обращений в нем идет к картинкам» или «удалить все временные файлы старше недели» или «найти все измененные с момента последнего бекапа файлы, заархивировать, зашифровать (по желанию) и закачать на сервер».

Ну и освоить на примере дебиана:

- пакетный менеджер, установка программ (apt-get и apt-cache)
- общую структуру папок в линкусе, где например находятся логи и что такое /dev/sda1
- пользователи, группы и права на файлы. Создание и управление пользователями и правами
- процессы и сигналы, просмотр процессов (top, htop), корректное прибивание (kill, killall)
- управление сервисами: запуск, останов, включение запуска при загрузке. Раньше там были команды типа service start/stop, а сейчас
- блочные устройства, файловые системы и монтирование дисков: mount, /etc/fstab, fsck, mkfs
- мониторинг диска, сети, процессора: http://habrahabr.ru/post/114082/
- сеть, общие понятия и простая диагностика: netstat, ping, traceroute, dig, host , файл hosts

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

После этого ты будешь готов к тому чтобы учиться администрированию, это отдельная наука. Но даже то что написано выше тебе наверняка не раз пригодится, да и ты будешь увереннее себя чувствовать в командной строке.
#583 #556781
>>556285

>>Ну только добавь тут еще проверку живое ли животное


> А где лучше делать эту проверку?


Не там. В коде который берет всех животных на карте и вызывает у них move() надо добавить проверку, что животное еще живо.

> По моему если животное мертво, то его вообще не должно быть на карте (в смысле мире),


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

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

> Получение списка ходов можно тоже в Animal сделать.


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

>>Ты странно учитываешь сумму расстояний до кошек. В чем смысл именно суммирования?


> Сложно объяснить, попробую показать наглядно.


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

Так как для каждой клеточки мы суммируем расстояния до одних и тем же кошек то фактически мы сравниваем среднее расстояние от клеточки до кошек.

Но всегда ли такой подход будет работать правильно? Мне например кажется что надо брать расстояние до ближайшей кошки. Разве это не логичнее?

А затем уже, если есть несколько клеточек с равным расстояним, добавлять им очки с учетом других факторов, например числа выходов с клеточки или среднего расстояния до кошек.
#583 #556781
>>556285

>>Ну только добавь тут еще проверку живое ли животное


> А где лучше делать эту проверку?


Не там. В коде который берет всех животных на карте и вызывает у них move() надо добавить проверку, что животное еще живо.

> По моему если животное мертво, то его вообще не должно быть на карте (в смысле мире),


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

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

> Получение списка ходов можно тоже в Animal сделать.


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

>>Ты странно учитываешь сумму расстояний до кошек. В чем смысл именно суммирования?


> Сложно объяснить, попробую показать наглядно.


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

Так как для каждой клеточки мы суммируем расстояния до одних и тем же кошек то фактически мы сравниваем среднее расстояние от клеточки до кошек.

Но всегда ли такой подход будет работать правильно? Мне например кажется что надо брать расстояние до ближайшей кошки. Разве это не логичнее?

А затем уже, если есть несколько клеточек с равным расстояним, добавлять им очки с учетом других факторов, например числа выходов с клеточки или среднего расстояния до кошек.
#584 #556782
>>556778
разбираться в хтмл цсс
Не хояу я на это говно даже время свое тратить. вот есть фронтенд макаки - пусть и разгребают, я бэкендщик и хочу им быть.
#585 #556783
Блять, какой ты долбоеб тупой, у меня макет прекрасно адаптивный и резиновый, все скручивается в трубочку для определенной ширины, да через эмулятор прокрутить поленился, чтобы пиксель в пиксель прям подогнать. Поссал на тебя с твоей версткой, макака тупая.
#587 #556789
>>556782

Скажи проще ты хочешь быть быдлокодером и не хочшь изучать технологии которые используешь. Никому бенедщики в вакууме не нужны, ладно бы ты был экспертом по блокировкам в mysql или на Си писал демоны держащие миллион соединений, а если ты быдлокодишь на PHP, то это слишком просто, будь любезен и фронтенд освоить.

>>556786

Статью читать не пробовал?

>>556783

Шапку своего макета посмотри на маленькой ширине.
#588 #556802
ОП, ты ведь тут давно уже. Скажи были ли тут аноны, которые в конечном счете пилили истории о том как элитно они устроились на работу? Или только посты в стиле "ну это программирование, пойду в игоры играть" были?
#589 #556808
>>556079

>https://github.com/someApprentice/Cat-and-Mouse/blob/master/index.php#L21


>> <?php $cat->move(); ?>


>> <?php $mouse->move(); ?>


>Лучше вынести это в отдеьную функцию и сделать так:


>


>foreach ($world->getAllAnimals() as $animal) {


>$animal->move();


>}


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

https://github.com/someApprentice/Cat-and-Mouse/blob/master/index.php#L22
https://github.com/someApprentice/Cat-and-Mouse/blob/master/Classes/World.php#L96
#590 #556809
>>556802

Были. Например

>>544087
>>544103

Можешь сам поискать в предыдущих тредах.
#591 #556844
>>556802
Были, от меня пол года назад была стори. Да и раньше даже. Я на самом деле 2 места уже успел сменить, просто на первом продержался всего неделю, ибо ездить было адво далеко, полтора часа в 1 сторону уходило на дорогу в день.
>>552948
#592 #556856
>>556079

>У тебя как-то все не так. Например функция оценки одного хода, у тебя не вынесена отдельно, а намертво впаяна в цикл оценки ходов


Не могу понять почему плохо использовать цикл тут? Может быть ты имел ввиду что плохо объединять функцию получения всех ходов и функцию оценки этих ходов? Именно ходов. Мне сразу в голову пришло что в эту функцию нужно передавать массив со всеми возможными ходами и проверять каждый ход, а потом возвращать массив с балами.
#593 #556859
>>556079

>У тебя как-то все не так. Например функция оценки одного хода, у тебя не вынесена отдельно, а намертво впаяна в цикл оценки ходов, и она почему-то в базовом классе: https://github.com/someApprentice/Cat-and-Mouse/blob/master/Classes/Animal.php#L94


Не могу понять почему плохо использовать цикл здесь? Может быть ты имел ввиду что нельзя объединять функцию получения всех возможных ходов и оценку ходов?
Именно ходов. Мне сразу пришло в голову что нужно в эту функцию передавать массив со всеми возможными ходами и проверять каждый, а затем возвращать массив с балами.
#594 #556860
>>556859
Упс, макаба выдала ошибку при постинге и затем не обновила тред.
#595 #556885
>>556079

>Далее, само расстояние считается неверно: sqrt. Это декартово расстояние применимо в нашем мире где кошки ходят во все стороны с одинаковой скоростю. Но тут кошка по горизонтали ходит на расстояние 1, а по диагонали на sqrt(2) = 1.41, то есть игровой мир не изотропный. Тут надо считать не декартово расстояние а за сколько ходов до нас доберется кошка


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

>>556079

>Самый плохой ход тут второй — фактически в лапы кошек. Но по баллам это не очевидно. Если уж и складывать расстояния, то надо складывать обратные расстояния, 1/d, чтобы близкие кошки (как более опасные) давали большой вклад в сумму, а далекие — маленький.



>>556781

>Но всегда ли такой подход будет работать правильно? Мне например кажется что надо брать расстояние до ближайшей кошки. Разве это не логичнее?>>556079


>Наконец одного фактора маловато. Предлагаю взять три, с разными весами (то есть некоторые факторы вносят больший вклад в сумму):


>


>- расстояние до ближайшей кошки в ходах


>- число выходов с клетки (клетка в углу хуже клетки в центре)


>- сумма обратных расстояний (оценивает число и дальность до кошек)



>


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


Ну можно и это допилить. Только сначала исправлю ошибки чтобы кот работал >>556808

>Я же просил сделать чтобы было любое число животных, а не только два.


Dont worry я сделаю это когда код будет работать хотя бы с двумя. Чтобы несколько животных не создавали хаос, а то я глупенький не разберусь со всеми ошибками сразу.
#596 #556889
>>556079

> бы сделал абстрактный метод getSymbol. Это позволяет легко менять вид животного в зависимости от состояния, а также заставляет всех потомков класса реализовать этот метод.


>менять


А не setSymbol случайно?

И еще, могут ли быть абстрактными свойства? А то я что-то не вижу чтобы на php.net было написано об этом.
#597 #556925
Есть несколько таблиц в екселе. Как мне их импортировать в mysql?
#598 #556951
Вот смотрите какая история интересная: https://m.roem.ru/12-10-2015/209949/vsya-pravda-o-perezapuske-kinopoiska/

Хотели перейти с PHP на Яву и не смогли.

Я не думаю, что Ява такая плохая. Ява в общем-то быстрее PHP при правильном использовании, так что скорее всего они просто с архитектурой накосячили. Наделали модных микросервисов, как я понял из поста.
#599 #556973
>>556809
Ну устроиться за еду в мухосрани это одно. А хочется историй типа: вот учился тут год, а потом переехал в Питер/Москву и устроился сеньором за 10к долларов пассивного дохода.
#600 #557032
Есть сайт на вордпресс, который писал не я. Надо в добавить ещё одно поле в форму регистрации. Добавил. Надо сделать так что бы поле передавало данные в базу данных, где найти функцию которая занимается записью в базу данных значений из формы?
#601 #557057
>>556973

нельзя учиться год и устроиться сеньором по определению
#602 #557086
>>557057

А к 10к долларов пассивного дохода претензий нету? Я ведь просто преувеличил.
#603 #557092
>>557086
Что ты хочешь от нас? Тебе уже ответили что на работу после уроков ОПа устроиться реально, дальше дела опыта.
#604 #557093
>>557092

Так я больше и не спрашиваю.
#605 #557239
Ух, два дня не было интернета, быдло-соседи порвали провода, когда делали быдло-ремонт. Хорошо что насохранял книжек, иначе все обои порвал бы.

>>556597

> Подготовку запроса можно делать один раз, а выполнение с разными параметрами - много.


Не знал этого, сейчас погуглил, действительно можно сначала сделать prepare одного выражения, а потом в цикле bind и execute.
Но меня смущает количество инсертов.
Это ведь каждый раз новая команда для субд, даже при использовании транзакции?
Мне кажется, что мультиинсерт гораздо эффективнее, то есть собрать длинный запрос в цикле. Ну извините, что выглядит нечитабельно, но производительность ведь важнее?

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


Плевать на чистоту, меня интересует скорость, я не буду 36 часов ждать, пока база наполнится фейковыми данными.
Насчет плейсхолдеров принимаю твои замечания, но что насчет мультиинсерта? Я так и не понял, одобряешь или нет.
Короче, мне делать так:
$command->prepare($sql);
foreach(...) {$command->bindValue(); $command->execute();}
или так как я сделал раньше, то есть в цикле собрать длинный запрос на 10000 вставок (или сколько позволит max_allowed_packet), и один раз execute?

>ты должен сделать свою отдельную функцию мультиинсерта (или посмотреть может в DAO такая уже есть)


Вроде есть. Член знает, как учить фреймворк. То ли мне выучить наизусть десять тысяч свойств и методов, то ли каждый раз гуглить.
Нашел сначала issue по запросу в гугл "yii dao multiple insert"
https://github.com/yiisoft/yii/issues/1255
Затем сам метод
https://github.com/yiisoft/yii/blob/master/framework/db/schema/CDbCommandBuilder.php#L262

Ладно, я так понял, делаем мультиинсерт при помощи метода фреймворка и заключаем все это в транзакцию.

>Если используются настоящие плейсхолдеры...выигрыш там копеечный


>Если используется эмуляция плейсхолдеров...выигрыш конечно будет меньше


Так не понял, использовать эмуляцию или нет? Думаю, ты опечатался, хотел сказать, что с эмуляцией быстрее.

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


Какого счетчика? Разве не проще сделать select count(x) where category_id in ...
У меня счетчик только для просмотров конкретного объявления, вроде бы остановились на редисе для этих целей.
В одну транзакцию должны входить объявление и фото, которые юзер к нему прикрепляет, это да, сделал так с самого начала.

По статье в википедии:
чем отличается механизм теневых страниц от mvcc?
В википедии сказано:
1. "теневые страницы содержат копии тех страниц базы данных на начало транзакции, в которых происходят изменения"
2. "заключающийся в предоставлении каждому пользователю т. н. «снимка» БД, обладающего тем свойством, что вносимые пользователем изменения в БД невидимы другим пользователям до момента фиксации транзакции"
Чем "снимок" (mvcc) отличается от "копии" (теневые страницы)?
Или речь о том, что в механизме теневых страниц копируется только тот фрагмент данных, те строки (так я интерпретирую термин "страницы", который они не объясняют), над которыми производятся изменения? В случае с mvcc происходит копирование всей таблицы(?), благодаря чему можно избежать блокировки. Если я правильно понял.

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

По поводу реализации в innodb mysql мультиверсионности, то кажется они сохраняют данные по транзакции прямо в модифицируемой таблице в специальных столбиках. (rollback segment).

>Internally, InnoDB adds three fields to each row stored in the database


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

Или нет?

>Если делать все «по-простому» (то есть данные транзакции накапливаются в буфере, а при коммите вносятся в таблицу), то было бы много блокировок в момент коммита и при частой записи в базу все бы лежало


Значит я понял не совсем верно.

>При изменениях в таблице (update/delete/insert) исходные данные не удаляются, а просто добавляются новые строчки


Эвона как.

>Большая паста 2/2


Пример понятен. Но что будет, если например транзакция #1001 удаляет данные, а #1002 обновляет те же самые данные (с id=1 и text='hello')?
Причем коммитится сначала 1001, а потом попытается закоммититься 1002? Mysql достаточно умный, чтобы при таком казусе превратить апдейт в инсерт?

>Но MySQL все равно блокирует строки, которые изменяются или удаляются.


А, ну да, блокировка (на уровне строк в innodb). Блокировка означает, что конкурирующий запрос будет ждать, пока не выполнится (не закоммитится) текущая транзакция, я так понимаю.

> вопросы для проверки


Э, ты че, это ты должен отвечать, а я задавать тупые вопросы. Ну ладно.
1. Почему MyISAM блокирует таблицу на время апдейта одной строки?
Вероятно, это связано со способом хранения: если каждая таблица хранится в отдельном файле, то наверное есть ограничение от файловой системы на одновременный доступ/модификацию этого файла. А innodb тогда как хранится? Не знаю, короче.
2. Почему MVCC позволяет не блокировать таблицу?
Каждая транзакция работает с отдельным "снимком" базы. Вероятно, эти "снимки" хранятся отдельно от основной таблицы, поэтому с одной таблицей (и с одной строкой) могут работать разные транзакции.
3. почему InnoDB блокирует строки, хотя MVCC позволяет это не делать?
Чтобы избежать нарушения согласованности(?) данных.
Почему строки блокируются на все время транзакции (а не на время выполнения запроса)?
Не понимаю, о чем речь. Какого запроса? Имеешь ввиду, что если транзакция состоит из нескольких запросов, один из которых на модификацию данных, то блокировать модифицируемую строку только на время этого запроса, но не на всю транзакцию? Не знаю.
4. Не знаю.
#605 #557239
Ух, два дня не было интернета, быдло-соседи порвали провода, когда делали быдло-ремонт. Хорошо что насохранял книжек, иначе все обои порвал бы.

>>556597

> Подготовку запроса можно делать один раз, а выполнение с разными параметрами - много.


Не знал этого, сейчас погуглил, действительно можно сначала сделать prepare одного выражения, а потом в цикле bind и execute.
Но меня смущает количество инсертов.
Это ведь каждый раз новая команда для субд, даже при использовании транзакции?
Мне кажется, что мультиинсерт гораздо эффективнее, то есть собрать длинный запрос в цикле. Ну извините, что выглядит нечитабельно, но производительность ведь важнее?

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


Плевать на чистоту, меня интересует скорость, я не буду 36 часов ждать, пока база наполнится фейковыми данными.
Насчет плейсхолдеров принимаю твои замечания, но что насчет мультиинсерта? Я так и не понял, одобряешь или нет.
Короче, мне делать так:
$command->prepare($sql);
foreach(...) {$command->bindValue(); $command->execute();}
или так как я сделал раньше, то есть в цикле собрать длинный запрос на 10000 вставок (или сколько позволит max_allowed_packet), и один раз execute?

>ты должен сделать свою отдельную функцию мультиинсерта (или посмотреть может в DAO такая уже есть)


Вроде есть. Член знает, как учить фреймворк. То ли мне выучить наизусть десять тысяч свойств и методов, то ли каждый раз гуглить.
Нашел сначала issue по запросу в гугл "yii dao multiple insert"
https://github.com/yiisoft/yii/issues/1255
Затем сам метод
https://github.com/yiisoft/yii/blob/master/framework/db/schema/CDbCommandBuilder.php#L262

Ладно, я так понял, делаем мультиинсерт при помощи метода фреймворка и заключаем все это в транзакцию.

>Если используются настоящие плейсхолдеры...выигрыш там копеечный


>Если используется эмуляция плейсхолдеров...выигрыш конечно будет меньше


Так не понял, использовать эмуляцию или нет? Думаю, ты опечатался, хотел сказать, что с эмуляцией быстрее.

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


Какого счетчика? Разве не проще сделать select count(x) where category_id in ...
У меня счетчик только для просмотров конкретного объявления, вроде бы остановились на редисе для этих целей.
В одну транзакцию должны входить объявление и фото, которые юзер к нему прикрепляет, это да, сделал так с самого начала.

По статье в википедии:
чем отличается механизм теневых страниц от mvcc?
В википедии сказано:
1. "теневые страницы содержат копии тех страниц базы данных на начало транзакции, в которых происходят изменения"
2. "заключающийся в предоставлении каждому пользователю т. н. «снимка» БД, обладающего тем свойством, что вносимые пользователем изменения в БД невидимы другим пользователям до момента фиксации транзакции"
Чем "снимок" (mvcc) отличается от "копии" (теневые страницы)?
Или речь о том, что в механизме теневых страниц копируется только тот фрагмент данных, те строки (так я интерпретирую термин "страницы", который они не объясняют), над которыми производятся изменения? В случае с mvcc происходит копирование всей таблицы(?), благодаря чему можно избежать блокировки. Если я правильно понял.

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

По поводу реализации в innodb mysql мультиверсионности, то кажется они сохраняют данные по транзакции прямо в модифицируемой таблице в специальных столбиках. (rollback segment).

>Internally, InnoDB adds three fields to each row stored in the database


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

Или нет?

>Если делать все «по-простому» (то есть данные транзакции накапливаются в буфере, а при коммите вносятся в таблицу), то было бы много блокировок в момент коммита и при частой записи в базу все бы лежало


Значит я понял не совсем верно.

>При изменениях в таблице (update/delete/insert) исходные данные не удаляются, а просто добавляются новые строчки


Эвона как.

>Большая паста 2/2


Пример понятен. Но что будет, если например транзакция #1001 удаляет данные, а #1002 обновляет те же самые данные (с id=1 и text='hello')?
Причем коммитится сначала 1001, а потом попытается закоммититься 1002? Mysql достаточно умный, чтобы при таком казусе превратить апдейт в инсерт?

>Но MySQL все равно блокирует строки, которые изменяются или удаляются.


А, ну да, блокировка (на уровне строк в innodb). Блокировка означает, что конкурирующий запрос будет ждать, пока не выполнится (не закоммитится) текущая транзакция, я так понимаю.

> вопросы для проверки


Э, ты че, это ты должен отвечать, а я задавать тупые вопросы. Ну ладно.
1. Почему MyISAM блокирует таблицу на время апдейта одной строки?
Вероятно, это связано со способом хранения: если каждая таблица хранится в отдельном файле, то наверное есть ограничение от файловой системы на одновременный доступ/модификацию этого файла. А innodb тогда как хранится? Не знаю, короче.
2. Почему MVCC позволяет не блокировать таблицу?
Каждая транзакция работает с отдельным "снимком" базы. Вероятно, эти "снимки" хранятся отдельно от основной таблицы, поэтому с одной таблицей (и с одной строкой) могут работать разные транзакции.
3. почему InnoDB блокирует строки, хотя MVCC позволяет это не делать?
Чтобы избежать нарушения согласованности(?) данных.
Почему строки блокируются на все время транзакции (а не на время выполнения запроса)?
Не понимаю, о чем речь. Какого запроса? Имеешь ввиду, что если транзакция состоит из нескольких запросов, один из которых на модификацию данных, то блокировать модифицируемую строку только на время этого запроса, но не на всю транзакцию? Не знаю.
4. Не знаю.
#606 #557262
>>556808

> После этого перестает двигаться кошка. Странно, но если поменять местами добавление животных на карту, и добавлять кошку первой, то перестает двигаться мышка.


Разберись, натыкай echo и var_dump, посмотри какие условия выполняются какие нет.

>>556856

Потому что код будет чище если будет отдельно функция оценки варианта хода и отдельно функция оценки всех вариантов, а у тебя все смешано.

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

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


Ты смешиваешь в одной функции 2 действия.

>>556859

> почему плохо использовать цикл здесь?


Потому что функция оценки хода должна быть у каждого животного своя. А цикл для всех общий. Потому они должны быть отдельными функциями.
#607 #557273
>>556885

> А как посчитать это? Решиться ли это простым округлением?


Надо брать минимальное из расстояние по горизонтали и вертикали.

Но я не уверен что тогда сложение будет давать правильные цифры.

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


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

>>556889

> А не setSymbol случайно?


setSymbol это когда ты хочешь его поменять сам, а getSymbol — возвращает символ животного.

$animal->setSymbol('c');
$x = $animal->getSymbol();

> И еще, могут ли быть абстрактными свойства?


нет

>>556925

Через csv например

>>557032

Посмотри куда форма отправляет данные и посмотри что там.

>>557239

> Мне кажется, что мультиинсерт гораздо эффективнее,


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

У меня претензия что ты вместо того чтобы разбить код на несколько функций набыдлокодил все одной простыней. И что не экранируешь данные при вставке в запрос. И что не нашел готовую функцию мультиинсера в Юи.

Я не против мультиинсертов никоим образом. Но необходимость экранировать данные это не отменяет. и не обходимость сделать отдельную функцию для мультиинсерта тоже (или поискать вдруг она уже есть в Юи - я проверил, есть).

> Плевать на чистоту, меня интересует скорость,


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

> но что насчет мультиинсерта? Я так и не понял, одобряешь или нет.


Одобряю но код надо сделать нормально.

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


Использовать функцию мультиинсерта в Юи

> как учить фреймворк


Прежде чем писать свое, погуглить. Также, прочесть весь туториал на сайте:

http://www.yiiframework.com/doc/guide/1.1/ru
http://www.yiiframework.com/doc/guide/1.1/en/index

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

> Ладно, я так понял, делаем мультиинсерт при помощи метода фреймворка и заключаем все это в транзакцию.


Да. Помни что размер мультиинсерта ограничен размером пакета на сервере mysql и он то ли 1Мб то ли 16 Мб по умолчанию, тебе сообщат если ты его превысишь.

> Так не понял, использовать эмуляцию или нет? Думаю, ты опечатался, хотел сказать, что с эмуляцией быстрее.


С чего быстрее-то? Эмуляция это для тех баз которые не поддерживают плейсхолдеры и при ее использовании PDO сам подставляет данные и шлет каждый раз новый запрос. А без эмуляции он делает prepare/execute на стороне базы что и дает микроэкономию.

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


> Какого счетчика?


Это к примеру. Нет, SELECT COUNT не всегда проще хотя это правильее с точки зрения нормализации.
#607 #557273
>>556885

> А как посчитать это? Решиться ли это простым округлением?


Надо брать минимальное из расстояние по горизонтали и вертикали.

Но я не уверен что тогда сложение будет давать правильные цифры.

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


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

>>556889

> А не setSymbol случайно?


setSymbol это когда ты хочешь его поменять сам, а getSymbol — возвращает символ животного.

$animal->setSymbol('c');
$x = $animal->getSymbol();

> И еще, могут ли быть абстрактными свойства?


нет

>>556925

Через csv например

>>557032

Посмотри куда форма отправляет данные и посмотри что там.

>>557239

> Мне кажется, что мультиинсерт гораздо эффективнее,


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

У меня претензия что ты вместо того чтобы разбить код на несколько функций набыдлокодил все одной простыней. И что не экранируешь данные при вставке в запрос. И что не нашел готовую функцию мультиинсера в Юи.

Я не против мультиинсертов никоим образом. Но необходимость экранировать данные это не отменяет. и не обходимость сделать отдельную функцию для мультиинсерта тоже (или поискать вдруг она уже есть в Юи - я проверил, есть).

> Плевать на чистоту, меня интересует скорость,


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

> но что насчет мультиинсерта? Я так и не понял, одобряешь или нет.


Одобряю но код надо сделать нормально.

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


Использовать функцию мультиинсерта в Юи

> как учить фреймворк


Прежде чем писать свое, погуглить. Также, прочесть весь туториал на сайте:

http://www.yiiframework.com/doc/guide/1.1/ru
http://www.yiiframework.com/doc/guide/1.1/en/index

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

> Ладно, я так понял, делаем мультиинсерт при помощи метода фреймворка и заключаем все это в транзакцию.


Да. Помни что размер мультиинсерта ограничен размером пакета на сервере mysql и он то ли 1Мб то ли 16 Мб по умолчанию, тебе сообщат если ты его превысишь.

> Так не понял, использовать эмуляцию или нет? Думаю, ты опечатался, хотел сказать, что с эмуляцией быстрее.


С чего быстрее-то? Эмуляция это для тех баз которые не поддерживают плейсхолдеры и при ее использовании PDO сам подставляет данные и шлет каждый раз новый запрос. А без эмуляции он делает prepare/execute на стороне базы что и дает микроэкономию.

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


> Какого счетчика?


Это к примеру. Нет, SELECT COUNT не всегда проще хотя это правильее с точки зрения нормализации.
#608 #557287
>>557239

по теневым старницам:

https://en.wikipedia.org/wiki/Shadow_paging

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

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

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

> "заключающийся в предоставлении каждому пользователю т. н. «снимка» БД, обладающего тем свойством, что вносимые пользователем изменения в БД невидимы другим пользователям до момента фиксации транзакции"


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

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


Да

> В случае с mvcc происходит копирование всей таблицы(?), благодаря чему можно избежать блокировки. Если я правильно понял.


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

Блокировок и проблем нет так как в MVCC транзакции не меняют и не удаляют существующие строки (которые в данный момент может читать кто-то еще) а только дописывают новые.

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

MVCC не требует таких блокировок так как ничего не перезапиывает. а только дописывает новые строки в конец.
#608 #557287
>>557239

по теневым старницам:

https://en.wikipedia.org/wiki/Shadow_paging

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

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

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

> "заключающийся в предоставлении каждому пользователю т. н. «снимка» БД, обладающего тем свойством, что вносимые пользователем изменения в БД невидимы другим пользователям до момента фиксации транзакции"


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

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


Да

> В случае с mvcc происходит копирование всей таблицы(?), благодаря чему можно избежать блокировки. Если я правильно понял.


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

Блокировок и проблем нет так как в MVCC транзакции не меняют и не удаляют существующие строки (которые в данный момент может читать кто-то еще) а только дописывают новые.

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

MVCC не требует таких блокировок так как ничего не перезапиывает. а только дописывает новые строки в конец.
#609 #557308
>>557239

Дополню еще по теневым страницам: я немного не так описал процесс сброса данных при коммите:

> Shadow paging is a copy-on-write technique for avoiding in-place updates of pages. Instead, when a page is to be modified, a shadow page is allocated. Since the shadow page has no references (from other pages on disk), it can be modified liberally, without concern for consistency constraints, etc. When the page is ready to become durable, all pages that referred to the original are updated to refer to the new replacement page instead. Because the page is "activated" only when it is ready, it is atomic.



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

Ну и далее в вики описаны варианты оптимизаций этой техники.

> атомарность (должны быть выполнены все команды в транзакции, иначе откат)


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

Замечу что в mysql не все запросы подчинаются этому правилу, некоторые виды запросов вызывают неявный коммит (например запросы создания и модификации тадблиц ALTER TABLE, также по моему TRUNCATE).

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

> изолированность


Это то, что незакомиченные изменения видит только транзакция которая их сделала. А закомиченные — все.

> Не совсем понятна идея "согласованности"


Пример с банком относится к базам которые позволяют указывать условия которые должны всегда выполняться (вроде сумма всех денег на счетах равна X или число строк в таблице равно Y, в mysql такого нет).

В Mysql таким условием является например то что внешний ключ должен указывать на существующую запись. Или что в колонке с уникальным индексом нет повторяющихся значений. Согласованность значит что до и после транзакции эти условия должны соблюдаться (все внешние ключи должны быть верные). А вот должна ли соблюдаться внутри транзакции — этого ACID не требует.

В mysql впрочем внешние и уникальные ключи проверяются не на границах транзакций а на границе запроса. То есть временно их нарушить не получится (недостаток это или преимущество?). И соответственно для mysql согласованность следует из атомарности.

Впрочем, пожалуюсь еще, в mysql можно временно отключить проверку внешних ключей, и после включения никто их не перепроверяет, то есть при желании нарушить целостность можно. Это плохо.

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


нет. соблюдение наложенных на базу ограничений как раз забота БД.

К примеру в некоторых базах ты можешь указать для колонки выражение с помощью слова CHECK и база будет проверять что оно выполняется для всех вставляемых значений:

CREATE TABLE ...
level INT NOT NULL CHECK (level BETWEEN 1 AND 5),
...

В mysql слово CHECK игнорируется и условие не проверяется.

Оно работает в postgres например: http://www.postgresql.org/docs/8.1/static/ddl-constraints.html
#609 #557308
>>557239

Дополню еще по теневым страницам: я немного не так описал процесс сброса данных при коммите:

> Shadow paging is a copy-on-write technique for avoiding in-place updates of pages. Instead, when a page is to be modified, a shadow page is allocated. Since the shadow page has no references (from other pages on disk), it can be modified liberally, without concern for consistency constraints, etc. When the page is ready to become durable, all pages that referred to the original are updated to refer to the new replacement page instead. Because the page is "activated" only when it is ready, it is atomic.



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

Ну и далее в вики описаны варианты оптимизаций этой техники.

> атомарность (должны быть выполнены все команды в транзакции, иначе откат)


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

Замечу что в mysql не все запросы подчинаются этому правилу, некоторые виды запросов вызывают неявный коммит (например запросы создания и модификации тадблиц ALTER TABLE, также по моему TRUNCATE).

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

> изолированность


Это то, что незакомиченные изменения видит только транзакция которая их сделала. А закомиченные — все.

> Не совсем понятна идея "согласованности"


Пример с банком относится к базам которые позволяют указывать условия которые должны всегда выполняться (вроде сумма всех денег на счетах равна X или число строк в таблице равно Y, в mysql такого нет).

В Mysql таким условием является например то что внешний ключ должен указывать на существующую запись. Или что в колонке с уникальным индексом нет повторяющихся значений. Согласованность значит что до и после транзакции эти условия должны соблюдаться (все внешние ключи должны быть верные). А вот должна ли соблюдаться внутри транзакции — этого ACID не требует.

В mysql впрочем внешние и уникальные ключи проверяются не на границах транзакций а на границе запроса. То есть временно их нарушить не получится (недостаток это или преимущество?). И соответственно для mysql согласованность следует из атомарности.

Впрочем, пожалуюсь еще, в mysql можно временно отключить проверку внешних ключей, и после включения никто их не перепроверяет, то есть при желании нарушить целостность можно. Это плохо.

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


нет. соблюдение наложенных на базу ограничений как раз забота БД.

К примеру в некоторых базах ты можешь указать для колонки выражение с помощью слова CHECK и база будет проверять что оно выполняется для всех вставляемых значений:

CREATE TABLE ...
level INT NOT NULL CHECK (level BETWEEN 1 AND 5),
...

В mysql слово CHECK игнорируется и условие не проверяется.

Оно работает в postgres например: http://www.postgresql.org/docs/8.1/static/ddl-constraints.html
#610 #557327
>>557239

>>Internally, InnoDB adds three fields to each row stored in the database


> Непонятно, прямо в таблице создаются эти поля?


Да. Посмотри на мой пример с 2 дописанными полями (я не стал дописвыать третье так как у меня есть первичный ключ по которому можно найти одинаковые записи).

> в innodb mysql мультиверсионности, то кажется они сохраняют данные по транзакции прямо в модифицируемой таблице в специальных столбиках. (rollback segment).


Нет, это другое.

> ? Нет, думаю скорее всего создаются временные(?) таблицы, куда складываются данные каждой транзакции, мы же выше читали о том, что mvcc реализуется в виде неких "снимков".


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

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



Нет, MVCC подразумевает что таблица одна, все с ней работают, и не мешают друг другу благодаря этим скрытым полям (транзакция не читает строки которые принадлежат незакомиченным транзакциям и как бы «не замечает» их). Благодаря тому что никто не правит закоммиченные данные, а только дописывает новые.

> Пример понятен. Но что будет, если например транзакция #1001 удаляет данные, а #1002 обновляет те же самые данные (с id=1 и text='hello')?


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

Потому та транзакция которая будет первой, возьмет эксклюзивную блокировку, а вторая при попытке ее взять заблокируется до момента коммита первой. Но эти блокировки не из-за MVCC а ради предотвращения конфликта.

> Mysql достаточно умный, чтобы при таком казусе превратить апдейт в инсерт?


Нет, и я не уверен что это равнозначная замена.

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


Нет, ограничений нет. Блокировка нужна так как изменения вносятся не атомарно. Представь что у нас есть строчка с текстом hello и мы меняем его на world. Ты не можешь поменять ее атомарно, ты идешь и меняешь по одной букве.

Если в это время второй поток попробует прочитать строку, он может получить полуперезаписанную строку:

wo|llo

А если в это время третий поток пытается заменить hello на goodbuy, мы вообще можем сохранить в итоге смесь goodbuy и world:

wor|dbuy

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

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

Если есть время, ты можешь сделать самодельную «базу» на основе текстового файла и допустим менять в ней строки (с помощью fseek и fwrite). Если запустить 2-3 скрипта параллельно, со временем файл превратится в мусор.

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

В MVCC обходятся без блокировок за счет того что никто не перезаписывает строки. В MyISAM блокировки обязательны, на всю таблицу (причем блокируется таблица + ее индексы чтобы никто не увидел несогласованные данные между ними).

> 2. Почему MVCC позволяет не блокировать таблицу?


> Каждая транзакция работает с отдельным "снимком" базы. Вероятно, эти "снимки" хранятся отдельно от основной таблицы, поэтому с одной таблицей (и с одной строкой) могут работать разные транзакции.


Неверно, попробуй еще.

> Почему строки блокируются на все время транзакции (а не на время выполнения запроса)?


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


расмотри пример в википедии: 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#.D0.9F.D0.BE.D1.82.D0.B5.D1.80.D1.8F.D0.BD.D0.BD.D0.BE.D0.B5_.D0.BE.D0.B1.D0.BD.D0.BE.D0.B2.D0.BB.D0.B5.D0.BD.D0.B8.D0.B5

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

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

> 4. Не знаю.


Погугли SELECT FOR UPDATE и SELECT .. SHARED LOCK
#610 #557327
>>557239

>>Internally, InnoDB adds three fields to each row stored in the database


> Непонятно, прямо в таблице создаются эти поля?


Да. Посмотри на мой пример с 2 дописанными полями (я не стал дописвыать третье так как у меня есть первичный ключ по которому можно найти одинаковые записи).

> в innodb mysql мультиверсионности, то кажется они сохраняют данные по транзакции прямо в модифицируемой таблице в специальных столбиках. (rollback segment).


Нет, это другое.

> ? Нет, думаю скорее всего создаются временные(?) таблицы, куда складываются данные каждой транзакции, мы же выше читали о том, что mvcc реализуется в виде неких "снимков".


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

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



Нет, MVCC подразумевает что таблица одна, все с ней работают, и не мешают друг другу благодаря этим скрытым полям (транзакция не читает строки которые принадлежат незакомиченным транзакциям и как бы «не замечает» их). Благодаря тому что никто не правит закоммиченные данные, а только дописывает новые.

> Пример понятен. Но что будет, если например транзакция #1001 удаляет данные, а #1002 обновляет те же самые данные (с id=1 и text='hello')?


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

Потому та транзакция которая будет первой, возьмет эксклюзивную блокировку, а вторая при попытке ее взять заблокируется до момента коммита первой. Но эти блокировки не из-за MVCC а ради предотвращения конфликта.

> Mysql достаточно умный, чтобы при таком казусе превратить апдейт в инсерт?


Нет, и я не уверен что это равнозначная замена.

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


Нет, ограничений нет. Блокировка нужна так как изменения вносятся не атомарно. Представь что у нас есть строчка с текстом hello и мы меняем его на world. Ты не можешь поменять ее атомарно, ты идешь и меняешь по одной букве.

Если в это время второй поток попробует прочитать строку, он может получить полуперезаписанную строку:

wo|llo

А если в это время третий поток пытается заменить hello на goodbuy, мы вообще можем сохранить в итоге смесь goodbuy и world:

wor|dbuy

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

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

Если есть время, ты можешь сделать самодельную «базу» на основе текстового файла и допустим менять в ней строки (с помощью fseek и fwrite). Если запустить 2-3 скрипта параллельно, со временем файл превратится в мусор.

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

В MVCC обходятся без блокировок за счет того что никто не перезаписывает строки. В MyISAM блокировки обязательны, на всю таблицу (причем блокируется таблица + ее индексы чтобы никто не увидел несогласованные данные между ними).

> 2. Почему MVCC позволяет не блокировать таблицу?


> Каждая транзакция работает с отдельным "снимком" базы. Вероятно, эти "снимки" хранятся отдельно от основной таблицы, поэтому с одной таблицей (и с одной строкой) могут работать разные транзакции.


Неверно, попробуй еще.

> Почему строки блокируются на все время транзакции (а не на время выполнения запроса)?


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


расмотри пример в википедии: 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#.D0.9F.D0.BE.D1.82.D0.B5.D1.80.D1.8F.D0.BD.D0.BD.D0.BE.D0.B5_.D0.BE.D0.B1.D0.BD.D0.BE.D0.B2.D0.BB.D0.B5.D0.BD.D0.B8.D0.B5

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

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

> 4. Не знаю.


Погугли SELECT FOR UPDATE и SELECT .. SHARED LOCK
#611 #557393
>>557273

>Через csv например


Пробовал через csv импортировать в pma, но он ругается на пустые значения в столбцах.
#612 #557403
>>557393
кто ругается? mysql? Значит сделай что бы значения в столбцах могли быть null
Ну ты понял. У тебя логически все должно совпадать. Если ты импортируешь лист с пустыми значениями в базу, в которой везде стоит not null, то ты его либо заполняешь сначала какими-нибудь нулями, ну либо меняешь устройство базы.
#613 #557449
ОП, помоги!
Как правильно разворачивать проекты на yii2, если у тебя они в репозитории на гите?
Допустим работал я на одном пк, потом перекатился на другой, естественно гит не подхватывает все файлы, да и не нужно. Папка vendor заполняется с помощью композера, но как быть с другими файлами, которые попадают в gitignore? Просто убрать их оттуда, или же ебаться в ручную? Может еще есть какие варианты?
#614 #557450
Ебался два часа с линуксом и приплыл к тому, что апач не хочет мои .htaccess обрабатывать. Чому?
#615 #557506
>>557450
Потому что ты пидор.
#616 #557529
ОП, я тут столкнулся с одной проблемой. Последовал твоему совету:

>Также, мне не нравится идея генерировать имя функции так:



> $imgCreateFunc = "imagecreatefrom".$this->extension;



>Как-то это не очень надежно, ведь определение расширения у тебя в обном месте, а эта строчка в другом. Вдруг какой-нибудь программист добавит новое расширение, а на то как оно используется, не обратит внимание? Я думаю, тогда в классе можно сделать поле imgCreateFunc и присваиваеть ему значение в том же switch где и определяется расширение. Аналогично сделать поле для функции сохранения файла.



Сделал $imgCreateFunc полем класса, но проблема в том, что когда я обращаюсь к этому полю как к функции $this->imgCreateFunc(аргумент), то скрипт ищет метод с таким именем,а не поле, в связи с чем возникает ошибка Call to undefined method Thumbnail::imgCreateFunc()
#617 #557539
>>557506
это потому что я гетар.
#618 #557561
>>557529
Сделал через call_user_func($this->imgCreateFunc, $image), так пойдет?
#619 #557574
>>557273
С третьего раза вроде дошло по поводу подготовленных выражений и эмуляции pdo.

При использовании подготовленного выражения (при отключенной эмуляции) php отправляет на сервер шаблон запроса, например
$sql = "INSERT INTO user (name, password, email) VALUES (:name, :password, :email)";
$sth = $dbh->prepare($sql);
На сервере строится план выполнения запроса, и прочие внутренние дела, в которые я не вникаю. Но суть в том, что пока открыто соединение, от pdo требуется только присылать данные для подстановки плейсхолдеров.
foreach ($users as $user) {
$sth->bindValue(':name', $user->name);
$sth->bindValue(':password', $user->password);
$sth->bindValue(':email', $user->email);
$sth->execute();
}
Execute здесь только отсылает данные для привязки, а операции подстановки выполняются на сервере.

Если включить эмуляцию, то pdo при execute каждый раз шлет новый запрос. При этом сначала экранируются и подставляются плейсхолдеры на стороне php.
Значит, эмуляцию вообще не нужно использовать, только в случае, когда база не поддерживает плейсхолдеры.
А как ее отключить? Вроде бы через setAttribute, но что-то я не уверен, что это корректно работает.
Пробовал наоборот включить ради теста
$pdo->setAttribute( PDO::ATTR_EMULATE_PREPARES, true );
$res = $pdo->getAttribute( PDO::ATTR_EMULATE_PREPARES );
var_dump($res);
Выдает false.

По умолчанию эмуляция включена или нет? В мануале php не сказано.
http://php.net/manual/ru/pdo.setattribute.php

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


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

В yii кстати по умолчанию эта настройка в конфиге выставлена в true (emulatePrepare=>on)
Вероятно это сделано для старых версий mysql (или других баз, не поддерживающих подтготовленные выражения).
Пост на stackoverflow http://stackoverflow.com/questions/10113562/pdo-mysql-use-pdoattr-emulate-prepares-or-not/10455228#10455228

>прочесть весь туториал на сайте


А теперь покажи мне то место в туториале, где говорится о методе для мультиинсерта или например про эмуляцию подготовленных выражений.
Туториал отстой, читал я его несколько раз, там только беглый обзор возможностей фреймворка и особенности реализации тех или иных фич.
С другой стороны, для большого фреймворка действительно непонятно как организовать мануал: если перечислить в нем вообще все методы, то он разрастется до бесконечности, и все равно ничего нельзя будет найти.
#619 #557574
>>557273
С третьего раза вроде дошло по поводу подготовленных выражений и эмуляции pdo.

При использовании подготовленного выражения (при отключенной эмуляции) php отправляет на сервер шаблон запроса, например
$sql = "INSERT INTO user (name, password, email) VALUES (:name, :password, :email)";
$sth = $dbh->prepare($sql);
На сервере строится план выполнения запроса, и прочие внутренние дела, в которые я не вникаю. Но суть в том, что пока открыто соединение, от pdo требуется только присылать данные для подстановки плейсхолдеров.
foreach ($users as $user) {
$sth->bindValue(':name', $user->name);
$sth->bindValue(':password', $user->password);
$sth->bindValue(':email', $user->email);
$sth->execute();
}
Execute здесь только отсылает данные для привязки, а операции подстановки выполняются на сервере.

Если включить эмуляцию, то pdo при execute каждый раз шлет новый запрос. При этом сначала экранируются и подставляются плейсхолдеры на стороне php.
Значит, эмуляцию вообще не нужно использовать, только в случае, когда база не поддерживает плейсхолдеры.
А как ее отключить? Вроде бы через setAttribute, но что-то я не уверен, что это корректно работает.
Пробовал наоборот включить ради теста
$pdo->setAttribute( PDO::ATTR_EMULATE_PREPARES, true );
$res = $pdo->getAttribute( PDO::ATTR_EMULATE_PREPARES );
var_dump($res);
Выдает false.

По умолчанию эмуляция включена или нет? В мануале php не сказано.
http://php.net/manual/ru/pdo.setattribute.php

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


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

В yii кстати по умолчанию эта настройка в конфиге выставлена в true (emulatePrepare=>on)
Вероятно это сделано для старых версий mysql (или других баз, не поддерживающих подтготовленные выражения).
Пост на stackoverflow http://stackoverflow.com/questions/10113562/pdo-mysql-use-pdoattr-emulate-prepares-or-not/10455228#10455228

>прочесть весь туториал на сайте


А теперь покажи мне то место в туториале, где говорится о методе для мультиинсерта или например про эмуляцию подготовленных выражений.
Туториал отстой, читал я его несколько раз, там только беглый обзор возможностей фреймворка и особенности реализации тех или иных фич.
С другой стороны, для большого фреймворка действительно непонятно как организовать мануал: если перечислить в нем вообще все методы, то он разрастется до бесконечности, и все равно ничего нельзя будет найти.
#620 #557600
Сосаны, поясните за long polling и подобные методики, второй день сука не могу найти ни нормальных примеров, ни объяснений. Какие нужны экстеншены, демоны, какой-нибудь бы пиздецки простой пример.
#621 #557627
>>557600
по вебсокетам на хабре годно и просто читал, погугли
#622 #557713
>>557327

>Блокировка нужна так как изменения вносятся не атомарно. Представь что у нас есть строчка с текстом hello и мы меняем его на world. Ты не можешь поменять ее атомарно, ты идешь и меняешь по одной букве.


Я не в курсе нюансов работы файловой системы, поэтому кажется странным, что замена производится побуквенно. Почему так?
Но теперь понятно, зачем нужна блокировка на уровне таблицы в myisam.

> 2. Почему MVCC позволяет не блокировать таблицу?


>Неверно, попробуй еще.


Ну ты уже объяснил, поэтому я только перефразирую своими словами, чтобы показать, насколько понял.
В myisam изменения вносятся прямо в запись, поэтому два процесса могут внести противоречивые модификации.
В innodb, где используется mvcc, строки не перезаписываются, а добавляются новые, поэтому такого конфликта не возникает. Поэтому в блокировке на уровне таблицы нет необходимости. На уровне строки блокировки нужны во избежание нарушения согласованности.

> 3. Почему строки блокируются на все время транзакции (а не на время выполнения запроса)?


Я не понимаю вопроса. Суть транзакций в том, чтобы внести атомарное изменение. Естественно блокировать нужно на все время транзакции, иначе возникнет несогласованность, когда выполнена только часть запросов от первой транзакции, и после этого будут внесены модификации от другой транзакции.
Какой смысл в транзакции, если строки будут блокироваться только на время выполнения запроса?

> 4. Чтение с блокировкой.


Погуглил, ок. Когда возникает нужда в выборке с последующей модификацией (например выбрать всех пользователей с таким-то статусом и дать им другой статус), имеет смысл поставить блокировку LOCK IN SHARE MODE, чтобы пока работает наш скрипт, над выбранными пользователями не была произведена какая-то посторонняя модификация.
Эта конструкция блокирует данные только на запись, не на чтение.
SELECT FOR ... UPDATE выставляет также блокировку на чтение.
#623 #557715
>>557449
Покажи файл гитигнор.
Там должны быть только временные файлы типа ассетов, кеши и тому подобный мусор, но никак не модели и контроллеры.
#624 #557735
>>557713

> Я не в курсе нюансов работы файловой системы, поэтому кажется странным, что замена производится побуквенно. Почему так?


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

Конечно они могли бы грузить кусок файла для редактирования в свою приватную область, но тогда потребление памяти возрастет и каждому потоку придется грузить повторно те же данные. И даже в этом случае ты не можешь атомарно поменять данные в файле так как на уровне ОС чтение/запись идет блоками по 4Кб. Если тебе надо записать более одного блока, запись будет не атомарная.

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

А в случае с MyISAM мы должны менять не один файл, а несколько (таблица + индексы), причем заранее неизвестно какой именно объем данных надо поменять.

То есть ты не можешь атомарно вносить изменения в файловую систему, запись идет блоками по 4Кб, и тебе надо либо применять трюки с переименованием либо делать блокировки.

Пример с буквами это лишь пример. Если тебе надо поменять не буквы, а нескоько 4 Кб блоков в файле, ты получаешь ту же проблему не атомарной записи.

> В innodb, где используется mvcc, строки не перезаписываются, а добавляются новые, поэтому такого конфликта не возникает.


Верно

> Естественно блокировать нужно на все время транзакции, иначе возникнет несогласованность, когда выполнена только часть запросов от первой транзакции, и после этого будут внесены модификации от другой транзакции.


Ну да, иначе может быть ситуация что 2 транзакции внесут противоречивые изменения в одну и ту же строку.

> LOCK IN SHARE MODE


Да, все верно.

Ну, надеюсь ты теперь хорошо понимаешь что такое транзакции.
#624 #557735
>>557713

> Я не в курсе нюансов работы файловой системы, поэтому кажется странным, что замена производится побуквенно. Почему так?


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

Конечно они могли бы грузить кусок файла для редактирования в свою приватную область, но тогда потребление памяти возрастет и каждому потоку придется грузить повторно те же данные. И даже в этом случае ты не можешь атомарно поменять данные в файле так как на уровне ОС чтение/запись идет блоками по 4Кб. Если тебе надо записать более одного блока, запись будет не атомарная.

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

А в случае с MyISAM мы должны менять не один файл, а несколько (таблица + индексы), причем заранее неизвестно какой именно объем данных надо поменять.

То есть ты не можешь атомарно вносить изменения в файловую систему, запись идет блоками по 4Кб, и тебе надо либо применять трюки с переименованием либо делать блокировки.

Пример с буквами это лишь пример. Если тебе надо поменять не буквы, а нескоько 4 Кб блоков в файле, ты получаешь ту же проблему не атомарной записи.

> В innodb, где используется mvcc, строки не перезаписываются, а добавляются новые, поэтому такого конфликта не возникает.


Верно

> Естественно блокировать нужно на все время транзакции, иначе возникнет несогласованность, когда выполнена только часть запросов от первой транзакции, и после этого будут внесены модификации от другой транзакции.


Ну да, иначе может быть ситуация что 2 транзакции внесут противоречивые изменения в одну и ту же строку.

> LOCK IN SHARE MODE


Да, все верно.

Ну, надеюсь ты теперь хорошо понимаешь что такое транзакции.
#625 #557737
>>557713

Кстати Sublime Text применяет именно трюк с переименованием чтобы атомарно сохранить редактируемый файл.
#626 #557773
>>557262

>Потому что код будет чище если будет отдельно функция оценки варианта хода и отдельно функция оценки всех вариантов, а у тебя все смешано.


>


>Функция оценки хода у каждого животного своя. Функция которая перебирает варианты ходов и вызывает функцию оценки, общая для всех. Соответственно раз она общая ее можно поместить в Animal, а вот функцию оценки нет.


А как я буду оценивать вариант хода не имея возможности сравнивать его с другими ходами? Я вижу тут только такой вариант и тут без цикла, который будет проходиться по каждому ходу и сравнивать его с другими, не обойтись. Как понять вообще функция оценки хода? Что-то ты меня совсем запутал.

>>557262

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


>Ты смешиваешь в одной функции 2 действия.


Нет же, будет отдельно функция получения списка всех ходов, и функция сравнивания их с друг с другом.

>>557273

>> А как посчитать это? Решиться ли это простым округлением?


>Надо брать минимальное из расстояние по горизонтали и вертикали.


А можно подсказку как это сделать?

>>557273

>> А не setSymbol случайно?


>setSymbol это когда ты хочешь его поменять сам, а getSymbol — возвращает символ животного.


>


>$animal->setSymbol('c');


>$x = $animal->getSymbol();


>


Но ты же сказал чтобы он >менял вид животного в зависимости от состояния.
#627 #557811
https://github.com/MindiMakridi/RESTFUL Вроде всё исправил.
#628 #557829
>>557773

> Как понять вообще функция оценки хода?


Функция оценки хода это функция получающая на вход координаты клеточки и выдающая оценку хода на эту клеточку.

> Но ты же сказал чтобы он >менял вид животного в зависимости от состояния.


set это когда знаечние меняют извне. get возвращает значение. У нас никто символ для кошки менять не будет извне, мы прсто вызваем getSymbol а она вернет текущую иконку.
#629 #558019

>сомнительной соцсети в которую приличный человек и носа не сунет


Прямо заинтриговал.

>>556188
Написал консольный скрипт для faker (пока только создание пользователей).
https://github.com/nsdvw/classifieds/blob/master/protected/commands/FakerCommand.php
100 тысяч за 7 минут, для начала неплохо наверное.

Вопросы:
Не получается переопределить методы beforeAction и afterAction.
http://www.yiiframework.com/doc/api/1.1/CConsoleCommand#beforeAction-detail
Что с ними не так? Я хотел перед началом выполнения и после выполнения выдать сообщение о времени, например.
Если прописать что-то типа
protected function beforeAction(string $action, array $params)
{
echo date('H:i:s') . " - start $action generation";
parent::beforeAction($action, array $params);
}
то скрипт выдает это сообщение и подыхает, дальше не выполняется.

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

>Там наверно что-то готовое есть для логгирования в командах.


Я ничего не нашел в классе CConsoleCommand, чтобы выводило информационные сообщения.
Только beforeAction и afterAction, но не понимаю, как их корректно переопределить.
#629 #558019

>сомнительной соцсети в которую приличный человек и носа не сунет


Прямо заинтриговал.

>>556188
Написал консольный скрипт для faker (пока только создание пользователей).
https://github.com/nsdvw/classifieds/blob/master/protected/commands/FakerCommand.php
100 тысяч за 7 минут, для начала неплохо наверное.

Вопросы:
Не получается переопределить методы beforeAction и afterAction.
http://www.yiiframework.com/doc/api/1.1/CConsoleCommand#beforeAction-detail
Что с ними не так? Я хотел перед началом выполнения и после выполнения выдать сообщение о времени, например.
Если прописать что-то типа
protected function beforeAction(string $action, array $params)
{
echo date('H:i:s') . " - start $action generation";
parent::beforeAction($action, array $params);
}
то скрипт выдает это сообщение и подыхает, дальше не выполняется.

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

>Там наверно что-то готовое есть для логгирования в командах.


Я ничего не нашел в классе CConsoleCommand, чтобы выводило информационные сообщения.
Только beforeAction и afterAction, но не понимаю, как их корректно переопределить.
#630 #558038
>>558019

> parent::beforeAction($action, array $params);


Опечатка? что за array?

> И еще, что делать с фейкерскими имейлами?


генерировать шаблоном [email protected]
пароли прописать всем простые и одинаковые, чтобы ты мог под ними залогиниться

заодно нет риска отправить письмо реальным людям.

Обрати внимание, в faker это учтено и там есть свойство safeEmail: https://github.com/fzaninotto/Faker#fakerproviderinternet

Обрати внимание также, если бы ты использовал Доктрину, то у faker есть какая-то интеграция, чтобы автоматически находить нужные поля в моделях и заполнять: https://github.com/fzaninotto/Faker#populating-entities-using-an-orm-or-an-odm (хотя это наверно было бы не так быстро но зато кода меньше писать).

> логи


Есть такая штука: http://www.yiiframework.com/doc/guide/1.1/en/topics.logging
Надо посмотреть можно ли это перенаправить в консоль, желательно с метками времени, и стоит ли это использовать.

Вот еще список плагинов по теме: http://www.yiiframework.com/extensions/?category=8 - поищи там

для Юи 2 есть что-то такое: http://www.yiiframework.com/doc-2.0/guide-tutorial-console.html

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

Также можно сделать свой базовый класс для консольных команд и добавить в него метод для вывода текста через echo. Но тогда мы не можем видеть сообщения от Юи.
#630 #558038
>>558019

> parent::beforeAction($action, array $params);


Опечатка? что за array?

> И еще, что делать с фейкерскими имейлами?


генерировать шаблоном [email protected]
пароли прописать всем простые и одинаковые, чтобы ты мог под ними залогиниться

заодно нет риска отправить письмо реальным людям.

Обрати внимание, в faker это учтено и там есть свойство safeEmail: https://github.com/fzaninotto/Faker#fakerproviderinternet

Обрати внимание также, если бы ты использовал Доктрину, то у faker есть какая-то интеграция, чтобы автоматически находить нужные поля в моделях и заполнять: https://github.com/fzaninotto/Faker#populating-entities-using-an-orm-or-an-odm (хотя это наверно было бы не так быстро но зато кода меньше писать).

> логи


Есть такая штука: http://www.yiiframework.com/doc/guide/1.1/en/topics.logging
Надо посмотреть можно ли это перенаправить в консоль, желательно с метками времени, и стоит ли это использовать.

Вот еще список плагинов по теме: http://www.yiiframework.com/extensions/?category=8 - поищи там

для Юи 2 есть что-то такое: http://www.yiiframework.com/doc-2.0/guide-tutorial-console.html

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

Также можно сделать свой базовый класс для консольных команд и добавить в него метод для вывода текста через echo. Но тогда мы не можем видеть сообщения от Юи.
#631 #558041
>>558019

Вообще API у CConsoleCommand довольно беспорядочный. Хорошие дети, не проектируйте так:

http://www.yiiframework.com/doc/api/1.1/CConsoleCommand#copyFiles-detail

Непонятно каким вообще боком копирование файлов относится к консольным командам.

В этом плане конечно симфониевский Console Component намного образцовее спроектирован.
#632 #558053
>>557449

> но как быть с другими файлами, которые попадают в gitignore?


В гитигнор обычно добавляют всякие временные папки типа runtime и assets которые заполняются автоматически. Что в твоем гитигноре такого что тебе надо пересоздать руками?

>>557450

Покажи htaccess, где он лежит, конфиг Апача. Перезапускал Апач после правок конфига?

>>557529

Можно в переменную скопировать или как ты догадался, call_user_func использовать.

>>557561

Да

>>557574

Эмуляция для баз которые не умеют в плейсхолдеры. Mysql умеет, но включена или отключена эмуляция по умолчанию? Надо разбираться, держи:

http://php.net/manual/ru/pdo.prepared-statements.php
http://www.yiiframework.com/doc/api/1.1/CDbConnection#emulatePrepare-detail
http://php.net/manual/en/pdo.setattribute.php
http://stackoverflow.com/questions/10113562/pdo-mysql-use-pdoattr-emulate-prepares-or-not/10455228#10455228
https://bugs.php.net/search.php?cmd=display&search_for=ATTR_EMULATE_PREPARES+&x=0&y=0

Наконец у нас всегда есть вариант открыть исходники PHP и посмотреть код драйвера MySQL для PDO (Это Си, но он похож на PHP, только значков доллара перед переменными нет, перед переменными и функциями указывается тип, а точка значит примерно то же самое что и -> ):

https://github.com/php/php-src/blob/master/ext/pdo_mysql/mysql_driver.c#L616
Это mysql-специфичная функция инициализации нового объекта PDO, как я понимаю, и там сохраняется значение опции EMULATE_PREPARES (как я понимаю, она вызывается из конструктора).

https://github.com/php/php-src/blob/master/ext/pdo_mysql/mysql_driver.c#L390
Тут обрабатывается вызов setAttribute() и вроде тоже все сохраняется

https://github.com/php/php-src/blob/master/ext/pdo_mysql/mysql_driver.c#L175
Это вызывается при вызове prepare() или execute(), как я понял. Тут мы видим интересный алгоритм:

- если эмуляция включена, переходим в конец функции
- если версия MySQL меньше 4.01, то включаем эмуляцию
- иначе же ставим параметр указывающий на поддержку только плейсхолдеров-вопросиков:

stmt->supports_placeholders = PDO_PLACEHOLDER_POSITIONAL;
И вызываем функцию pdo_parse_params ( https://github.com/php/php-src/blob/master/ext/pdo/pdo_sql_parser.c#L441 ), код которой довольно сложный но интуиция мне подсказывает что функция заменяет в запросе те плейсхолдеры которые не поддерживаются базой (в данном случае именные плейсхолдеры с двоеточием).

Ну и наконец вызывается mysql_stmt_prepare, в описании которой ( https://dev.mysql.com/doc/refman/5.0/en/mysql-stmt-prepare.html ) мы видим что поддерживаются только плейсхолдеры-вопросы.

Таким образом мне кажется, запросы с порядковыми плейсхолдерами отправляются в MySQL, а вот запросы с именованными плейсхолдерами заменяются на стороне PDO.

> Пробовал наоборот включить ради теста


Попробуй указывать опцию в конструкторе PDO, некоторые опции нельзя менять после создания объекта.

> А теперь покажи мне то место в туториале, где говорится о методе для мультиинсерта


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

> или например про эмуляцию подготовленных выражений.


А это не особенность Юи, а PDO.
#632 #558053
>>557449

> но как быть с другими файлами, которые попадают в gitignore?


В гитигнор обычно добавляют всякие временные папки типа runtime и assets которые заполняются автоматически. Что в твоем гитигноре такого что тебе надо пересоздать руками?

>>557450

Покажи htaccess, где он лежит, конфиг Апача. Перезапускал Апач после правок конфига?

>>557529

Можно в переменную скопировать или как ты догадался, call_user_func использовать.

>>557561

Да

>>557574

Эмуляция для баз которые не умеют в плейсхолдеры. Mysql умеет, но включена или отключена эмуляция по умолчанию? Надо разбираться, держи:

http://php.net/manual/ru/pdo.prepared-statements.php
http://www.yiiframework.com/doc/api/1.1/CDbConnection#emulatePrepare-detail
http://php.net/manual/en/pdo.setattribute.php
http://stackoverflow.com/questions/10113562/pdo-mysql-use-pdoattr-emulate-prepares-or-not/10455228#10455228
https://bugs.php.net/search.php?cmd=display&search_for=ATTR_EMULATE_PREPARES+&x=0&y=0

Наконец у нас всегда есть вариант открыть исходники PHP и посмотреть код драйвера MySQL для PDO (Это Си, но он похож на PHP, только значков доллара перед переменными нет, перед переменными и функциями указывается тип, а точка значит примерно то же самое что и -> ):

https://github.com/php/php-src/blob/master/ext/pdo_mysql/mysql_driver.c#L616
Это mysql-специфичная функция инициализации нового объекта PDO, как я понимаю, и там сохраняется значение опции EMULATE_PREPARES (как я понимаю, она вызывается из конструктора).

https://github.com/php/php-src/blob/master/ext/pdo_mysql/mysql_driver.c#L390
Тут обрабатывается вызов setAttribute() и вроде тоже все сохраняется

https://github.com/php/php-src/blob/master/ext/pdo_mysql/mysql_driver.c#L175
Это вызывается при вызове prepare() или execute(), как я понял. Тут мы видим интересный алгоритм:

- если эмуляция включена, переходим в конец функции
- если версия MySQL меньше 4.01, то включаем эмуляцию
- иначе же ставим параметр указывающий на поддержку только плейсхолдеров-вопросиков:

stmt->supports_placeholders = PDO_PLACEHOLDER_POSITIONAL;
И вызываем функцию pdo_parse_params ( https://github.com/php/php-src/blob/master/ext/pdo/pdo_sql_parser.c#L441 ), код которой довольно сложный но интуиция мне подсказывает что функция заменяет в запросе те плейсхолдеры которые не поддерживаются базой (в данном случае именные плейсхолдеры с двоеточием).

Ну и наконец вызывается mysql_stmt_prepare, в описании которой ( https://dev.mysql.com/doc/refman/5.0/en/mysql-stmt-prepare.html ) мы видим что поддерживаются только плейсхолдеры-вопросы.

Таким образом мне кажется, запросы с порядковыми плейсхолдерами отправляются в MySQL, а вот запросы с именованными плейсхолдерами заменяются на стороне PDO.

> Пробовал наоборот включить ради теста


Попробуй указывать опцию в конструкторе PDO, некоторые опции нельзя менять после создания объекта.

> А теперь покажи мне то место в туториале, где говорится о методе для мультиинсерта


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

> или например про эмуляцию подготовленных выражений.


А это не особенность Юи, а PDO.
#633 #558056
>>557773

>>> А как посчитать это? Решиться ли это простым округлением?


>>Надо брать минимальное из расстояние по горизонтали и вертикали.


> А можно подсказку как это сделать?


В общем случае определение за сколько ходов животное дойдет из клетки A в B может быть сложным. Например если у нас животное ходит как шахматный конь, сложно понять сколько ему надо ходов.

Однако с кошкой все проще - она ходит в 8 сторон на $speed клеточек. Таким образом мы определяем расстояние между A и B по горизонтали, по вертикали, берем меньшее и делим на скорость кошки. Это дает нам, за сколько ходов кошка доберется от A до B.

Попробуй на бумаге или в редакторе нарисовать это.

> А как я буду оценивать вариант хода не имея возможности сравнивать его с другими ходами?


Оценочная функция дает оценку одному варианту хода (на клетку x, y) в баллах, она его ни с чем не сравнивает. Но я говорил о другом. Я говорил что поведение у разных животных разное, значит оценочные функции у них тоже разные и они должны быть в классе животного. А у тебя оценка делается в классе Animal, как будто все животные используют одну и ту же систему оценки хода и движутся по
одинаковой логике.

Но это не так. Например мышка должна избегать углов, а кошке их наличие без разницы.
506 Кб, 672x1023
#634 #558059
Статьи про ООП в учебнике по JS learn.javascript.ru такие няшные. ^_^
Даже читать интересно, особенно после всех этих малопонятных статей про методы и все такое. Хоть начинает складываться картина того каким образом код пишется в реальных проектах, да и понятия, которые раньше тут встречал и не понимал раскрываются. Надеюсь, то, что я читаю там, применимо и к другим языкам, к тому же PHP. Понятное дело, что такие штуки как __proto__ там заменены на какие-то свои, но общая концепция ведь одинакова?
#635 #558062
>>558059

Применимо, но частично. Например прототипов в PHP нет, зато есть нормальные классы. Но конечно второй язык учить проще чем первый.

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

А что касается _ _ proto _ _ , она там только для пояснения, в коде ее использовать нельзя (это не стандартное свойствот и работает не везде).
#636 #558063
Аноны, переходите в новый тред >>558058 (OP) , этот тред закрыт. Если я кому-то не ответил, напомните о себе в новом треде.
#637 #558086
>>558056

>между A и B по горизонтали, по вертикали


А как посчитать одновременно расстояние по вертикали и горизонтали?

>Но я говорил о другом. Я говорил что поведение у разных животных разное, значит оценочные функции у них тоже разные и они должны быть в классе животного. А у тебя оценка делается в классе Animal, как будто все животные используют одну и ту же систему оценки хода и движутся по


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

https://github.com/someApprentice/Cat-and-Mouse/blob/master/Classes/Mouse.php#L7

https://github.com/someApprentice/Cat-and-Mouse/blob/master/Classes/Mouse.php#L36

Ты все еще против циклов?

>>557829

>set это когда знаечние меняют извне. get возвращает значение. У нас никто символ для кошки менять не будет извне, мы прсто вызваем getSymbol а она вернет текущую иконку.


>>556079

>В твоем случае, что если кто-то унаследует класс и не переопределит поле symbol, что будет? Ведь в коде нет никаких намеков что его надо переопределить.


А как тогда намекнуть что поле symbol нужно переопределить? Добавить его в конструктор подойдет?
#638 #561986
>>555416
Доброе утро, ОП! Надо же, тред ещё не уплыл. Следуя твоим мудрым советам, всё ещё ковыряюсь в регэкспах
1) Задача про автоисправление ошибок. Перечитал урок, про \\b действительно там не увидел.
Сделал функцию, определяющую регистр (избавился от if) и сделал так, что не искажается регистр (меняю только 1 букву и всё).
Пробовал реализовать >Массив + цикл можно заменить на несколько вызовов функции
но обнаружил, что по сути написал тупую обёртку к той же preg_replace_callback - http://ideone.com/FQ0Jb1
ведь для каждого случая у меня разные 1) шаблон 2) коллбек, то есть мне их каждый раз отправлять, что тут можно повторно использовать не знаю. Единственное что можно было с текстом как с глобальной переменной работать, и тут вызов функции мог бы быть проще, но я так понял, глобальные переменные так лучше не использовать. В итоге вернулся к копипасту 3 раза как тут http://ideone.com/bD3KGf , всё равно красивее, чем мешанина из массивов.
В общем видимо тут уже ничего не улучшишь
2) Задача на автозамену http://ideone.com/c6pWA1
3) Задача на поиск e-mail http://ideone.com/RKsUDb тут я хотел сделать так, чтобы если в e-mail какой-то косяк, то он бы вообще не выводился, даже его часть, которая формально бы подходила, но столкнулся с разными вариантами, я там в тексте описал. Может быть, в этой задаче не надо так глубоко копать, но я пытаюсь поставить себя на твоё место и найти какие-нибудь скользкие варианты
Спасибо
2628 Кб, 1092x820
#639 #562691
Расскажите мне почему я пидор
#640 #562793
>>562691
Так с данными не работают в реальных проектах. Парси данные в соответствующие классы, где есть геттеры и сеттеры для всего, потом используй их. У тебя тут по меньшей мере 3 класса будет.
17 Кб, 604x365
#641 #568551
https://ideone.com/jCw9un

ОП, делаю задачку - числа с прописью. Вот сделал пока что только первую функцию где нужно сделать так, чтобы в зависимости от числа писало "рубля, рублей, рубль".

Чекни, пожалуйста, не сильно ли я наговнокодил?
Тред утонул или удален.
Это копия, сохраненная 1 ноября 2015 года.

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

Если вам полезен архив М.Двача, пожертвуйте на оплату сервера.
« /pr/В начало тредаВеб-версияНастройки
/a//b//mu//s//vg/Все доски