Это копия, сохраненная 12 мая 2018 года.
Скачать тред: только с превью, с превью и прикрепленными файлами.
Второй вариант может долго скачиваться. Файлы будут только в живых или недавно утонувших тредах. Подробнее
Если вам полезен архив М.Двача, пожертвуйте на оплату сервера.
Да, в нашем треде отвечают почти на все вопросы, только не сразу.
Это тред для начинающих. Не написал за свою жизнь ни одной программы и имеешь тройку по математике? Ты наш человек.
Предыдущий тред был тут: >>1135053 (OP) . Остальные треды есть в архиве: https://phpclub.tech/ (там есть поиск, так что можно легко найти обсуждение какой-то задачи или ответы на свой старый пост) или ищутся в гугле по словам "клуб изучающих php" и в архиваче.
Мейлач лежит? Есть запасной тред на доброчане: /s/res/23225.xhtml#i46467
Что самое главное для программиста? Умение аккуратно оформлять код (как, написано во втором посте).
Правила: ведем себя воспитанно, помогаем новичкам, читаем учебники, решаем задачки, постим ссылки на решения, ОП их проверяет и дает советы и замечания. ОП заходит редко, где-то раз в 2-3 дня, у него мало времени, не жди его, решай задачки дальше. ОП отвечает на все вопросы по его задачкам и учебнику, а вот насчет каких-то других вещей - только если останется время. Но в треде немало анонимных экспертов разного уровня, так что вряд ли вопрос останется без ответа.
С чего начать
У нас есть свои уроки по основам PHP, они собраны и выложены по адресу http://codedokode.github.io/phpbook (вас отредиректит на другой домен, не читайте, не сохраняйте, не запоминайте его, он временный). Это учебник для изучающих с нуля, то есть если ты вообще ничего не знаешь, то можно начать с него. Он простой и понятный. Там есть задачи, их нужно решать (чтобы стать программистом, надо писать код — иначе никак). Пости ссылки на решения в тред, мы их проверим, напишем замечания и дадим советы по улучшению. С другой стороны, если этот учебник тебе не нравится, можно читать любой другой. Или официальный мануал. Или все сразу.
Устанавливать пока что ничего не требуется, разве что редактор кода вроде Sublime Text 3, Notepad++, Visual Studio Code, Netbeans PHP или PhpStorm (с ним будет удобнее).
Если не знаешь как решать, запости код, напиши в каком месте остановился и попроси подсказку.
Ты прошел весь учебник? Молодец, но это были лишь основы языка PHP, этого недостаточно. Вот что в идеале надо изучить еще: ООП, как работает веб-сервер, HTML/CSS, SQL, PDO, работа с таблицами в БД, работа с формами, MVC, git, composer, JS, фреймворки, автоматизированное тестирование.
Надо переходить к более серьезным задачкам, которые научат тебя всему этому.
- для начала прочти урок https://github.com/codedokode/pasta/blob/master/soft/web-server.md
- установи Апач + PHP (советы выше и ниже) и читай туториал http://php.net/manual/ru/tutorial.php
- Учи HTML/CSS и SQL, PDO, хотя бы основы
- Далее простая, но полезная задача сделать список студентов, в ней много полезных советов: https://github.com/codedokode/pasta/blob/master/student-list.md
- Более сложная задача сделать файлообменник на микрофреймворке Slim: https://gist.github.com/codedokode/9424217
- Еще более сложная и долгая задача на Yii/Symfony: https://gist.github.com/codedokode/8733007
- После нее можно изучать автоматизированное тестирование https://gist.github.com/codedokode/a455bde7d0748c0a351a
- Если ты все решил, переходи к Symfony 3/Doctrine 2
- Почитать про паттерны http://designpatternsphp.readthedocs.org/ru/latest/README.html (если ты не изучил ни одного фреймворка, то это будет рановато), тут с примерами кода http://designpatternsphp.readthedocs.org/ru/latest/README.html . Имей в виду что без примеров использования их учить бесполезно - не поймешь, хочешь увидеть примеры использования паттернов - ковыряй исходники Симфони, например Symfony Forms. Не заучивай паттерны - смотри код и думай, зачем тут они использованы.
Чтобы делать эти задания, тебе надо установить Апач + PHP (можно заодно сразу и MySQL) на компьютер. Вот полезные инструкции:
https://github.com/codedokode/pasta/blob/master/soft/php-install.md
https://github.com/codedokode/pasta/blob/master/soft/apache-install.md
Может тебе понадобится пользоваться командной строкой, вот гайд https://github.com/codedokode/pasta/blob/master/soft/cli.md
Решения задач лучше показать мне, особенно на ООП,так как сам ты вряд ли увидишь все ошибки. Пости свой код на гитхаб и вкидывай ссылку в тред по мере решения. Я прокомментирую и укажу на ошибки.
Параллельно стоит подучивать английский, на первых порах можно без него, но по мере развития придется все чаще сталкиваться с англоязычными статьями, так что лучше не откладывать. Читать можно news.ycombinator.com - это что-то вроде их хабра. Также можно начинать смотреть фильмы и видео на английском.
Также, у нас есть задачи которые позволят тебе изучить или подтянуть до нормального уровня знания JS/HTML/CSS/SQL. Решай их параллельно с задачами выше.
- HTML/CSS: https://github.com/codedokode/pasta/blob/master/html/html.md
- JS: https://gist.github.com/codedokode/ce30e7a036f18f416ae0
- SPA (сложно): https://github.com/codedokode/pasta/blob/master/js/spa.md
- Проверялка решений на JS: http://dkab.github.io/jasmine-tests/
- MySQL: https://github.com/codedokode/pasta/blob/master/db/databases.md
Что почитать
- Мануал по PHP — http://www.php.net/manual/ru/langref.php
- Сайт phptherightway (перевод на русский: http://getjump.me/ru-php-the-right-way/ )
- По PHP: Профессиональное программирование на PHP Джордж Шлосснейгл
- По PHP: Мэтт Зандстра — PHP: Объекты, шаблоны, методики программирования
- JS: learn.javascript.ru
- Про Git: https://git-scm.com/book/ru/v1
- Новости IT на англ. https://news.ycombinator.com/
Оформляй код аккуратно!!! — например пропусти через phpformatter.com . Также, если ты пользуешься IDE вроде PhpStorm, Netbeans, Eclipse, то в них эта опция встроена, подробнее: https://gist.github.com/codedokode/8759492
У ОПа нет аккаунтов и групп вконтакте, в фейсбуке, в твиттере, все "пхп-треды" там поддельные.
Платиновые вопросы
- Почему PHP? Потому что вакансий море, и учить легко.
- Сайт опять упал!!!!! — Не паникуй, а открой http://rghost.ru/6bfCY9lfl и получи личную немного устаревшую оффлайновую копию сайта (можно читать хоть на андроиде без интернета)
- Что надо знать чтобы найти работу - разработчику: PHP, SQL, HTML/CSS, JS, ООП, Git, композер, MVC, фреймворк. Верстальщику - HTML/CSS, JS, jQuery. У нас в треде были люди, которые практически с нуля учились и смогли найти работу.
- Что будут спрашивать на собеседовании если 0 опыта - гонять по теории, по официальному мануалу PHP, давать дурацкие задачки на переворачивание строк, гонять по SQL (транзакции, внешние ключи, напиши запрос), по JS (как сделать анимацию при нажатии кнопки), ну погугли, не ленись
- Можно подробнее про поиск работы, собеседования - нет, ОП писать не будет, но может кто из анонов захочет рассказать. Поищите тред перезвонивших, а также раздел /wrk/
- Сколько времени надо изучать все это? - все зависит от тебя, но не меньше 6-8 месяцев
- Нужен ли ООП, фреймворки, MVC, git, composer? — Да, однозначно. Посмотри любую вакансию.
Если тебе лень выравнивать код руками, закачай его на http://beta.phpformatter.com/ и нажми «format» (иногда сайт не работает). Робот исправит выравнивание и отступы в мгновение ока (да, прогресс не стоит на месте). Если ты используешь мощную IDE вроде PhpStorm, там тоже есть функция форматирования кода.
Горячие клавиши для форматирования кода в разных IDE: https://gist.github.com/codedokode/8759492
Вообще, в PHP долгое время не было единого стандарта оформления кода, все писали как попало и было много бардака, но сейчас дело лучше — есть стандарты PSR-1 и 2. Вот как надо оформлять код:
- переменные и функции пишутся с маленькой буквы, подчеркивание не используется, используется camelCase, пример: $x, $numberOfPeople, printResults()
- Название функции начинается с глагола, в стиле «сделайЧтоТо»
- не знаешь английский? Не беда, в 21 веке есть решение этой проблемы. Не пиши транслитом, открой лучше Гугл Транслейт или slovari.yandex.ru и найди название для переменной там
- в именах классов используется CamelCase, первая буква большая, «_» может использоваться
- мы предпочитаем подстановку переменных вместо конкатенации строк: "I am $age years old" — хорошо, 'I am ' . $age . ' years old' — плохо из-за обилия точек и кавычек
- мы используем для отступов 4 пробела (можно настроить редактор, чтобы при нажатии Tab он вставлял 4 пробела)
Вот ссылка на стандарты, где все это описано подробнее и даны примеры оформления:
PSR-1: https://github.com/samdark/fig-standards-ru/blob/master/accepted/ru/PSR-1-basic-coding-standard.md
PSR-2: https://github.com/samdark/fig-standards-ru/blob/master/accepted/ru/PSR-2-coding-style-guide.md
Проверена задача https://github.com/dsgaljkeguhodgiosetuhsegjposguh/studlist3/ вот тут вот: >>1152248
Напомню всем, что у нас есть архив тредов phpclub.tech . Там есть поиск и можно найти, например, все обсуждения задачи про кредит. Или найти свой старый пост и все ответы к нему.
Читаю:
https://ru.wikipedia.org/wiki/Принцип_открытости/закрытости
>Принцип открытости/закрытости (англ. The Open Closed Principle, OCP) — принцип ООП, устанавливающий следующее положение: «программные сущности (классы, модули, функции и т. п.) должны быть открыты для расширения, но закрыты для изменения»;
Думаю -"Окей, должно быть имеется ввиду, что программная сущность должна принимать всегда только один и тот же набор типов параметров и возвращать всегда только один и тот же тип результата, а её содержание может меняться(расширяться) как угодно"
Например:
function(Type $type): Returnable
{
// Здесь могут происходить какие угодно расширения
return $returnable;
}
Перехожу дальше к описанию:
>Принцип открытости/закрытости означает, что программные сущности должны быть:
>открыты для расширения: означает, что поведение сущности может быть расширено путём создания новых типов сущностей
Думаю: "Должно быть здесь не правильный перевод - не понятно что за сущности имеются ввиду"
Открываю английскую версию вики:
https://en.wikipedia.org/wiki/Open/closed_principle
>A module will be said to be open if it is still available for extension. For example, it should be possible to add fields to the data structures it contains, or new elements to the set of functions it performs.
Thinking: -"What's kind of fields or elements is talking about?"
Гуглю: open/close principle php example
и получаю https://github.com/wataridori/solid-php-example/blob/master/2-open-closed-principle.php
И всё становиться понятно! Как я и думал ранее, сущность должна не поддаваться изменению со стороны получения и возврата данных, чтобы, например, как показано в примере, была возможность наследования от такой абстрактной сущности
Возможность такого наследования, это конечный результат такого принципа, или это только одно из вытекающих его применения?
Почему по коду понять проще чем по определениям? Это проблема источника или моя?
Читаю:
https://ru.wikipedia.org/wiki/Принцип_открытости/закрытости
>Принцип открытости/закрытости (англ. The Open Closed Principle, OCP) — принцип ООП, устанавливающий следующее положение: «программные сущности (классы, модули, функции и т. п.) должны быть открыты для расширения, но закрыты для изменения»;
Думаю -"Окей, должно быть имеется ввиду, что программная сущность должна принимать всегда только один и тот же набор типов параметров и возвращать всегда только один и тот же тип результата, а её содержание может меняться(расширяться) как угодно"
Например:
function(Type $type): Returnable
{
// Здесь могут происходить какие угодно расширения
return $returnable;
}
Перехожу дальше к описанию:
>Принцип открытости/закрытости означает, что программные сущности должны быть:
>открыты для расширения: означает, что поведение сущности может быть расширено путём создания новых типов сущностей
Думаю: "Должно быть здесь не правильный перевод - не понятно что за сущности имеются ввиду"
Открываю английскую версию вики:
https://en.wikipedia.org/wiki/Open/closed_principle
>A module will be said to be open if it is still available for extension. For example, it should be possible to add fields to the data structures it contains, or new elements to the set of functions it performs.
Thinking: -"What's kind of fields or elements is talking about?"
Гуглю: open/close principle php example
и получаю https://github.com/wataridori/solid-php-example/blob/master/2-open-closed-principle.php
И всё становиться понятно! Как я и думал ранее, сущность должна не поддаваться изменению со стороны получения и возврата данных, чтобы, например, как показано в примере, была возможность наследования от такой абстрактной сущности
Возможность такого наследования, это конечный результат такого принципа, или это только одно из вытекающих его применения?
Почему по коду понять проще чем по определениям? Это проблема источника или моя?
Обожаю этот тред из-за авки с Юкинощитой ^^
$result = $pdo->query("SELECT mail FROM users WHERE mail='$mail'");
if (!$result){
$reg = $pdo->query("INSERT INTO users VALUES('$name','$mail','$password','0')");
}else {
MessageSend (1, 'Пользователь с таким E-mail адресом уже существует!');
}
Что не так делаю?
>Что не так делаю?
Потому что возвращается объект PDOStatement, а не результат. Результат, судя по всему, получается во время выполнения функции foreach, потому что PDOStatement это Traversable.
Чтобы получить результат нужно выполнить execute()
https://secure.php.net/manual/ru/pdostatement.execute.php
https://secure.php.net/manual/ru/pdo.query.php
https://secure.php.net/manual/ru/class.pdostatement.php
Так же,
У тебя можно выполнить SQL-инъекцию - чтобы её избежать, нужно использовать плейсхолдеры
См. функции:
https://secure.php.net/manual/ru/pdo.prepare.php
https://secure.php.net/manual/ru/pdostatement.bindvalue.php / https://secure.php.net/manual/ru/pdostatement.bindparam.php
https://secure.php.net/manual/ru/pdostatement.execute.php
В этой задаче, учел твои рекомендации по кредитному iphone.
>- прибавляем проценты и комиссию к остатку долга (!не >вычитаем ничего пока!)
>- если остаток маленький, выплачиваем сколько осталось и >уходим
>- иначе платим 5000
>«Платим» здесь значит уменьшаем долг и увеличиваем >общую сумму выплаченного.
По ману
>особенность, которая может быть использована для того, чтобы получить ссылку на вызываемый класс в контексте статического наследования.
По Зандстре:
>в php 5.3 введена концепция позднего статического связывания, самым заметным ее проявлением является введение ключевого слова static.
Какие есть незаметные проявления, кроме как получения контекста вызова через ключевое слово static?
>>52813
>Как выкладывать допиленную версию сайта на вордпрессе на виртуальный хостинг?
Не нужно писать, что вопрос непонятный. Для тех кто внимательно читает все ясно.
Мне нужно автоматизировать разработку на вордпрессе, хостинг - виртуальный, ОС на локальном компьютере - убунту. Нужно выкладывать допиленные версии сайта чтобы не возникало проблем с базой и т.д. Желательно автоматизировать версионность и обновление. В общем нужно решить эту задачу раз и навсегда, пока сайт на виртульном хостинге.
>Если просто заменить файлы, то все сломается скорее всего, ведь есть еще база данных и разные настройки.
>Нужно выкладывать допиленные версии сайта чтобы не возникало проблем с базой и т.д.
>Мне нужно автоматизировать разработку на вордпрессе
>>52843
Это не чат в телеграме. Иди постить смешные картинки в какое-нибудь другое место.
>>52826
Ты правильно делаешь, что хочешь автоматизировать рутинные вещи. Немного в общих чертах про деплой написано тут >>1143223
С копированием измененных файлов, я думаю, особых проблем не будет.
Что касается базы данных, то тут все непросто. Вообще, обычно изменения структуры БД (добавление таблиц и колонок) принято делать через миграции, вот их общее описание: https://www.google.ru/url?q=https://habrahabr.ru/post/121265/&sa=U&ved=0ahUKEwjN9I2KxOHZAhXmJ5oKHbxYBO8QFggUMAA&usg=AOvVaw1D9Ujm8m98F29f1y_Y1AaB
Они поддерживаются во многих фреймворках, например: https://symfony.com/doc/master/bundles/DoctrineMigrationsBundle/index.html
Но во-первых, в ВП их скорее всего нет, во-вторых,миграции не помогут перенести какие-то изменения, сделанные через админку, например, добавление статьи.
Я когда-то делал так: дампил БД с продакшена, заливал локально, делал правки, делал дамп, заливал на продакшен. Но что, если кто-то в это время делал правки на сайте? Они потеряются. Плюс, если в БД может храниться конфиг, разный для dev и production.
Так что я бы искал какое-то специализированное решение именно для ВП.
Я погуглил, есть какие-то плагины (вроде WP migrate DB), но они по сути переносят тот же самый дамп БД.
То есть ВП сам по себе не очень заточен на традиционную разработку, он ведь сделан для не-программистов, которые правят сайт через админку.
Поправьте меня если я где-то не прав.
public, private & protected - тут все понятно.
abstract - перед класссом пишем, если хотим что бы он был лишь основой, от которой будут наследоваться другие классы? Создавать объекты таких классов нельзя.
Перед методом пишем abstract - что бы его принудительно переопределять в потомке?
Вот пишу я кошечек-мышечек, и например делаю abstract class Animal, в нем например будут обычные методы, которые будут работать у потомков без переопределения, по типу
public function move() {
... ходит на выбраную клеточку
}
так и абстрактные, которые будут принудительно переписаны как для кошечки, так и для мышечки
abstract public function choseMove() {}
верно с этим?
static - это когда тебе нужно без создания объектов прогонять что-то через функции.
аналог простому процедурному программированию, но через обертку ооп.
например пишешь такое
class Helper {
static public function convertSqlDateToHuman ($sqlDate) {
...
}
}
Ну и в коде просто используешь когда хочешь в виде
$readableDate = Helper::convertSqlDateToHuman($sqlDate);
На этом этапе для начала правильно всё? Принцип использования всего этого верный у меня в голове?
Поправьте меня если я где-то не прав.
public, private & protected - тут все понятно.
abstract - перед класссом пишем, если хотим что бы он был лишь основой, от которой будут наследоваться другие классы? Создавать объекты таких классов нельзя.
Перед методом пишем abstract - что бы его принудительно переопределять в потомке?
Вот пишу я кошечек-мышечек, и например делаю abstract class Animal, в нем например будут обычные методы, которые будут работать у потомков без переопределения, по типу
public function move() {
... ходит на выбраную клеточку
}
так и абстрактные, которые будут принудительно переписаны как для кошечки, так и для мышечки
abstract public function choseMove() {}
верно с этим?
static - это когда тебе нужно без создания объектов прогонять что-то через функции.
аналог простому процедурному программированию, но через обертку ооп.
например пишешь такое
class Helper {
static public function convertSqlDateToHuman ($sqlDate) {
...
}
}
Ну и в коде просто используешь когда хочешь в виде
$readableDate = Helper::convertSqlDateToHuman($sqlDate);
На этом этапе для начала правильно всё? Принцип использования всего этого верный у меня в голове?
Благодарю.
из двух сортов говна выбирай mod_php, он быстрее. php-cgi это вообще штука из начала нулевых. в целом самая быстрая связка (при одинаковой версии языка) это nginx+php-fpm.
а вообще хостер часто предлагает несколько версий пхп на выбор, из них выбирай более новый.
Как правильно работать с сертификатами Let's Encrypt. Допустим, у меня есть 1 домен example.ru
И я хочу периодически (несколько раз в день) добавлять новые поддомены. Для каждого поддомена нужен сертификат.
На сайте летсэнкрипт я вычитал:
>The main limit is Certificates per Registered Domain, (20 per week). A registered domain is, generally speaking, the part of the domain you purchased from your domain name registrar. For instance, in the name www.example.com, the registered domain is example.com. In new.blog.example.co.uk, the registered domain is example.co.uk. We use the Public Suffix List to calculate the registered domain.
То есть я могу делать только 20 доменов в неделю, райт?
Есть другой способ решения вопроса:
>If you have a lot of subdomains, you may want to combine them into a single certificate, up to a limit of 100 Names per Certificate. Combined with the above limit, that means you can issue certificates containing up to 2,000 unique subdomains per week. A certificate with multiple names is often called a SAN certificate, or sometimes a UCC certificate.
Тут написано, что для большого количества субдоменов, можно выпустить один сертификат.
Но моя проблема в том, что новые субдомены добавляются постепенно (там система такая, пользователи создают новые субдомены), а создавать новый можно только 20 раз в неделю.
Но если мне нужно больше?
Тут еще в дубликатах проблема. Для тех, которые уже зареганы, можно пересоздать только 5 раз в неделю:
>We also have a Duplicate Certificate limit of 5 certificates per week. A certificate is considered a duplicate of an earlier certificate if they contain the exact same set of hostnames, ignoring capitalization and ordering of hostnames. For instance, if you requested a certificate for the names [www.example.com, example.com], you could request four more certificates for [www.example.com, example.com] during the week. If you changed the set of names by adding [blog.example.com], you would be able to request additional certificates.
Очевидным способом решения является откладывать выпуск сертификата на 0.5 суток и делать их кучей, но тогда у пользователя не будет возможности получить свой домен сразу.
Тебе по идее нужен wildcard certificate на *.example.com. Начинается по моему от 100 долларов в год.
Истории успеха аноны могут поделиться. Ну там начал 3 месяца назад, сеичас зашибаю по 10к сие изучаю для подработка и на ништяк мне бы хватило, подкачал тело, появилась тян, за ипотеку выплатил и прочее....
Нужна мотивация аноны.
Начал изучать в 2016 по сайту опа. Оп сильно помогал здесь, да будет он здоров счастлив.
Сейчас живу в тайланде с няшным трапиком (я не гей). Зарабатываю на фрилансе около 2500 баксов в месяц. В 2015 я жил в ебенях севера, и мечтал о том, чтобы лето длилось дольше месяца. Лучшей мотивации и не надо.
Расскажи что ли какой путь ты прошел? Я вот изучаю чет изучаю, поработал на всякие шараги где по сути нихуя не делаешь. Наверное я слишком медленно развивался за последние 2 года.
В том смысле, что я изучил пхп (его фишки и особенности) до этого писал на C++, поэтому на это ушло пару дней, выучил SQL, разобрался с ООП и всякими паттернами, посмотрел как устроены некоторые фреймворки, научился работать с Yii2, далее вкратце изучил алгоритмы, сети (ну это как дополнительно), написал пару сайтиков и что-то вроде собственного фреймворка (просто готовая архитектура, виджеты, модули, шаблоны, куча функций и всё такое), покурил безопасность и нашёл работу.
На работе как макака делаю одно и то же, однотипные вебсайты на yii2. Фронтенд знаю на уровне написать адаптивную верстку на бутстрапе и простенькие скрипты на JS.
И что дальше? Изучать что-то теоретическое, что никогда не пригодится и через полгода забудется. Я не хочу навсегда остаться веб-макакой, мне нужно постоянное движение вперед, без этого я начинаю впадать в уныние.
Что вы сейчас изучаете, антоны, и как вам это помогает в повседневности?
Я вот думаю перекатиться в геймдев, т.к. C++
знаю на уровне разговорного, да и моделировать умею неплохо. Но в геймдеве знаний нужно гораздо больше,
поэтому будет стимул развиваться
>>53378
я иногда смотрю вакансии, и на пхп такое ощущение, что вообще нет сложной работы, только веб студии ищут макак для хуяринья сайтиков на говноцмсках. Нет сложных сервисов или самописных проектов с тяжелым бэк-эндом. Либо есть но туда нужен синьор-помидор 100к зп в мухосрани и 5+лет опыта в крупных конторах.
В 90% вакансий льют тебе в глаза ссанину, что сложные задачи, всё интересно и много развития. А в итоге ты листаешь требования, видишь что там помимо стандартной заготовки из html+css+js+lamp на самом деле сидят такие замечательные пикрилы, которые как бы не обязательны, но хуй там плавал, поработав пару раз в подобных шарагах, ты понимаешь, что всё там написано только на таком, и "писать" ты тоже будешь только на этом. Никаких сложных проектов долгоиграющих с обширной логикой. Будешь сначала поддерживать старое говно, кому-то баннер поменять, кому-то метрику на форму прилепить и так далее, и со временем ты вырастешь в самостоятельного почетного говнолепа, который будет с 0 нахуяривать свеженькие сайты для новых клиентов изо дня в день. Такие вот истории.
Вот значит дети не учите ПХП. Закончите жизнь эмигрантом в Азии в окружении трапов. Лучше учите питон, чтобы уехать в европку поебывать няшных шведок.
Вот согласен. Это история с одной стороны как нужно хуячить, а с другой — как не надо делать. Но если человек счастлив — то похуй.
Плюс к тому мое диванное манямнение, что трудность переезда в европку не в языках программирования, а в человеческих языках: средний образованный европеец - полиглот.
Вот например работка в европке для пыхера http://knplabs.com/en/career/jobs/mission/paris - то бишь тебе нужен и английский и французский.
В Европку переехать один хуй проще, чем в СШАшку. И ровно настолько же бесполезней. Особенно во Францию бгг. Ну это если ты не ебанутый галломан, но таковые программисты давно уже там.
Да особо нечего рассказывать. Попробовал силы у ОПа, выяснил что на уровне продвинутых задач уже сосу. Потом сделал пару сайтов для себя и пару чтобы было что показать. Поучился немного на вебинарах не буду рекламировать контору. Там мне подняли скилл, дали поработать с галпом, npn, PHPStorm, Composer, xDebug, PHPUnit, git, bitBucket, Eloquent, laravel и устроили на удалёнку за гроши. У меня была работа, а по удалёнке требовалось изредка пинать базу и редактировать кое что, так что ради опята я согласился. Спустя два месяца поступило предложение покруче. Ну как-то так прыгал с работы на работу.
>>53379
Сперва я подумал оставить твой комментарий. Но потом я понял что если-бы мне это пруфанули в 2012, то я не потратил бы зря несколько лет своей жизни.
>>53386
У каждого своя мечта бро, кому-то Европа, кому-то Тайланд, кому-то Канада, а кому-то и собаку норм.
Тоесть даже это может быть плюсом при перекате в рельсы?
Думаю просто у меня стереотипы к пыхе, вот и не хочу с пыхой долго ебаться
А что за проекты на фрилансе например? Нужно что уметь что бы так вывозить? И еще у тебя чисто фриланс с рандомными заказами, или по факту просто удаленка с постоянным контрактом и 2500 на руки ежемесячно?
Проблема только в том, что ища работу на пхп, хз как найти тот самый бэкэнд с хайлоадом. Разве что игнорировать галеры на которых тебя по сути продают в рабство хуярить очередной сайт, а обращаться в совсем неит крупные компании, но которые ебашат свои собственные ресурсы для автоматизации бизнес-процессов.
с т.з. того, о чем я говорил, это проект, в котором ты при решении задач должен держать в голове ограниченность доступных ресурсов.
echo "{$i}x{$i} = {pow(&i, 2)} \n"; выводит просто значение
https://ideone.com/QEtH2w
Псст... так нельзя делать, дружок :)
Если язык позволяет тебе всё, не значит что ты можешь вертеть им как хочешь.
>ельзя делать, дружок :
Я уже понял, что тут как в С/С++ не сделаешь, а так как ты создал это хуево и без создания переменной не обойтись
Команды из мана не запрос всей таблицы не работает:
$var = R::getAll( 'SELECT * FROM article' );
print_r($var['id']);
Работает только R::getCol
$menu_array = R::getCol('SELECT title FROM articles');
print_r($menu_array);
Но это мне не подходит.
mysqli юзать не хочется...
Поставил 100мсек лимита времени выполнения, 10кбайт лимита памяти - и все! Теперь у нас и хайлоад, и бигдата.
Можно пиздеть о соответствующем опыте.
Круто, рад за тебя. По сколько часов в день, дней в неделю трудишься?
А ты в офисе успел поработать? Где скилл набивал?
Если сразу на фриланс полез, то вангую, в рублях такой доход ты в ДСном офисе получать не сможешь.
>Питон сложнее пхп?
Я начинал с питона, пару месяцев учил, потом сделал перекот на пхп.
Как по мне, то они оба легкие, просто что на питоне писать гораздо приятнее. И еще, как мне показалось, циклы в питоне реализованы на много лучше. Но с другой стороны пхп больше адаптирован для веба + его интерпретатор нативно работает с апачем, никакой ебли uwsgi и virtualenv.
Программач, выручай.
Абу новую парашу закрепил заместо списка досок сверху и снизу.
Добрый аноним через настройки пользовательский ЦСС вернул список досок взад наверх:
#boardNavBottom {position: absolute; top: 40px}
.logo {margin-top: 70px}
Вопрос: как подобное продублировать вниз? У меня есть вкладка, где список досок внизу есть а сверху нет. Может как-то через инспектор элементов можно понять? Или местные гуру смогут в пару изящных строчек это дело поправить без таких дебрей?
Благодарю за внимание.
Ничего. Оценить можешь только ты.
я в прошлых тредах писал. вкатился в симфони, 90к, удаленка. 1.5 опыта. начинал с 30к на галере.
Вот это круто! То есть знаний, которые передает ОП достаточно для вкатывания?
Самому нравится работа?
Да, как сделаешь файлообменник из шапки - смело можно начинать искать работу. Можно и раньше, я считаю.
Работа нравится, интересная предметка (форекс).
Тупо сайты делать, наверное, не так интересно.
Выглядит неплохо. Наверное, неприязнь к синтаксису проходит, когда несколько разных языков выучишь.
Мне бы твои проблемы! Есть идея для продукта которая точно выстрелит и будет кормить годами, но не хватает знаний на его написание. Найти бы специалиста, который готов к сотрудничеству.
Доброкун запилил вот такую штуку, которая позволяет вернуть список досок вниз, сверху при этом остается пробел и пустое поле:
.cntnt__left_sticky {height: 120px}
ul.fm li {float: left}
.cntnt__left {position: absolute; top: 50px; height: 100px}
.logo {margin-top: 120px}
ul.fm li a{display: block; max-width: 34px; white-space: nowrap; overflow: hidden; margin-right: 5px; text-decoration: none}
.fm__header {display: none}
li.fm__item {float: left; margin: 0; display: inline}
Но если добавить код приведенный ранее- сверху список появляется, а снизу пропадает. Как работает данная магия?
нужно ли учить винду, чтобы сидеть на двачах?
Надо что бы поле с непарным айдишником бросало большим блоком в одну сторону, а с парным в другую.
кусок кода страницы
https://pastebin.com/S88kFq1P
Архив с исходником страницы
http://rgho.st/89NxY99WZ
>>53797
Не актуально, уже разобрался.
Во первых ничего не видно на скрине и не понятно в чем проблема.
Сформулируй четко как ты хочешь что бы выстраивались блоки, и сделай четкий скрин, на котором видно будет.
Если ты хочешь что бы кто-то запустил твой код, то пожалуйста сделай его автономным.
Я не прочь создать php файлик и скопипастить туда, но у тебя мешанина из селекта из базы и вьюхи в одном флаконе, поэтому я даже пробовать не буду.
Что у тебя прямо в файле создан руками такой вот например массив https://ideone.com/CGl3II
Который и разбирается в html'e в дальнейшем
Ну и дальше у тебя какая-то копипаста адовая в коде, я пытался представить что тебе нужно, но чет 20 минут хуярил код на идеоне и забил.
У меня есть 2 разных ряда с блоками, в одном блок с комментариями слева а статьи справа, в другом наоборот. Я хочу наполнить эти блоки из бд циклом так, что бы сохранить эту структуру.
Для теста я обернул эту всю конструкцию в цикл, достал из бд id категорий, и по ним пытался сделать распределение этих блоков, парные id идут влево, непарные вправо.
Это сработало, но лишь частично, как видно на предыдущем скрине, идет id 2, затем id 3, а после 2 пустых ряда с блоками, и уже после них идет id 4 и id 5 и так далее.
Вот упрощенный код:
https://pastebin.com/zdnKAewR
Если добавить else или elseif противоположным условием, то пропусков не будет, но блоки продублируются (11 22 33 44 55 итд).
Отаравить n http-запросов, но не сразу а в течение m минут. Между отправкой должны быть интервалы (примерно одинаковые).
Есть скрипт, который получает от клиента (веб-морды) и собирает в кучу данные для отправки. Но чтобы отправить, к примеру, 30 запросов в течение 20 минут при этом не повесить UI на это время нужно как-то изъебнуться.
Реально ли это запилить средствами php без применения доп. костылей вроде cron'а и т.п.?
Попробуй на сервере выставить время выполнения на 2000 секунд и юзай http://php.net/manual/ru/function.sleep.php между отправками запросов.
>при этом не повесить UI на это время нужно как-то изъебнуться.
Не понял тебя. Ты собрался из браузера отправлять? Хочешь отправлять запросы, но при этом что бы страничка брауза не ушла в перезагрузку длиною в пол часа? Тогда просто ебашь яваскриптом на фоне эти запросы или дергай аяксом php-скрипт, который будет их отправлять.
Аналогично предыдущему - можешь кроном дергать тот же самый пхп скрипт.
Вот еще проще:
<?php
$array = array(1, 2, 3, 4, 5, 6, 7, 8, 9);
?>
<?php foreach ($array as $key => $item): ?>
<div style="border: 1px solid; width: 80px; height: 20px; margin-top: 5px;">
<?php
if ($item % 2 == 0) {
echo $item.'<br>';
}
?>
</div>
<div style="border: 1px solid; width: 80px; height: 20px; margin-left: 40px; margin-top: 5px;">
<?php
if ($item % 2 != 0) {
echo $item;
}
?>
</div>
<?php endforeach; ?>
Результат пикрелейтед. Как убрать пропуски и сделать как на пикрелейтед2 ?
Вот еще проще:
<?php
$array = array(1, 2, 3, 4, 5, 6, 7, 8, 9);
?>
<?php foreach ($array as $key => $item): ?>
<div style="border: 1px solid; width: 80px; height: 20px; margin-top: 5px;">
<?php
if ($item % 2 == 0) {
echo $item.'<br>';
}
?>
</div>
<div style="border: 1px solid; width: 80px; height: 20px; margin-left: 40px; margin-top: 5px;">
<?php
if ($item % 2 != 0) {
echo $item;
}
?>
</div>
<?php endforeach; ?>
Результат пикрелейтед. Как убрать пропуски и сделать как на пикрелейтед2 ?
Интерфейса для управления не дается, мы его получаем на сайте разработчика. То есть покупателю отдается нагруженная часть, из БД на vds данные каким-то образом передаются на сайт разработчика и выводятся в интерфейсе.
Вопрос в том каким образом они передаются в интерфейс на сайте разработчика, как он получает данные из БД на моем вдс если ему известен только домен?
https://ideone.com/YpKCss
Держи, ты просто плохо понял как циклы и условия работают. Попробуй решить задачу про физз-базз класичесскую для начала. Это как раз примерно тот случай. По коду получишь пикрил.
Немножко не так как я хотел, но в твоих словах определенно больше смысла, спасибо, буду дальше работать.
добра:3
ВСМЫСЛЕ БЛЯДЬ НЕ ТАК КАК ТЫ ХОТЕЛ? Ты картинку нарисовал - касарь долж... я тебе четко как на ней все вывел.
Если ты хочешь рисовать отдельно левый блок - и отдельно правый, то делай вот так.
https://ideone.com/IGnQmL
Если они у тебя кардинально отличаются и html код левого и правого блоков сильно разнятся - это ок, но в том простом случае который ты хотел - это просто копипаста, которую я вынес за пределы условия.
Как то так вышло. https://pastebin.com/Fn6nEcwf
Интуитивно ткнул пальцем в небо и вставил перед блоками <?php if ($key % 2 == 1): ?>, а уже внутри if с ключами к массиву. Работает как надо, но чем до конца всю логику проследить не могу. Пиздец(
мой косяк, уже вроде бы разобрался.
Получил временный бан на сайте, теперь на любой поисковый запрос получаю код 429(too many requests). Поставил впн, сменил бразуер, а толку ноль.
Вопрос сюда, потому что пишу парсер этого сайта через curl. Он использует куки, отправляет заголовки и разные юзер-агенты, обходит ajax загрузку инфы, парсит с интервалами, и в принципе работает, но пока недостаточно стабильно и только в один поток.
Так вот, если получаю бан(консольно или через браузер), то никакие смены айпи и куков вообще не действуют. На самом сайте ни капчи, ни магик пикселей.
Спасибо
1.22
function tab_expand($text) {
while (strstr($text,"\t")) {
$text = preg_replace_callback('/^([^\t\n])(\t+)/m',
'tab_expand_helper', $text);
}
return $text;
}
function tab_expand_helper($matches) {
$tab_stop = 8;
return $matches[1] .
str_repeat(' ',strlen($matches[2])
$tab_stop - (strlen($matches[1]) % $tab_stop));
}
$spaced = tab_expand($obj->message);
Функция ,как я понял удлиняет части текста разделенные табуляциями до 8 символов "$tab_stop",
Вопрос за что отвечает выделенные выше фрагмент strlen($matches[2]),
http://php.net/manual/ru/function.preg-replace-callback.php
// как обычно: $matches[0] - полное вхождение шаблона
// $matches[1] - вхождение первой подмаски,
// заключенной в круглые скобки и так далее...
если есть строка
aaa\t\tbbb\tccc\t
соответственно получется
$matches[0] - весь шаблон
$matches[1] - aaa затем, bbb...
$matches[2] - получается две табуляции \t\t,
Я не хочу сейчас разбирать сборник рецептов и конкретно эту регулярку, но вот тебе сайт, там вводишь регу, строки для проверки, всю хуйню, и он покажете тебе и фулматч, и что такое матч 1-2-10, и все свои действия объяснит. А так же в нем есть справочник по синтаксису регулярок.
https://regex101.com/
Если вводишь русский текст, не забудь флаг u поставить.
спасибо
>глобальный
виден из всего файла
В него автоматом попадают все данные из POST запроса.
Есть GET запрос, это когда вся хуйня передается в url'e
www.example.com?name=vasya&from=2ch
В этом случае в $_GET будет массив
'name' => 'vasya'
'from' => '2ch'
А есть POST запрос, типа более безопасный итд, не суть. Но его массив формируется по тому же принципу.
о, анон, у меня так полыхает, помоги мне с этим вопросом.
>Из всего файла
То есть, только из того файла где он используется?
>Автоматом попадают все данные из POST запроса
Хмхмхмхм, то есть, $_GET и $_POST это своего рода контейнер, куда АВТОМАТОМ попадают все данные исходя из их метода передачи. То есть, в $_GET попадают данные, переданные методом GET, и такая же хурма с $_POST?
>То есть, только из того файла где он используется?
Ну куда отправишь его, там и используй. Почитай еще, php.net какой-нибудь. По идее он отовсюду виден.
Остальное- да.
Добрый анонче, света и добра тебе в твой дом, ты спас одного безликого анона от пожара в квартире. Ещё пару вопросов хочу задать тебе:
1) $_POST['login'] - это значит, то есть, что в массив $_POST попадают данные из login? login, в данном случае, это атрибут формы ввода логина(атрибут name).
То есть, в это поле с именем login я ввожу имя ВАСЯНХХХ228, и это имя записывается в глобальный массив?
2) Смотри пик. Почему я указал в атрибуте формы метод POST, а данные всё равно видны в URL? То есть, логин, и имя кнопки. GET и POST мы можем указывать только в атрибуте формы, а массивы $_POST и $_GET, правильно?
Прошу прощения за тупость ещё раз, но пока я не разберусь в этом говнище, я не успокоюсь.
1. Перенеси method в <form>
2. Если в форме не указан явно метод, то по умолчанию используется GET
3. Закрой блять тег form
мимошел
блять, точно, лол. Проиграл как орк со своей же невнимательности. На эмоциях просто ебенил, вот и не заметил нихуя. Спасибо!
>>55048
Аноны, я опять бью тревогу! Как мне вывести или посмотреть весь массив $_GET или $_POST(ну это я думаю, вряд ли возможно на странице браузера)? То есть, можно ли как-то посмотреть чё я вообще туда навводил нахуй через эти формы блять ебучие? Это же массив всё-таки, и я хочу узнать его данные!
var_dump($_GET)
Мне кажется, что принцип более-менее определен тут в начале: https://en.wikipedia.org/wiki/Open/closed_principle
> entity can allow its behaviour to be extended without modifying its source code.
Насчет примеров - есть статья http://blog.byndyu.ru/2009/10/blog-post_14.html
Думаю, что тут речь в первую очередь о наследовании, которое позволяет переопределить поведение отдельных методов. При этом оригинальный класс остается неизменным, и нам не нужно менять код, который его использует. Но конечно есть и другие варианты - в статье приведен пример с подменой логгера за счет использования DI и интерфейсов.
Но, конечно, мне этот принцип кажется довольно размытым, и я не уверен, что надо всегда ему следовать. Там в обоих примерах код в итоге усложняется и как бы тут не вышло то, что описано в статье про хлеб: https://habrahabr.ru/post/153225/
Что плохого в том, что мы иногда правим исходный код класса? Если этот класс мало где используется, то ничего страшного. Если же на него завязаны какие-то сторонние системы, то конечно, это может стать проблемой.
В твоем примере с функцией function(Type $type): Returnable - принцип предполагает, что когда тебе надо поменять поведение функции, ты не будешь ее переписывать, а например, напишешь функцию-обертку над ней. Это и будет "расширение без модификации исходного кода".
>>A module will be said to be open if it is still available for extension. For example, it should be possible to add fields to the data structures it contains, or new elements to the set of functions it performs.
Чтобы это понять, обрати внимание на примечание:
> At the time Meyer was writing, adding fields or functions to a library inevitably required changes to any programs depending on that library.
Я думаю, там речь о том, что в языках типа С++, если у тебя есть библиотека (.so или .dll) с классом и ты меняешь его код, то может понадобиться перекомпилировать и те библиотеки и приложения, которые ее используют (хотя я настолько хорошо Си++ не знаю). А расширение функционала с помощью наследования от класса позволяет этого избежать. Но это мое предположение.
> Почему по коду понять проще чем по определениям? Это проблема источника или моя?
Это прицип плохо софрмулирован.
Мне кажется, что принцип более-менее определен тут в начале: https://en.wikipedia.org/wiki/Open/closed_principle
> entity can allow its behaviour to be extended without modifying its source code.
Насчет примеров - есть статья http://blog.byndyu.ru/2009/10/blog-post_14.html
Думаю, что тут речь в первую очередь о наследовании, которое позволяет переопределить поведение отдельных методов. При этом оригинальный класс остается неизменным, и нам не нужно менять код, который его использует. Но конечно есть и другие варианты - в статье приведен пример с подменой логгера за счет использования DI и интерфейсов.
Но, конечно, мне этот принцип кажется довольно размытым, и я не уверен, что надо всегда ему следовать. Там в обоих примерах код в итоге усложняется и как бы тут не вышло то, что описано в статье про хлеб: https://habrahabr.ru/post/153225/
Что плохого в том, что мы иногда правим исходный код класса? Если этот класс мало где используется, то ничего страшного. Если же на него завязаны какие-то сторонние системы, то конечно, это может стать проблемой.
В твоем примере с функцией function(Type $type): Returnable - принцип предполагает, что когда тебе надо поменять поведение функции, ты не будешь ее переписывать, а например, напишешь функцию-обертку над ней. Это и будет "расширение без модификации исходного кода".
>>A module will be said to be open if it is still available for extension. For example, it should be possible to add fields to the data structures it contains, or new elements to the set of functions it performs.
Чтобы это понять, обрати внимание на примечание:
> At the time Meyer was writing, adding fields or functions to a library inevitably required changes to any programs depending on that library.
Я думаю, там речь о том, что в языках типа С++, если у тебя есть библиотека (.so или .dll) с классом и ты меняешь его код, то может понадобиться перекомпилировать и те библиотеки и приложения, которые ее используют (хотя я настолько хорошо Си++ не знаю). А расширение функционала с помощью наследования от класса позволяет этого избежать. Но это мое предположение.
> Почему по коду понять проще чем по определениям? Это проблема источника или моя?
Это прицип плохо софрмулирован.
Что значит "длина пути 000"? Там путь составляется из кусочков фиксированной длины (для правильной сортировки) и если ты используешь 3 цифры на кусочек, то да, возможно не более 1000 ответов на один комментарий. И столько же корневых комментариев.
Хотя, можно сделать длину кусочков разной - для комменатрия верхнего уровня выделить в пути не 3, а больше цифр. Лишь бы структура пути была одинаковой и по ней можно было сортировать комментарии так, чтобы после сортировки они шли в древовидном порядке.
>>52780
Все правильно.
>>52781
self всегда относится к тому классу, внутри которого он написан. То есть в конструкции
class A
{
...
self::something();
...
}
self всегда ссылается на класс A.
При отсутствии наследования static равносилен self.
При наличии наследования static ссылается на самого дальнего потомка.
То есть в коде
class B extends A
{
...
}
$a = new A;
$b = new B;
При вызове вроде B::x(); или $b->y(); static будет указывать на класс B. Даже если это слово написано внутри класса A. А при вызове A::x() или $a->y() тот же static будет ссылаться на A.
Это в PHP назвали "поздним статическим связыванием". "связывание" расшифровывается как "определение, на какой класс ссылается слово". "статическое" - так как self/static указывают на класс, а не объект, и используются для обращения только к статическим полям или методам. "позднее" - так как имя класса определяется не в момент разбора кода (как для self), а позже - только в момент выполнения кода.
Что значит "длина пути 000"? Там путь составляется из кусочков фиксированной длины (для правильной сортировки) и если ты используешь 3 цифры на кусочек, то да, возможно не более 1000 ответов на один комментарий. И столько же корневых комментариев.
Хотя, можно сделать длину кусочков разной - для комменатрия верхнего уровня выделить в пути не 3, а больше цифр. Лишь бы структура пути была одинаковой и по ней можно было сортировать комментарии так, чтобы после сортировки они шли в древовидном порядке.
>>52780
Все правильно.
>>52781
self всегда относится к тому классу, внутри которого он написан. То есть в конструкции
class A
{
...
self::something();
...
}
self всегда ссылается на класс A.
При отсутствии наследования static равносилен self.
При наличии наследования static ссылается на самого дальнего потомка.
То есть в коде
class B extends A
{
...
}
$a = new A;
$b = new B;
При вызове вроде B::x(); или $b->y(); static будет указывать на класс B. Даже если это слово написано внутри класса A. А при вызове A::x() или $a->y() тот же static будет ссылаться на A.
Это в PHP назвали "поздним статическим связыванием". "связывание" расшифровывается как "определение, на какой класс ссылается слово". "статическое" - так как self/static указывают на класс, а не объект, и используются для обращения только к статическим полям или методам. "позднее" - так как имя класса определяется не в момент разбора кода (как для self), а позже - только в момент выполнения кода.
> abstract - перед класссом пишем, если хотим что бы он был лишь основой, от которой будут наследоваться другие классы? Создавать объекты таких классов нельзя.
Абстрактный класс - это класс, который задуман как основа для наследования других классов (не доделанный до конца класс) и объекты которого нельзя создавать. Антоним слова "абстрактный" - конкретный класс.
Абстрактный метод - это метод-заготовка в базовом классе, для которого указан заголовок, но нет тела (реализации). Абстрактные методы обязаны реализовать потомки класса. С помощью абстрактных методов мы указываем, что именно не доделано в базовом классе.
> делаю abstract class Animal, в нем например будут обычные методы, которые будут работать у потомков без переопределения, по типу
> так и абстрактные, которые будут принудительно переписаны как для кошечки, так и для мышечки
> верно с этим?
Да.
> static - это когда тебе нужно без создания объектов прогонять что-то через функции.
Это метод/поле класса, а не объекта. Статическому методу не нужен объект и он не использует $this. Его можно вызывать, даже не имея ни одного объекта.
> Ну и в коде просто используешь когда хочешь в виде
> $readableDate = Helper::convertSqlDateToHuman($sqlDate);
Такие классы из статических методов называются Utility Class.
> Принцип использования всего этого верный у меня в голове?
Более-менее, да.
>>53359
Скрытое поле с названием email. Другие варианты - проверять наличие разных событий, например, нажатий клавиш, прокрутки, движения мыши.
>>53378
Симфони изучи. Или другие языки программирования.
> abstract - перед класссом пишем, если хотим что бы он был лишь основой, от которой будут наследоваться другие классы? Создавать объекты таких классов нельзя.
Абстрактный класс - это класс, который задуман как основа для наследования других классов (не доделанный до конца класс) и объекты которого нельзя создавать. Антоним слова "абстрактный" - конкретный класс.
Абстрактный метод - это метод-заготовка в базовом классе, для которого указан заголовок, но нет тела (реализации). Абстрактные методы обязаны реализовать потомки класса. С помощью абстрактных методов мы указываем, что именно не доделано в базовом классе.
> делаю abstract class Animal, в нем например будут обычные методы, которые будут работать у потомков без переопределения, по типу
> так и абстрактные, которые будут принудительно переписаны как для кошечки, так и для мышечки
> верно с этим?
Да.
> static - это когда тебе нужно без создания объектов прогонять что-то через функции.
Это метод/поле класса, а не объекта. Статическому методу не нужен объект и он не использует $this. Его можно вызывать, даже не имея ни одного объекта.
> Ну и в коде просто используешь когда хочешь в виде
> $readableDate = Helper::convertSqlDateToHuman($sqlDate);
Такие классы из статических методов называются Utility Class.
> Принцип использования всего этого верный у меня в голове?
Более-менее, да.
>>53359
Скрытое поле с названием email. Другие варианты - проверять наличие разных событий, например, нажатий клавиш, прокрутки, движения мыши.
>>53378
Симфони изучи. Или другие языки программирования.
А ты порешай наши задачи из шапки - про список студентов, файлообменник, тестхаб. Там много полезной информации в комментариях и общие принципы, которые там изучаются, пригодятся и в Руби.
>>53677
Можно использовать специально для этого придуманный printf (подробности в мануале):
printf("%dx%d=%d\n", $x, $x, $x * $x);
Или echo "x=", pow($x, 2);
>>53921
По предыдущему опыту. Посмотри, сколько предыдущие задачи заняли по ожиданиям и по факту.
>>54029
А я-то думаю, куда все пропадают и почему никто не делает Тестхаб...
>>54363
Придется подучить CSS. Гугли "css флоаты", "css абсолютное позиционирование", а также все использованные в коде свойства.
>>54470
Чтобы в коде не было мешанины, почитай 2 урока
- https://github.com/codedokode/pasta/blob/master/php/templates.md
- https://github.com/codedokode/pasta/blob/master/arch/mvc.md
>>54625
Нужна очередь фоновых задач вроде gearman. Веб-скрипты не должны долго работать. Ну или аякс, да.
А ты порешай наши задачи из шапки - про список студентов, файлообменник, тестхаб. Там много полезной информации в комментариях и общие принципы, которые там изучаются, пригодятся и в Руби.
>>53677
Можно использовать специально для этого придуманный printf (подробности в мануале):
printf("%dx%d=%d\n", $x, $x, $x * $x);
Или echo "x=", pow($x, 2);
>>53921
По предыдущему опыту. Посмотри, сколько предыдущие задачи заняли по ожиданиям и по факту.
>>54029
А я-то думаю, куда все пропадают и почему никто не делает Тестхаб...
>>54363
Придется подучить CSS. Гугли "css флоаты", "css абсолютное позиционирование", а также все использованные в коде свойства.
>>54470
Чтобы в коде не было мешанины, почитай 2 урока
- https://github.com/codedokode/pasta/blob/master/php/templates.md
- https://github.com/codedokode/pasta/blob/master/arch/mvc.md
>>54625
Нужна очередь фоновых задач вроде gearman. Веб-скрипты не должны долго работать. Ну или аякс, да.
Куча вариантов, крон-скрипт может пересылать данные разработчику, а также у тебя может быть скрипт, к которому стучится удаленный сервер.
>>54981
Вообще, код довольно плохой. Ну например strlen не может корректно посчитать длину utf-8 строки с кирилицей: https://github.com/codedokode/pasta/blob/master/php/strings-utf8.md
Цикл while мне кажется, лишний.
> ($matches[2])
Сюда помещается та часть строки, которая при сопоставлении строки с шаблоном (регуляркой) соответствует вторым круглым скобкам, то есть (\t+). То есть строка с табами.
>strlen не может корректно посчитать длину utf-8
удваиваю, а с mb_strlen потрахаешься с кодировками
пасиб
>self всегда относится к тому классу, внутри которого он написан...
Про self, static я сразу понял.
Смутило это "самое заметное проявление". Если следовать твоему описанию, то тут же нет других проявлений именно в позднем статическом связывании.
Зойчем тогда используют такие обороты речи, только с толку сбивают или переводчики пидоры.
>Скрытое поле с названием email. Другие варианты - проверять наличие разных событий, например, нажатий клавиш, прокрутки, движения мыши.
Проблема в том, что уже в формах есть всякие телефоны и емейлы (считай что обычный говнолендинг с одинаковыми вездесущими формами по оставке своих контактов)
Вхуярил туда уже 2 скрытых инпута, в надежде что бот хоть 1 из них заполнит и нихуя пока. Переназывать реальные поля (которые юзеру показываются) на какой-нибудь мусор, а поля-уловки делать email, phone, name?
>А ты порешай наши задачи из шапки
Уже решаю, задачки норм, но к синтаксису PHP только привыкание идет туго, думаю с практикой привыкну быстрее
>webref.ru
Не рабочий сайт, нет никакой информации о HTML/CSS.
>видео-уроки
С каких видео-уроков лучше всего начать изучение языков разметки? ITVDN? LoftBlog?
https://ideone.com/GPvMRe
Arch linux
На серверах стоит Debian, поэтому на домашний нужно либо его, либо более дружелюбные проитзводные Ubuntu, Mint.
Вкатываюсь в html и столкнулся с вот такой маленькой проблемой. я создал header,который по своей сути уже является блоком и в нем создал еще один блок left-part, которому для удобства задал определенный цвет фона. И когда я пытаюсь сместить блок в блоке,с помощью margin-... , то весь главный блок header смещается тоже. в сторону он не смещается как я понял,потому что я уже задал фиксированную ширину я уже сам догадываюсь,что 100% не указывают, а указывают всегда определенный размер в px. , но там тоже возникли некоторые вопросы,так что пока что для теста указал в 100% ,но когда я пытаюсь сместить голубой блок вниз,то весь header тоже съезжает вниз,пожалуйста объясните почему и как делается правильно.
я знаю,что еще запозиционировать с помощью position: relative; и дваигать блок с помощью top и left, то тогда все нормально, но я читал,что лучше всегда использовать margin, тогда отображения сайта на разных разрешениях будет точнее.
Это называется схлопывание границ - маргин дочернего вылазит через родительский. Если и у дочернего и у родителя есть маргин, то они не складываются, а берется большийесли в общем.
Отменяется - border для родителя/дочернего, padding для родителя/дочернего еще что-то, не помню, гугли
А не будет являться ошибкой позиционирования дочернего блока через relative? Не повлияет ли это на отображение страницы на других разрешениях/устройствах?
Такая хуйня: не знаю пхп и языки программирования вообще (пока что), но умудрился собрать из нескольких скриптов свой, рабочий причём. Его суть в том, что он транслирует музыку в статус во впашке. Собственно, вот код:
<?php
$access_token = 'ацес токен тута';
$audio = 'айди конкретной композиции (порыться в коде элемента (он в стиле 999999_999999';
$statusSet = curl( 'https://api.vk.com/method/status.set?audio='. urlencode( $audio ) .'&access_token='. $access_token );
function curl( $url ) {
$ch = curl_init( $url );
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
curl_setopt( $ch, CURLOPT_SSL_VERIFYHOST, false );
curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, false );
$response = curl_exec( $ch );
curl_close( $ch );
return $response;
}
echo "Статус установлен на 2 минуты!";
?>
Он работал пол года, но потом что-то наебнулось. Толи с апи что-то сделали, то ли хостинг подвёл. Проверьте, ребят, подскажите.
Зойчем тебе релатив? Отодвинь паддингом прост и все, чего фигней маяться.
>ошибкой позиционирования
Во ты тут слова выдумываешь. Не повлияет, хотя все зависит от остальной верстки.
Почитай про схлопывание отступов http://softwaremaniacs.org/blog/2005/09/05/css-layout-flow-margins/
>>55259
Это не равносильно добавлению margin. Изучи внимательно, как работает относ. позиционирование: http://softwaremaniacs.org/blog/2005/08/03/css-layout-positioning/
>нет никакой информации о HTML/CSS.
ебобо? там справочник был хороший, вот его старая версия.
http://htmlbook.ru/
>С каких видео-уроков лучше всего начать изучение языков разметки?
хуй его знает, я смотрел webdesignmaster, а дальше сам.
Аноны, изучаю джаваскрипт. Добрался до массивов и объектов. Придумал себе задачку написать подобие рандомной обзывалки. (учу по джаваскрипт для детей) Есть несколько рандомных фраз, где все элементы массива с маленькой буквы. Порядок задан мной, рандомно выбираются лишь элементы каждого массива. Этот массив превращается в строку и выводится на экран. И в коде делается так, что первая буква первого слова становится большой (типа не мелкобуквенный). По идее. Но реализовать я этого не смог через .toUpperCase и .slice. Уже часик бьюсь, посоветуй решения
Стрелочкой показал на пике, куда хочу всунуть это "поднятие" первой буквы, это только для массива word.
Но ведь написано, что тут изучают
>мы изучаем язык PHP а также JS
Не по адрессу? Ну ладно, тогда я пошёл...
Спасибо, от души, пригласил бы тебя на чашку чая...
Причём, блин, пытался вот точно также, как ты, делать, но проебался со слайсом
Для обработки массивов цикл не костыль, или поищи функцию-аналог php'шной array_walk(), я JS функции так хорошо не помню.
Важно помнить, что когда вы где-то указываете свои персональные данные, или ставите приложение, имеющее доступ к получению данных о телефоне, то неизвестно, где они потом всплывут.
Но я хотел бы обратить внимание еще на один момент. Эти "гении" в качестве uid использовали md5-хеш от номера телефона. Да, md5 труднообратимая функция, но если мы знаем, что исходные данные состоят из 10 цифр, то мы можем перебором проверить все возможные номера телефонов. И потому нет смысла хешировать номера телефонов, паспортов, имена-фамилии, так как их всех ограниченное количество и вскрыть такой хеш можно за несколько секунд. Хеш от номера телефона эквивалентен самому номеру.
оффтоп
Ребята спасайте, ебусь со схемой
Есть викторины, есть игроки, есть вопросы и у вопросов варианты ответов (пока можно не смотреть даже).
Как приебланить ответы игроков
Прикрепляю схему, там вроде всё понятно по замыслу
Спасайте братцы
ответ в себе содержит id, questionId, text в твоем случае.
Когда нужно будет заселектить ответы для конкретного вопроса, то будешь select from answers where question_id = 5 (выбрать все ответы на 5й вопрос) например делать, ну или как-то так.
А, сори, я подумал что речь о вариантах ответов на вопрос, а у тебя уже есть variants - которые я по сути и описал тебе.
У меня просто встречный вопрос - а зачем варианты игроков хранить в этой же базе? У тебя подсчет идет как-то после или что?
ну если прям надо то храни answerId, questionId, playerId, variantId
когда нужно будет узнать какой игрок что ответил на какой вопрос, то будешь у базы спрашивать select from Answer where questionId = 5 and playerId = 3
- узнаешь какой вариант ответа дал игрок с id 3 на вопрос с id 5
Да схема вообще канеш неудачная получилась, %отношение Variant можно пока что откинуть%
Рассматриваем случай, когда вопросы открытые, т.е. игрок сам пишет ответ на вопрос (textAnswer)
тогда таблица answers выглядеть должна как-то так:
answerId, questionId, playerId, answerText тогда делаешь и хранишь.
1) почему отношение question - quiz это многие-ко-многим, вопросы можно использовать в нескольких викторинах?
2) Ты сделал связь игрок - викторина. Но что, если игрок играет в викторину 2 раза? Нужно сделать сущность сеанс игры и привязывать игрока к нему.
3) Надо сделать ответы.
1. Есть удаленный сервер, на котором запущен веб-сервер. На него через вебхуки могут приходить запросы. Например на адрес server.url/test1.php приходит POST-данные.
2. Мне нужно чтобы эти запросы по ssh переправлялись на сервер на локалхосте, чтоб этот POST пришел на локальную машину на условный адрес localhost.url/ test2.php
Полезно прочесть тем, кто хочет понять, как реализуется атомарность коммитов. В многопользовательских СУБД вроде MySQL используется другая схема - MVCC https://phpclub.tech/search/?q=mvcc
Asp.net, node.js или laravel?
в том и дело, что место приличное, а этот даун обащеться, как в своем гей-клубе
Почему? Я слышал другую инфу, мол ларавель самый лучший из этих трех.
Есть 2 варианта:
1) вкладывать в разметке все дочерние комменты внутрь родительского, после чего просто поставить такому блоку padding-left 20px
<div class="comment">
тело родительского комментария
<div class="comment">..дочерние комментарии..</div>
<div class="comment">....</div>
<div class="comment">....</div>
</div>
2) плоская система, но для каждого комментария мы вычисляем и выставляем отступ
<div class="comment" style="padding-left: ...">...</div>
<div class="comment" style="padding-left: ...">...</div>
<div class="comment" style="padding-left: ...">...</div>
<div class="comment" style="padding-left: ...">...</div>
Вторую реализовать попроще, но первая выглядит более семантично.
Также, важно так рассчитать отступы, чтобы комментарии с очень глубокой вложенностью не выползли за экран. Также, не забудь про адаптивность и отображение на маленьких экранах.
Также, ты можешь открыть отладчик в браузере (Ctrl + Shift + I) и изучить, как например сделаны комментарии на Хабре или другом сайте с комментариями.
Есть 2 варианта:
1) вкладывать в разметке все дочерние комменты внутрь родительского, после чего просто поставить такому блоку padding-left 20px
<div class="comment">
тело родительского комментария
<div class="comment">..дочерние комментарии..</div>
<div class="comment">....</div>
<div class="comment">....</div>
</div>
2) плоская система, но для каждого комментария мы вычисляем и выставляем отступ
<div class="comment" style="padding-left: ...">...</div>
<div class="comment" style="padding-left: ...">...</div>
<div class="comment" style="padding-left: ...">...</div>
<div class="comment" style="padding-left: ...">...</div>
Вторую реализовать попроще, но первая выглядит более семантично.
Также, важно так рассчитать отступы, чтобы комментарии с очень глубокой вложенностью не выползли за экран. Также, не забудь про адаптивность и отображение на маленьких экранах.
Также, ты можешь открыть отладчик в браузере (Ctrl + Shift + I) и изучить, как например сделаны комментарии на Хабре или другом сайте с комментариями.
Спасибо!
>сто приличное, а этот даун
>мелкобуквенное безграмотное биотопливо продолжает рваться, из-за того, что кто-то на дваче написал что-то не так как он в своем маня-мирке себе представлял
Успокой меня и скажи, что тебе просто 16 лет.
Так же например в БД есть слово Doodo и он его ищет только если я ввoжу do, если doo, то нихуя. Doodo соответственно тоже не видит.
Так я тебе и писал, зайчик.
Должно же работать? Покажи, как выводишь результаты.
Где оно нужно? она полностью решается без JS, или я что-то не так понял? Там даже CSS сильно знать не требуется - все делается на стандартных классах бутстрапа. HTML, конечно, немного знать надо.
В задаче не было обязательного условия использовать бутстрап, а очень хотелось поскорее попробовать свои силы именно собственно в кодинге, так что я по-быстрому напейсал свою таблицу стилей попроще (сделал фон поприятнее, навигационную панельку, кнопочки посимпатичнее и переключатель страниц стилизовал, благо CSS как раз знаю достаточно неплохо, бо не пожлобился на платные уроки у htmlacademy). Думаю, как только окончательно доведу до ума двигло "сайта", натянуть на него другие стили не очень уж и большая проблема. JS я использовал для того, чтобы при сортировке по кликам на заголовках рядом с ними появлялись стрелочки вверх-вниз (в зависимости от порядка сортировки) и модификации ссылок на переключателе страниц. Например, при первой загрузке таблицы без сортировки ссылка на запрос второй страницы таблички у меня имеет вид main.php?from=10 (я их по 10 вывожу). А при клике на заголовок для сортировки ссылка на вторую страничку приобретала вид вроде main.php?from=10&sort=grade&desc=true, чтобы порядок сортировки не прерывался при переключении страниц. Я это делал именно жабаскриптом. Защиту от произвольных данных в адресной строке тоже предусмотрел, если вбить несуществующий параметр, просто ничего не произойдёт. Может быть это дико кривой костыль, но работает нормально.
зы. Я понимаю, что это можно было бы сделать и на php, особенно модификацию ссылок внизу. Но, например, добавлять по клику на заголовке столбца стрелочку порядка сортировки рядом с ним, на JS объективно удобнее, разве нет?
Я не очень понял, что ты сделал. В моем понимании, заголовки таблицы - это ссылки вида
list.php?sort=+name
list.php?sort=-name
list.php?sort=+points
list.php?sort=-points
И при клике по ним загружается новая страница. И я не очень понимаю, как тут яваскрипт помогает пририсовывать стрелочки. Ведь их проще вставить в шаблон в момент генерации страницы на сервере.
То же самое касается пагинации - модификация ссылок яваскриптом выглядит как костыль. Тогда логичнее уж их целиком генерировать с нуля яваскриптом, а не дописывать что-то к существующим ссылкам.
Или ты сделал сортировку данных при клике яваскриптом внутри страницы? Это вряд ли будет корректно работать, так как при смене вида сортировки данные на странице меняются.
То есть я плохо понимаю, что именно ты сделал.
> Но, например, добавлять по клику на заголовке столбца стрелочку порядка сортировки рядом с ним, на JS объективно удобнее,
Так страница после этого (клика по заголовку) сразу перезагружается и твоя стрелочка пропадает. Или нет?
Он про то дерьмо, когда у тебя таблица без пагинации выведена и ты сортируешь её прямо в браузере с помощью js сделав заголовки кликабельными. Вангую что на собеседовании за такое сразу отправят в лес.
С другой стороны я бы посмотрел на реализацию когда у тебя полностью выведена вся таблица на страницу, но при этом разбита на удобно читаемые блоки и пагинация + полная сортировка реализована на JS что бы не перезагружать каждый раз страницу при попытках посортировать что-то или бегая по страничкам.
>>57075
Не совсем. Страница загружается с сервера новая и табличку сортирует по нужным значениям именно сервер, а не скрипт. Скрипт выдирает из адресной строки параметры sort и desc, (я напейсал соответствующую функцию), ищет среди ссылок в заголовке с параметром name, совпадающим с параметром sort и в зависимости от значения параметра desc проставляет ей класс "asc" или "desc", которые в css через псевдокласс after приписывают после ссылки соответствующую стрелочку. Порядок сортировки desc скрипт тоже меняет в свойстве href заголовка напрямую, в зависимости от его предыдущего значения, которое он опять-таки выдирает из адресной строки. Если щелкаешь по другому заголовку, происходит то же самое, только предварительно этот же скрипт убирает стрелочку с предыдущего и выставляет ему desc в свойстве href обратно в false. Так что после загрузки стрелочки не пропадают, бо информация о том, где их ставить скрипт тащит из адресной строки.
У меня проблема в том, что в шаблоне я заголовки таблицы изначально жестко прописал и они загружаются as is и теперь приходится так изъёбываться. Да и модификация переключателя страниц реально бредовая получилось, я только теперь это понял. Он и так генерируется на сервере, и модифицировать его как-либо нужно было там. Просто делал это задание именно сейчас, почти всю ночь, у нас уже 6 час утра и голова не варила совершенно. Алсо, я всю неделю до этого почти 2 недели хуярил learn.javascript.ru, прошел его почти полностью и решил большую часть задач. Соответственно, жабаскриптом у меня забита голова и меня на нём явно подклинило. Сам знаю, что черезжопно все получилось, так что теперь займусь переделкой.
В любом случае, прошу не судить строго, мне еще до этих ваших собеседований как до Китая раком. Это из-за сайта Кантора всё в башке смешалось, наверное.
Не надо так категорично. Никто не говорит, что сортировка через JS - плохо. В Википедии любые таблицы сортируются через JS и это прекрасно работает - но там они выводятся не постранично, а целиком.
Не стоит говорить, что "X - плохо". Лучше говорить, вариант X имеет такие достоинства/недостатки, а Y - такие и в данной ситуации лучше подходит X.
Я так-то не против сортировки через JS, но хорошо бы сохранить при этом все удоства - возможность скопировать и переслать ссылку, например.
Например, как в вк.
Я просто не могу разобраться какую БД создавать, с какими значениями.
И как потом грамотно извлечь эти значения, что бы пользователи видели сообщения собеседника, а не все сообщения которые в БД.
Делаешь например таблицу messages:
id - id сообщения
fromUserId - id юзера который отправил
toUserId - кому послали сообщение
readen - было ли прочитано
timestamp - время отправки
Ну вот как бы простейший вариант. когда надо подгрузить беседу, то просто:
SELECT from messages where fromUserId = 4 and toUserId = 6 ORDER BY timestamp.
Выплюнет тебе все сообщения между юзерами с id 4 и 6 например.
Во вьюхе опять же простейшим вариантом можешь выводить так как тут челику советовали: >>54654
Только например свои сообщения юзер будет видеть справа, а сообщения собеседника слева, провеку изменишь банально не на чет/нечет, а свойId/собеседникаId
Очевидно, что мой $result до этого и этот совпали случайно.
Отклеился вывод массивов.
Спасибо, буду пробовать. Я сам что-то типа такого пытался сделать, но получилось херово.
И вот тебе задания на проверку:
Строки:
http://codepad.org/Kt0oetj8
http://sandbox.onlinephpfunctions.com/code/252d024b81b93ce460c2319bfcb12091fd091a28
Функции:
http://sandbox.onlinephpfunctions.com/code/5e6756da07a7d8c2e49b3cfba688ea227af8a46f
Спасибо.
На, почитай последнюю кулстори, как простые сайтостроители, ввиду своей некомпетентности, работы спустярукава, и не инженерного подхода к разработке (когда все как попало, без какого-либо цикла, разграничения прав, деплоя), вот так вот на ровном месте доставили убытки в 1 миллион рублей за день своему клиенту.
https://habrahabr.ru/post/351396/
А все почему? Потому что веб-дев унижают? Нет, его унижают из-за таких вот горе разработчиков, а не разработчики такие, потому что это веб-дев. Те, что с головой, и действительно специалисты, такой хуйни не творят.
Дело не в сфере,а в человеке.
Но ты почему-то стремишься за ярлычками, а значит глупец априори.
https://ideone.com/UgRjBW
Да ты бы и собаке
А что плохо у тебя получалось? Я тут зашел перечитал своё сообщение и подумал, что довольно слабое решение получается.
Во первых
>SELECT from messages where fromUserId = 4 and toUserId = 6 ORDER BY timestamp.
даст сообщения только от 1 юзера к другому, а полноценную беседу будет подсосать нужно как-то так
SELECT from messages where (fromUserId = 4 and toUserId = 6) OR (fromUserId = 6 and toUserId = 4) ORDER BY timestamp.
- то есть все сообщения от 4 к 6 или от 6 к 4 нам подходят (нужны для нормального отображения диалога)
Во вторых опять же много условий и я бы подумал, что по мере заполнения таблицы всё начнет дико тормозить со временем. Представь у тебя в одной таблице милион сообщений уже, и нужно вот так sql-ю бегать по всем и смотреть что бы 3 условия сочетались.
Поэтому можно попробовать каждой беседе назначить свой id
Например можно изобразить что-то типа столбца chatId - и в него складывать некую хитрую пару вида юзерСМеньшимИд_юзерСБольшимИД.
На первый взгляд наверное выглядит костыльно и вообще дублированием информации, но по факту такое простое решение во первых тебе наверное много мозгоебли сбережет.
Поясняю на примере.
Допустим наши юзеры перекинулись парой сообщений и в табличку с сообщениями у тебя лягут следующие строки:
(еще забыл в таблицу сам текст сообщения записывать)
id______chatId_______fromUserId______toUserId_____text___________readen_________timestamp
1_______4_6_________4______________6___________'ку'____________1____________1521371398
2_______4_6_________6______________4___________'суп'___________1____________1521371428
3_______4_6_________6______________4___________'как_дела?'_____1____________1521371488
4_______4_6_________4______________6___________'норм'__________0____________1521371573
5_______4_6_________4______________6___________'а_у_тебя?'_____0____________1521371592
Заметь что и когда юзер-4 шлет сообщения, то chatId будет выглядеть как 4-6, и когда юзер-6 шлет сообщения, то такое же chatId
далее ты этот столбец индексируешь, и когда будешь делать поисковые запросы, то будешь делать простой селект всех сообщений из этой таблицы по этому столбцу.
Делаешь простую функцию которая будет тебе генерировать всегда одинаковый chatId для двух юзеров.
$chatId = returnChatId(4,6); //в $chatId ляжет строго 4_6
$chatId = returnChatId(6,4); //в $chatId ляжет строго 4_6
и подставляешь эти chatId в селект
Допустим юзер-4 хочет зайти в диалог с юзер-6 - в базу изи летит запрос
Select from messages where chatId = $chatId ORDER BY timestamp;
И всё у тебя будет охуенно и быстро летать имхо.
Ну и что касается столбца readen - то это как бы косметика, но повышающая не слабо комфорт юзеров, поэтому в 2к18 считаю обязаловом. Во первых во вьюхе можно отдельный css для таких сообщений сделать, что бы выделялись, а во вторых тот человек который отправил сообщения, будет знать дошли ли они и прочитаны ли.
Ну и когда скажем адресат подучает новые сообщения, ты уже пхп скриптом пробегаешь по беседе с конца и смотришь прочитаны ли последние сообщения, если не были прочитаны адресатом (тем кто сейчас зашел в беседу и прочитал их), то в базу шлешь пару апдейтов, что бы по id быстренько каждое проставить прочитанным.
Надеюсь доступно и понятно объяснил, и надеюсь меня опытные работяги если что поправят и пояснят где есть оишбки.
Сам 1 раз нечто подобное лишь писал и то давно и на старте работы, ща уже и не помню как там что было.
А что плохо у тебя получалось? Я тут зашел перечитал своё сообщение и подумал, что довольно слабое решение получается.
Во первых
>SELECT from messages where fromUserId = 4 and toUserId = 6 ORDER BY timestamp.
даст сообщения только от 1 юзера к другому, а полноценную беседу будет подсосать нужно как-то так
SELECT from messages where (fromUserId = 4 and toUserId = 6) OR (fromUserId = 6 and toUserId = 4) ORDER BY timestamp.
- то есть все сообщения от 4 к 6 или от 6 к 4 нам подходят (нужны для нормального отображения диалога)
Во вторых опять же много условий и я бы подумал, что по мере заполнения таблицы всё начнет дико тормозить со временем. Представь у тебя в одной таблице милион сообщений уже, и нужно вот так sql-ю бегать по всем и смотреть что бы 3 условия сочетались.
Поэтому можно попробовать каждой беседе назначить свой id
Например можно изобразить что-то типа столбца chatId - и в него складывать некую хитрую пару вида юзерСМеньшимИд_юзерСБольшимИД.
На первый взгляд наверное выглядит костыльно и вообще дублированием информации, но по факту такое простое решение во первых тебе наверное много мозгоебли сбережет.
Поясняю на примере.
Допустим наши юзеры перекинулись парой сообщений и в табличку с сообщениями у тебя лягут следующие строки:
(еще забыл в таблицу сам текст сообщения записывать)
id______chatId_______fromUserId______toUserId_____text___________readen_________timestamp
1_______4_6_________4______________6___________'ку'____________1____________1521371398
2_______4_6_________6______________4___________'суп'___________1____________1521371428
3_______4_6_________6______________4___________'как_дела?'_____1____________1521371488
4_______4_6_________4______________6___________'норм'__________0____________1521371573
5_______4_6_________4______________6___________'а_у_тебя?'_____0____________1521371592
Заметь что и когда юзер-4 шлет сообщения, то chatId будет выглядеть как 4-6, и когда юзер-6 шлет сообщения, то такое же chatId
далее ты этот столбец индексируешь, и когда будешь делать поисковые запросы, то будешь делать простой селект всех сообщений из этой таблицы по этому столбцу.
Делаешь простую функцию которая будет тебе генерировать всегда одинаковый chatId для двух юзеров.
$chatId = returnChatId(4,6); //в $chatId ляжет строго 4_6
$chatId = returnChatId(6,4); //в $chatId ляжет строго 4_6
и подставляешь эти chatId в селект
Допустим юзер-4 хочет зайти в диалог с юзер-6 - в базу изи летит запрос
Select from messages where chatId = $chatId ORDER BY timestamp;
И всё у тебя будет охуенно и быстро летать имхо.
Ну и что касается столбца readen - то это как бы косметика, но повышающая не слабо комфорт юзеров, поэтому в 2к18 считаю обязаловом. Во первых во вьюхе можно отдельный css для таких сообщений сделать, что бы выделялись, а во вторых тот человек который отправил сообщения, будет знать дошли ли они и прочитаны ли.
Ну и когда скажем адресат подучает новые сообщения, ты уже пхп скриптом пробегаешь по беседе с конца и смотришь прочитаны ли последние сообщения, если не были прочитаны адресатом (тем кто сейчас зашел в беседу и прочитал их), то в базу шлешь пару апдейтов, что бы по id быстренько каждое проставить прочитанным.
Надеюсь доступно и понятно объяснил, и надеюсь меня опытные работяги если что поправят и пояснят где есть оишбки.
Сам 1 раз нечто подобное лишь писал и то давно и на старте работы, ща уже и не помню как там что было.
chatId нормальная тема, жаль сам не додумался. А так уже сделал сообщения эти, все работает. Вот только одна проблема, как отображать новые значения в таблице, без обновления странницы ?
Сделал chatId
>Как отображать новые значения в таблице, без обновления странницы?
Некст левел уже, плохо помню точно как мы делали. Для начала ты на чем вообще пишешь? У тебя просто лапша или опп/мвц, фремворки?
Простейшим дырявым и незащищенным решением мне сейчас видится такое:
У тебя когда ты грузишь вьюху, вообще нет никаких запросов в базу и селектов - тупо отдаешь html-заготовочку.
Далее в этой заготовочке у тебя лежит js, который сразу начинает работать и по аяксу долбится в нужный контроллер, от которого получает всю беседу в виде json-массива, и после этого уже её отрисовывает во вьюхе.
А потом он периодически спрашивает опять же твой контроллер о том, а сколько там в такой-то chatId-беседе сообщений всего?
Посылаешь например контроллеру chatID - собственно ид беседы по которой он спросит базу и messages.length - количество сообщений в текущей беседе. В ответ либо получаешь что всё так и осталось по прежнему, либо получаешь обновленную беседу целиком, или недостающие сообщения - тут уже как сам решишь действовать.
Ну и яваскриптом дорисовываешь новый html с новыми сообщениями под это дело.
Тут дохуя на самом деле работы и подводных камней как по мне, просто ебануться можно ради такой казалось бы простой штуки как: "а давайте сделаем динамический чатик как ВэКа, че там сложна чтоле)))"
Во первых сейчас не вспомню как защищать всё это дело, что бы хитрозадые челики изучив твой js не смогли слать тебе запросы посмотреть чужие беседы, ну точнее пусть шлют, но в ответ получают ровно нихуя. Далее еще какие-то проблемы с потерянными сообщениями были - но это наверное от недостатка знаний в js'e (они и сейчас околонулевые). Ну и что-то еще
ох блин, с JS не хочу связывать, сам его не знаю. Чтож. Видимо пока, что никак мне это не сделать.
это я знаю, но хотелось бы не руками сидеть и убирать это говно, а одной командой это сделать. И можно ли вообще сделать так, чтобы логин вообще там не сохранялся
Пыха же на сервере работает, как она может изменять данные в нашем браузере?
Как вариант тестировать формы в браузерном режиме инкогнито.
Постоянно использовать относительные пути вида __DIR__ . 'relative_path'?
атрибут autocomplete поля поставь в off
type="text" конечно же.
И еще хром имеет блядскую привычку если рядом находится текстовое поле и парольное - он вставляет логин-пасс даже если autocomplete="off". Чтобы он этого не делал, нужно полю ввода пароля поставить атрибут autocomplete="new-password", а не off
Ты ещё посмотри на то, какие этот пидор цены заламывает. Лендинг за 60 тыщ. Я ебал :D
В этой классификации SPA проходит как лендинг?
Да, обычно всегда используют require_once . __DIR__ . '/path/'
Вот пример в Laravel: https://github.com/laravel/laravel/blob/master/public/index.php#L24+L38
>>55160
https://htmlacademy.ru/
>>58517
Может в перезвоним-тред с этим? Что ещё ты хочешь от веб-студии.
>>58561
Нет, это обычные требования на джуна нормального, там же написано "умеешь делать джойн или даже подзапрос". Ты если в этом треде сделаешь пару задач на бек и фронт из шапки, то будешь знать больше, чем написано в той вакансии.
ОП это ты? Я уже узнаю тебя по почерку.
У меня глупенький вопрос, но все же спрошу.
Стоит ли параллельно ламповому учебнику, смотреть какой-либо курс? Например курсы PHP при МГТУ им. Баумана.
Я не оп, но насколько я знаю, при бауманке работает центр "Специалист", который и ебашит платные видеогайды. Так вот гайд Питона от них - это просто запредельный пиздец. Если пых тоже читает Перлин, то явно не стОит. Но если не он, то тогда уже к ОПу вопрос, насколько эти курсы хороши.
Спасибо за мнение, анон.
Понаскачивал разных курсов, думаю на какой стул сесть помимо учебника:
1. [Profit] А. Степанцев 1-3 уровень
2. Специалист пхп7 от бауманки, преподает некий Попов (везде его хвалят, прослушал первый урок % охуительных историй зашкаливает)
3. [ntschool] Стань PHP специалистом
4. [loftschool] Комплексное обучение разработке на PHP (думаю на нем остановиться, у автора годный канал на ютубе https://www.youtube.com/user/loftblog)
Могу дать ссылки на скачивание курсов, если кому нужно.
Я за профит. Там все как то приличней.
Я понимаю, что разработчику он мастхев нужен, но насколько знаю бэк-енд не настолько динамичная сфера, в плане внедрения новых технологий и все нужные материалы уже переведены? Или нет?
На клиенте можешь генерировать, чтобы показать клиенту, при загрузке, лишний раз не гоняя данные на сервер. Но при получении файла на сервере, генерируй превьюху там. Потому что если ты будешь получать превьюху от клиента, ничто не помешает ему подсунуть не настоящую превьюху.
Или нет. Освоить и найти то получится, но в потолочек все равно упрешься. Проще поднажать на английский, чем пробовать ссать против этого ветра.
Тут либо английский, либо PHP - 1С Bitrix
Английский язык в прогерских учебниках сильно упрощён по сравнению с публицистическим и разговорным. Меньше слов, меньше оборотов речи. Школьного курса для старта более чем достаточно. Недельку посидишь, копипастя непонятные обороты в гуглопереводчик, а дальше знакомых фраз будет больше и в переводчик заглядывать уже почти не будешь, по себе знаю.
SELECT * FROM messages WHERE chatid LIKE '1_2' (и что бы он не SELECTтил одинаковые значения chatid)
я объебался чутка
SELECT * FROM messages WHERE chatid LIKE '%2%' (и что бы он не SELECTтил одинаковые значения chatid)
Вот так более верно, но суть не в этом.
Да, подходит. Но надо, что бы выводил всю строку, а не только столбец
Реально ли двигаться по шапке только со смартфона? На анальной работке на рабочем компе нихуя нельзя, а делать нехуй.
Это что -то с апачем не то? Как пофиксить?
ctrl + f5 - перезагрузка станицы с очисткой кэша
Ты хочешь наверное заселектить по последнему сообщению в каждой беседе? Что бы их в общую диалоговую вьюху выводить?
Спроси в соседнем mysql треде, там наверное быстро ответят, вангую что тебе нужно использовать group_by в запросе, но моих знаний не хватает сейчас на помощь :(
Тебе надо в html, там где ты подгружаешь css прописывать новую версию при изменении css
<link rel="stylesheet" href="style.css?v=1.1">
тогда браузер увидит что нужно подгружать теперь новую версию, и та что лежит у него в кеше уже не актуальна - и всё будет ок
LIMIT 1
Но они же не уникальны.
Да так надо после каждого закрытия браузера делать или перезагрузки системы. У других такой хуйни не происходит...
Ну тебя уже в принципе ткнули. Как ты хочешь селектить уникально chatId в подобной таблице:
1_______4_6_________4______________6___________'ку'____________1____________1521371398
2_______4_6_________6______________4___________'суп'___________1____________1521371428
3_______4_6_________6______________4___________'как_дела?'_____1____________1521371488
4_______4_6_________4______________6___________'норм'__________0____________1521371573
5_______4_6_________4______________6___________'а_у_тебя?'_____0____________1521371592
6_______2_3_________2______________3___________'hello'__________0____________1521371573
7_______2_3_________3______________2___________'sup nigga'______0____________1521371592
Какие ответы ты желаешь получить?
Разве тот-же Руби на рельсах не быстрее ПхП ? Да и кодить легче, Элегантный код вся хуйня
АНАНАСЫ, решил вкатиться и начать с верстки, но уже на простом хэдере меня начало тошнить от ксс. Если я буду только бустрапом пользоваться это нормально или считается зашкваром? Работодатели не обоссут? И подкиньте, пожалуйста, материалов по техникам верстки. Именно техникам, а не самой верстке.
Если ты делаешь админку или чисто приложение с какой-нибудь статистикой или прочим, то всё ок. ебашь бутстрап хоть везде, если же ты пытаешься что-то продать или делаешь сайт для клиента, то ясен хер на фасад нельзя бутстрап вываливать.
Галочку убрать и потом опять включить? Не робит чет
Все, заработало
Такой же мастхев как и вордпрес или джумла для пых-разработчика. Т.е. для человека не умеющего в верстку или в проекте, где внешний вид не настолько важен (энтерпрайз какой-нибудь), то мастхев, хотя кроме бутстрапа есть еще туча всякой другой шушеры.
Я лично для админок всяких юзаю материал дизайн от гугла. Намного приятней осточертевшего до коликов бутстрапа. Там правда нет внятных лэйаутов и гриды чуть-чуть странные, но я не представляю каким овощем надо быть, чтобы за один вечер не разобраться с флексбоксом или каким-нибудь инлайн блоком.
Он мастхэв для бэкэндеров, которые должны уметь изобразить админку вместо дефолтной серой вырвиглазной html'e-хуйни без изучения css+js в довесок. Там просто набор красиво оформленных заготовок (кнопочки, формочки, прогресс бары и т.д.)
>>59288
>Такой же мастхев как и вордпрес или джумла для пых-разработчика.
Максимум высер, что я бы тебе просто уебал за то что несешь с умным видом хуйню.
Даже если у тебя там тупо селект всей таблицы а потом с помощью пхп выбор последних сообщений каждой беседы, то ниче такого в принципе для начала. Главное пометить в коде что требуется рефакторинг и пиздовать дальше делать.
Ну вообще, мне нужно было, что бы выбиралось уникальные значения chatid. Это получилось сделать. Но проблема, в том, что остальные строчки не стелились.
Я плохо работаю с массивами.
Не селектелись*
Я думаю так сделать:
Отправлять sql запрос "SELECT id,chatid FROM messages ORDER BY date DESC".
По средствам PHP и массива найти уникальные значения chatid.
И уже будет известно сколько диалогов у пользователя, последнее сообщение в переписке.
Это реально сделать с помощью массива ? Я так понимаю еще и цикл нужно делать?
SELECT CHATID, COUNT(ID), FROM MAKER GROUP BY CHATID - вернет два столбца, в первомбудет УНИКАЛЬНЫЙ chatID, во втором - количество сообщений, которые с ним связаны.
Анон, может тебе сначала sql-tutorial.ru покурить? Отличный интерактивный учебник по SQL с песочницей и огромным количеством задач разного уровня сложности.
пасибо
>
Отправлять sql запрос "SELECT id,chatid FROM messages ORDER BY date DESC"
>id,chatid
нахуя толоько эти 2 столбца? Что бы потом по id еще раз селекты ебашить дополнительными запросами?
селекти все столбцы по chatid, что бы получить все сообщения которые написаны нашему юзеру или нашим юзером как тут делал >>58994
дальше получаешь условный массив всех сообщений юзеров, из которых с помощю пхп потом выхуяриваешь последнее сообщение в каждой беседе вот таким вот простейшим способом.
https://ideone.com/PUeu3x
Вот накидал тебе в упрощенном виде. Если ты не будешь хуйней страдать, то ты можешь сразу всё что хочешь за 1 селект во вьюху выводить.
Если бы вы писали что-то вроде семантического рабочего стола\семантической оболочки ОС, то какую бы СУБД выбрали в качестве хранилища метаинформации? Считай это все семантические связи между типа объектов, аналитическая информация, статистика, и прочее. НО. Это десктоп. То есть объемы, а самое главное, нагрузка не серверная - клиенты лишь сами сервисы\демоны одного пользователя\может пары девайсов, с учетом шаринга информации между ними. При этом есть потребность хранить\отслеживать отношения (следовательно можно задуматься о рдбмс), в тоже время данные - это в сущности объекты ссылающиеся друг на друга и храняшие друг друга (можно задуматься о графовых бд), есть так же потребность в атомарности записей, а потом приходится сомневать насчет носкюл-решений, ведь придется городить ее поверх.
Есть кому что сказать?
так это мухосрань, там в принципе наверное для джуна такие запралаты нормальны. плюс стек не битрикс
я тот самый овощь. захотел сделать хэдер. сделал div с display: flex, в нем список ul и в каждом элементе li по ссылке a. захотел растянуть ссылку на всю высоту предка (div), но при этом чтобы текст был по центру. ушло дохуя времени, но решения лучше чем поставить padding сверху и снизу в пикселях не нашел. а высота хэдера у меня в процентах, получается, что на другом разрешении ссылка будет уже не по центру.
в общем, верстануть что-нибудь легко, но сделать так, чтобы это выглядело одинаково на всех разрешениях Я НЕ ЗНАЮ КАК, ПОМОГИТЕ ПОЖАЛУЙСТА, МЕНЯ УЖЕ НАХУЙ ТОШНИТ ОТ ВСЕГО ЭТОГО.
ну и еще, тот самый хэдер, у которого высота в процентах не меняет свои размеры при зуме (а ссылки меняют).
>autocomplete="off"
Я тот самый анон, что задавал этот вопрос. Спасибо за помощь, друг! Добра тебе с:
Пиздец конечно вопрос. Они убирают символы, с помощью которых можно передать инъекцию
не работает
есть один хохол который делает подробно простой проект на пыхе вроде сайта регистрации, но он азов не поясняет вообще
Типа как тут? https://htmlacademy.ru/courses/55/run/7
Жабаскриптом же. Только не совсем понятно как этот пагинатор работает. Т.е., если даже текущее значение 99, то между ним и 100 все равно должен быть спан с многоточием или он переносится левее, если между текущим и конечным больше нет промежуточных элементов?
У тебя ж есть какой-то шаблон, собирающий страницу, которая отдается пользователю. Вот и добавь туда пару условий.
Есть 2 формы, у обеих метод POST. Обе ведут на одну и ту же страницу edit.php. Эта страница должна обрабатывать поля с обеих форм, но, мне нужно, чтобы при переходе с первой формы edit.php выполнялся одним способ, а со второй, другим. Методом GET я могу это сделать просто подставляя в action форм что-то типа "edit.php?type=1" и "edit.php?type=2" соответственно. А как это сделать при использовании POST?
public $a = [];
или
public $a = '';
А вот:
public $a = new A();
уже нельзя никак?
Только через конструктор получается надо туда засовывать в эту $a уже?
Попробовал изобразить что изначально спросил и такой фиал:
https://ideone.com/Lm6Yur
Попробовал через конструктор складывать - тоже самое:
https://ideone.com/lusCNo
В чем ошибки или где дыра в моем понимании?
>>59901
в формах заведи как вариант
по аналогии с твоим гет-запросом в первой:
<input type="hidden" name="type" value="1">
а во второй:
<input type="hidden" name="type" value="2">
в пхп коде просто пишешь:
https://ideone.com/CpeVcz
public $a = [];
или
public $a = '';
А вот:
public $a = new A();
уже нельзя никак?
Только через конструктор получается надо туда засовывать в эту $a уже?
Попробовал изобразить что изначально спросил и такой фиал:
https://ideone.com/Lm6Yur
Попробовал через конструктор складывать - тоже самое:
https://ideone.com/lusCNo
В чем ошибки или где дыра в моем понимании?
>>59901
в формах заведи как вариант
по аналогии с твоим гет-запросом в первой:
<input type="hidden" name="type" value="1">
а во второй:
<input type="hidden" name="type" value="2">
в пхп коде просто пишешь:
https://ideone.com/CpeVcz
Где блядь там макакинг? Максимально просто и изящьно всё. Или ты думаешь есть другая блядь скрытая магия в таких задачах, которая доступна опытным челикам?
Делай как сказали и не беси меня сука, то что у тебя вообще существует некий edit.php - уже само по себе макакинг, даже не спрашивай почему, вырастешь - поймешь.
Оцените, пожалуйста, мое решение задачи из учебника ОПа (тема "Условия и игра в кубики")
https://ideone.com/VAsuaE
Оформление верное?
Особенно интересует, верное ли оформление условия в этой строке:
> } elseif (($humanAll == $compAll) || ($humanDice1 == $humanDice2 && $compDice1 == $compDice2)) {
Надо ли было $humanDice1 == $humanDice2 и $compDice1 == $compDice2 заключать в еще одни дополнительные круглые скобки? при том, что и так все работает? На сайте у ОПа в примере этой задачи (который надо дописать) заключены.
Еще вопрос, зачем в примере этой задачи на сайте ОПа в 12 строке
> echo "У анона выпало {$anonDice1} и {$anonDice2}...
переменные спрятаны в фигурные скобки?
>Надо ли было $humanDice1 == $humanDice2 и $compDice1 == $compDice2 заключать в еще одни дополнительные круглые скобки?
Можно и не заключать. И - это логическое умножение, оно и так выполнится раньше, чем логическое сложение ИЛИ. Лишние скобочки просто нагляднее показывают порядок, я и сам их ставлю.
>Еще вопрос, зачем в примере этой задачи на сайте ОПа в 12 строке переменные спрятаны в фигурные скобки?
Сложный (фигурный) синтаксис
Он называется сложным не потому, что труден в понимании, а потому что позволяет использовать сложные выражения.
Любая скалярная переменная, элемент массива или свойство объекта, отображаемое в строку, может быть представлена в строке этим синтаксисом. Просто запишите выражение так же, как и вне строки, а затем заключите его в { и } . Поскольку { не может быть экранирован, этот синтаксис будет распознаваться только когда $ следует непосредственно за {. Используйте {\$, чтобы напечатать {$.
http://php.net/manual/ru/language.types.string.php
Если они это позволяют, и ты разбираешься, и файлы получаются удобночитаемые и небольшие, то почему бы и нет? jQuery это тоже фреймворк. Согласись, проще использовать его, чем городить самому (уже сделано до тебя, компактнее код, в едином узнаваемом стиле и т.п.). плюс, разбираясь в фреймворках ты перед стартом можешь выбрать тот, который позволит твой "не очень интерактивный" сайт превратить легко и быстро в пупер-интерактивный.
http://softwaremaniacs.org/blog/category/primer/
http://softwaremaniacs.org/blog/2005/06/08/juice-and-flies/
понравилась. Просьба ОП-у адаптировать в учебник.
Ну и я подумал, кто учит Лару или другой какой-то фреймворк и хочет попрактиковаться с реальными задачами, можете написать в телеграм @ruslan_peresy. Может совместно что-нибудь замутим))))
Правильно понял, что фигурные скобки нужно использовать тогда, когда в строку нужно вставить не только просто значение переменной, но и сразу произвести с этой переменной какую-то операцию в этой строке? Или еще что-то?
Спасибо.
Только еще вопрос, чтобы точно разобраться.
Без заключения в эти круглые скобки не может произойти так, что указанное условие будет выполнено таким образом, что $humanDice2 && $compDice1 равно $humanDice1 равно $compDice2?
Я правильно понял, что && имеет приоритет над || ? А == приоритетнее, чем &&?
Только начал изучение, сразу хочу понимать, сори за нубский вопрос.
>В каких случаях будет необходимо написать маркер ?> в конце скрипта?
когда php код вставляется в html, а когда файл полностью на php то маркер не нужон
В этой задачке >exit(); нужен чтобы досрочно остановить выполнение скрипта при выпадении одинаковых чисел.
Но у тебя же будет ошибка, если суммы у компа и у анона будут одинаковые (типа (4,3) и (3,4))
Это не имеет особого значения, вероятность что числа так выпадут минимальна. Не стоит так заморачиваться на простых задачках, главное чтобы работало.
Вот такое будет
Лул, как не имеет то? Мне кажется это уровня, вытереть жопу, а потом обнаружить чиркаш на трусах, главное жопу вытер.
Время не ждет, пока ты будешь до победного блеска натирать жопу, другие уже перейдут к изучению ООП (у некоторых из них будет чиркаш на трусах).
А зеленый скрипт тут у тебя не будет считаться как другой, независимый от первого?
Потому что если да, то >exit(); не повлияет на выполнение второго зеленого?
Они независимы друг от друга. При этом, если в первом присутствует >exit(); то скрипт останавливается и не выполняется далее. Все понятно?
http://php.net/manual/ru/function.exit.php
Объясните мне на пальцах отличия организации классов в пхп от жс?
Типы вместо ноды они хотел пэхэпэшника нанять?
Путь полный пропиши /usr/bin/emacs
сап веб-макакены . Собираюсь написать блог для поднятия скилла. Хочу сделать его полноценным веб-приложением . правильно ли я понимаю данную штуку:
есть клиентская (VIEW) часть для нее я выбрал библиотеку React . состояние приложения я буду хранить в store Redux .
для серверной части :
нужен роутинг , для этого буду юзать react-router
база данных - MySQL . для взаимодействия с БД использовать планирую PHP .
Правильно ли я понимаю взаимодействие между клиентской и серверной частью ? не намудил ли с выбором инструментов ?
Не совсем. Сравнение - это предикат, т.е. утверждение, которое может быть истинным или ложным. То есть, операция $humanAll == $compAll - это именно предикат. А "И", "ИЛИ", "НЕ" - это уже логические операции, порождающая новое утверждение на основе этих предикатов. Это дискретная математика 1 курса. Грубо говоря, представь себе выражение a + b c ; Здесь предикаты - это переменные, которые могут иметь любое значение, а логические операции - это математические операции. Так в и булевой логике. Отличие только в том, что здесь переменные-предикаты могут иметь только 2 значения, 1 - истина и 0 - ложь. Вообще, если ты не знаешь дискретку, то представь себе вместо || - знак ''+", вместо && - знак "", а вместо выражений вроде $humanAll == $compAll - единичку (истина) или нолик (ложь). Будет у тебя выражение 1 + 1 * 1. И попробуй потом вместо произвольных единичек поставить нолики и посмотреть, какое значение даст выражение с учетом приоритета операций. Я хз как проще объяснить, правда. Скачай книгу Хаггарти "Дискретная математика для программистов", там довольно доступно это изложено.
Выражения со вложенностью больше одной без скобок просто не вставить в строку. Например, в строке "Место жительства: user->address->city". Без фигурных скобок вокруг user->address->city пых подумает, что "user->address" - переменная для вставки, а -">city" - просто следующий за ней текст.
Может быть и так, как ты написал.
Вопрос, скорее, к тебе: понимаешь ли ты, как будут работать эти слои.
Нужна небольшая помощь, как сделать чтобы выводилось уже умноженное число?
$x * $x
https://ideone.com/M1Bxrb
Я так понимаю что это плохой тон, и надо бы по хорошему сразу передавать булеву переменную. Но как сделать это в цикле - я вообще не могу понять. Или и так нормально?
есть скрипт генератор паролей 32 символа с использованием rand и словаря. в цикле генерирую по 500 паролей за выполнение и пишу в базу.
1024 пароля записало, ок, и УГАДАЙТЕ ШТО, следующие 1024 пароля такие же как и предыдущие. ДОБРО ПОЖАЛОВАТЬ, НУФАГИ, ВЫ УБЬЕТЕ ЛЮДЕЙ СВОИМ КОДОМ, ТУТ ВСЕ РАБОТАЕТ НЕ КАК ДОЛЖНО.
мимо все на локалке 5.6 ксампп, в хедерах кеш выключен,страница запрашивается по уникальному get
По умолчанию числа никак не округляются и выводятся как есть. Но тут надо учесть, что дробные числа в PHP (как и в большинстве языков программирования) хранятся в формате IEEE754, это числа с плавающей запятой в двоичном виде: https://habrahabr.ru/post/112953/
Из этого вытекает 2 особенности:
- хранится только определенное число знаков и следующие за ними знаки теряются. Условно говоря, 123456789123.456789 может сохраниться как 123456789000
- некоторые дроби принципиально нельзя представить в виде конечной дроби в двоичной форме. Ну например, 1/3 - это бесконечная дробь в десятичной форме, а 1/5 - конечная. Но в двоичной форме 1/5 тоже становится бесконечной дробью
Числа можно округлять явно - с помощью функций round, ceil, floor. Также, их можно выводить с определенным числом знаков, используя printf() и спецификацию формата вроде %.3f - выводить с 3 знаками после запятой.
>>55021
Для начала, а ты знаешь, что такое POST-запрос? Когда ты в браузере заполняешь и отправляешь форму, у которой указан атрибут method="POST", браузер берет данные из нее и формирует HTTP POST запрос, который отправляет на сервер. Данные, введенные в форму, помещаются в тело этого запроса.
Подробнее HTTP описан тут, я рекомендую прочесть этот урок сначала: https://github.com/codedokode/pasta/blob/master/network/http.md - там объясняется и что такое запрос, и где у него тело.
Браузер составляет запрос и отправляет на сервер. Программа на сервере по идее должна разобрать этот запрос, извлечь из него нужные данные и что-то с ними сделать. В этом месте PHP как раз и приходит на помощь. Перед тем, как запустить твой скрипт, PHP разбирает пришедший запрос и помещает данные из него в специальные переменные:
- параметры из query string (то, что идет после знака вопроса) в URL помещаются в массив $_GET. Ну например, при разборе URL script.php?a=1 PHP поместит в $_GET элемент с ключом 'a' и значением '1'.
- если пришел POST-запрос, то параметры из его тела помещаются в массив $_POST
- наконец, некоторые настройки веб-сервера и заголовки пришедшего запроса помещаются в массив $_SERVER, они описаны в мануале http://php.net/manual/en/reserved.variables.server.php
Как видишь, ничего сложного. Я подозреваю, что ты не очень понимаешь взаимодействие клиента с сервером, протокол HTTP и потому советую прочесть урок по нему.
Задавай уточняющие вопросы, если что-то непонятно.
>>55036
"Суперглобальная переменная" значит, что она доступна в любом месте кода. Обычные глобальные переменные доступны только снаружи функций, а локальные - только внутри. Почитай мануал http://php.net/manual/ru/language.variables.scope.php
> Хмхмхмхм, то есть, $_GET и $_POST это своего рода контейнер, куда АВТОМАТОМ попадают все данные исходя из их метода передачи.
Перед запуском твоего скрипта PHP разбирает пришедший HTTP запрос и помещает данные из него в эти переменные.
> То есть, в $_GET попадают данные, переданные методом GET,
Нет, в $_GET попадают данные из query string в URL, независимо от метода. Он просто назван неудачно.
> и такая же хурма с $_POST?
$_POST заполняется только при использовании HTTP метода POST, да.
По умолчанию числа никак не округляются и выводятся как есть. Но тут надо учесть, что дробные числа в PHP (как и в большинстве языков программирования) хранятся в формате IEEE754, это числа с плавающей запятой в двоичном виде: https://habrahabr.ru/post/112953/
Из этого вытекает 2 особенности:
- хранится только определенное число знаков и следующие за ними знаки теряются. Условно говоря, 123456789123.456789 может сохраниться как 123456789000
- некоторые дроби принципиально нельзя представить в виде конечной дроби в двоичной форме. Ну например, 1/3 - это бесконечная дробь в десятичной форме, а 1/5 - конечная. Но в двоичной форме 1/5 тоже становится бесконечной дробью
Числа можно округлять явно - с помощью функций round, ceil, floor. Также, их можно выводить с определенным числом знаков, используя printf() и спецификацию формата вроде %.3f - выводить с 3 знаками после запятой.
>>55021
Для начала, а ты знаешь, что такое POST-запрос? Когда ты в браузере заполняешь и отправляешь форму, у которой указан атрибут method="POST", браузер берет данные из нее и формирует HTTP POST запрос, который отправляет на сервер. Данные, введенные в форму, помещаются в тело этого запроса.
Подробнее HTTP описан тут, я рекомендую прочесть этот урок сначала: https://github.com/codedokode/pasta/blob/master/network/http.md - там объясняется и что такое запрос, и где у него тело.
Браузер составляет запрос и отправляет на сервер. Программа на сервере по идее должна разобрать этот запрос, извлечь из него нужные данные и что-то с ними сделать. В этом месте PHP как раз и приходит на помощь. Перед тем, как запустить твой скрипт, PHP разбирает пришедший запрос и помещает данные из него в специальные переменные:
- параметры из query string (то, что идет после знака вопроса) в URL помещаются в массив $_GET. Ну например, при разборе URL script.php?a=1 PHP поместит в $_GET элемент с ключом 'a' и значением '1'.
- если пришел POST-запрос, то параметры из его тела помещаются в массив $_POST
- наконец, некоторые настройки веб-сервера и заголовки пришедшего запроса помещаются в массив $_SERVER, они описаны в мануале http://php.net/manual/en/reserved.variables.server.php
Как видишь, ничего сложного. Я подозреваю, что ты не очень понимаешь взаимодействие клиента с сервером, протокол HTTP и потому советую прочесть урок по нему.
Задавай уточняющие вопросы, если что-то непонятно.
>>55036
"Суперглобальная переменная" значит, что она доступна в любом месте кода. Обычные глобальные переменные доступны только снаружи функций, а локальные - только внутри. Почитай мануал http://php.net/manual/ru/language.variables.scope.php
> Хмхмхмхм, то есть, $_GET и $_POST это своего рода контейнер, куда АВТОМАТОМ попадают все данные исходя из их метода передачи.
Перед запуском твоего скрипта PHP разбирает пришедший HTTP запрос и помещает данные из него в эти переменные.
> То есть, в $_GET попадают данные, переданные методом GET,
Нет, в $_GET попадают данные из query string в URL, независимо от метода. Он просто назван неудачно.
> и такая же хурма с $_POST?
$_POST заполняется только при использовании HTTP метода POST, да.
1) Не ставь пробелы у атрибутов, пиши слитно name="..."
2) Атрибут method пишется у формы, а не у поля
3) Избегай br, его используют те, кто CSS не знает
> То есть, в это поле с именем login я ввожу имя ВАСЯНХХХ228, и это имя записывается в глобальный массив?
Ты пропустил важные шаги. Тебе надо почитать про протокол HTTP. Происходит такое:
- ты заполняешь форму и жмешь кнопку отправки
- браузер формирует HTTP POST запрос, помещая в него введенные в форму данные
- запрос отправляется на сервер
- на сервере PHP извлекает данные формы в $_POST
И да, то, что ты введешь в поле, окажется в итоге в $_POST.
В случае, если у формы стоит method="GET", то браузер ведет себя по другому. Он берет URL из атрибута action, и добавляет в него после знака вопроса данные формы, закодированные процентным кодировнием. Получается URL вроде script.php?x=1&y=2&z=%20%$20%30trd . И затем формирует GET запрос на сервер.
> GET и POST мы можем указывать только в атрибуте формы,
Потому что method указывается для всей формы сразу.
>>55127
Эти "связывания" - мне напоминают термины, относящиеся к компилируемым языкам. Там часто каждый файл с кодом (исходный файл) компилируется в специальный код (объектный код), а потом линкер связывает эти объектные файлы в исполняемый файл, который уже можно запускать на выполнение. Думаю, это оттуда. Согласен, что название больше запутывает.
>>55132
Назови поле для email как-то по другому, и сделай ловушку с именем email. Также, я тут не вижу особой проблемы - ну внесет бот мусор, ну у вас же все равно модерация там.
>>55160
В ОП посте кстати есть курс задач на HTML, и там же какие-то ссылочки есть.
1) Не ставь пробелы у атрибутов, пиши слитно name="..."
2) Атрибут method пишется у формы, а не у поля
3) Избегай br, его используют те, кто CSS не знает
> То есть, в это поле с именем login я ввожу имя ВАСЯНХХХ228, и это имя записывается в глобальный массив?
Ты пропустил важные шаги. Тебе надо почитать про протокол HTTP. Происходит такое:
- ты заполняешь форму и жмешь кнопку отправки
- браузер формирует HTTP POST запрос, помещая в него введенные в форму данные
- запрос отправляется на сервер
- на сервере PHP извлекает данные формы в $_POST
И да, то, что ты введешь в поле, окажется в итоге в $_POST.
В случае, если у формы стоит method="GET", то браузер ведет себя по другому. Он берет URL из атрибута action, и добавляет в него после знака вопроса данные формы, закодированные процентным кодировнием. Получается URL вроде script.php?x=1&y=2&z=%20%$20%30trd . И затем формирует GET запрос на сервер.
> GET и POST мы можем указывать только в атрибуте формы,
Потому что method указывается для всей формы сразу.
>>55127
Эти "связывания" - мне напоминают термины, относящиеся к компилируемым языкам. Там часто каждый файл с кодом (исходный файл) компилируется в специальный код (объектный код), а потом линкер связывает эти объектные файлы в исполняемый файл, который уже можно запускать на выполнение. Думаю, это оттуда. Согласен, что название больше запутывает.
>>55132
Назови поле для email как-то по другому, и сделай ловушку с именем email. Также, я тут не вижу особой проблемы - ну внесет бот мусор, ну у вас же все равно модерация там.
>>55160
В ОП посте кстати есть курс задач на HTML, и там же какие-то ссылочки есть.
У тебя тут ошибка:
> $arrName[] = '{$randomText}';
В строках с одиночными кавычками переменные не подставляются, и она просто воспринимается как есть.
Далее, ты пишешь
> $name = implode($randomText);
Но в implode надо указывать массив, значения элементов которого ты хочешь склеить в строку. Ты наверно написал в скобках не ту переменную.
Также, фигурная скобка } пишется на своей отдельной строке, где больше ничего нет.
>>55359
Не разбираясь исправить вряд ли получится. Я бы посоветовал сделать вывод, какие HTTP запросы ты отправляешь к API вконтакте и какие ответы оттуда приходят.
>>55741
В принципе, по JS тоже можно задавать вопросы.
>>55604
Сделать первую букву заглавной очень просто - отрежь первую букву и примени к ней toUpperCase, затем отрежь остаток строки, начиная со второй буквы, и приклей к первой. Это все лучше сделать в отдельной функции, а не писать длинный сложные выражения, как у тебя.
>>55784
А зачем тебе в массиве заменять первую букву? Ее можно заменить когда ты составишь предложение.
У тебя тут ошибка:
> $arrName[] = '{$randomText}';
В строках с одиночными кавычками переменные не подставляются, и она просто воспринимается как есть.
Далее, ты пишешь
> $name = implode($randomText);
Но в implode надо указывать массив, значения элементов которого ты хочешь склеить в строку. Ты наверно написал в скобках не ту переменную.
Также, фигурная скобка } пишется на своей отдельной строке, где больше ничего нет.
>>55359
Не разбираясь исправить вряд ли получится. Я бы посоветовал сделать вывод, какие HTTP запросы ты отправляешь к API вконтакте и какие ответы оттуда приходят.
>>55741
В принципе, по JS тоже можно задавать вопросы.
>>55604
Сделать первую букву заглавной очень просто - отрежь первую букву и примени к ней toUpperCase, затем отрежь остаток строки, начиная со второй буквы, и приклей к первой. Это все лучше сделать в отдельной функции, а не писать длинный сложные выражения, как у тебя.
>>55784
А зачем тебе в массиве заменять первую букву? Ее можно заменить когда ты составишь предложение.
В ES5 появился .map()
>>55953
Порт может открыть только одна программа. Если веб-сервер слушает на порту 80 узла 1.2.3.4, то ты не можешь, залогинившись на него, открыть этот же порт через ssh. Тебе надо отключить веб-сервер, и тогда ты сможешь открыть порт с помощью ssh и пробросить его к себе, то есть заставить клиент ssh у себя соединяться с указанным тобой портом при поступлении соединения на удаленный сервер.
Команды для этого легко гуглятся, там 2 варианта: открыть порт на удаленном сервере и пробрасывать соединения на него к себе, или наоборот.
>>56705
1) не использовать бутстрап
2) почитать исходный код или мануал бутстрапа. Там есть вариант сетки, который занимает 100% ширины без полей
>>56762
Скорее всего, дело в регистре букв. В MySQL по крайней мере для каждой таблицы и поля задан collation - правило сравнения строк на равенство (а также правило сортировки). Если у тебя у колонки регистрозависимый collation, то поиск по do не найдет "DO".
- http://itif.ru/kodirovka-mysql-kak-izbezhat-oshibok/
- https://dev.mysql.com/doc/refman/5.7/en/charset-general.html
>>57090
Стрелочки проставлять проще на стороне сервера, на PHP. Получается, что ты просто не смог сделать и влепил костыль, который после загрузки страницы что-то там на ней меняет. Я советую разобраться и сделать нормально.
Яваскрипт можно использовать, например, для сортировки данных внутри страницы или для сортировки с обновлением данных аяксом, а у тебя это просто костыль из-за слабого знания PHP.
Если непонятно, как сделать это на сервере, задавай уточняющие вопросы.
>>57599
Ну не надо копипастить код бездумно. Давай разбираться построчно.
> $connection = mysqli_connect(...) - что помешщается в переменную $connection ? (ответ в мануале)
> $result = mysqli_query(...) - что помещается в $result, значение какого типа? (ответ в мануале)
Может быть тогда тебе будет понятнее, как что выводить.
Ну и я сразу скажу, что тебе надо почитать комментарии к задаче про студентов, у тебя сейчас очень много чего нарушено, например, нет разделения на логику и шаблон, нет защиты от XSS. Не обрабатываются и не выводятся ошибки работы с базой данных.
В ES5 появился .map()
>>55953
Порт может открыть только одна программа. Если веб-сервер слушает на порту 80 узла 1.2.3.4, то ты не можешь, залогинившись на него, открыть этот же порт через ssh. Тебе надо отключить веб-сервер, и тогда ты сможешь открыть порт с помощью ssh и пробросить его к себе, то есть заставить клиент ssh у себя соединяться с указанным тобой портом при поступлении соединения на удаленный сервер.
Команды для этого легко гуглятся, там 2 варианта: открыть порт на удаленном сервере и пробрасывать соединения на него к себе, или наоборот.
>>56705
1) не использовать бутстрап
2) почитать исходный код или мануал бутстрапа. Там есть вариант сетки, который занимает 100% ширины без полей
>>56762
Скорее всего, дело в регистре букв. В MySQL по крайней мере для каждой таблицы и поля задан collation - правило сравнения строк на равенство (а также правило сортировки). Если у тебя у колонки регистрозависимый collation, то поиск по do не найдет "DO".
- http://itif.ru/kodirovka-mysql-kak-izbezhat-oshibok/
- https://dev.mysql.com/doc/refman/5.7/en/charset-general.html
>>57090
Стрелочки проставлять проще на стороне сервера, на PHP. Получается, что ты просто не смог сделать и влепил костыль, который после загрузки страницы что-то там на ней меняет. Я советую разобраться и сделать нормально.
Яваскрипт можно использовать, например, для сортировки данных внутри страницы или для сортировки с обновлением данных аяксом, а у тебя это просто костыль из-за слабого знания PHP.
Если непонятно, как сделать это на сервере, задавай уточняющие вопросы.
>>57599
Ну не надо копипастить код бездумно. Давай разбираться построчно.
> $connection = mysqli_connect(...) - что помешщается в переменную $connection ? (ответ в мануале)
> $result = mysqli_query(...) - что помещается в $result, значение какого типа? (ответ в мануале)
Может быть тогда тебе будет понятнее, как что выводить.
Ну и я сразу скажу, что тебе надо почитать комментарии к задаче про студентов, у тебя сейчас очень много чего нарушено, например, нет разделения на логику и шаблон, нет защиты от XSS. Не обрабатываются и не выводятся ошибки работы с базой данных.
> ${"word".$j}
Вот тут уже проблемы. Не надо использовать "переменные переменные" вроде $$name. В такой ситуации надо использовать массив, то есть сделать массив
$sets[1] = ...
$sets[2] = ...
И писать $sets[$j].
Массивы специально для этого придуманы, а ты лепишь какие-то костыли, в которых потом не разобраться
Далее, у тебя там 2 вложенных цикла, тоже сложно их понять:
для (i от 4 до 5) {
генерируем и выводим строку;
генерируем слово для последней строки;
}
Но почему так странно сделано? Почему генерация последней строки разбита на несколько шагов и перемешана с генерацией первых строк? Надо сделать так:
для (i от 1 до 2) {
генерируем и выводим строку;
}
генерируем и выводим последнюю строку;
Помни, что код пишется для людей и должен быть как можно понятнее. Твой код понятным назвать трудно, скорее запутанным.
палиндром
> [^а-я]
ё не входит в диапазон а-я и его надо указать отдельно.
Вообще, если ты захочешь написать "любой символ, кроме буквы любого алфавита", то тебе стоит почитать про Юникодные свойства символов: http://php.net/manual/ru/regexp.reference.unicode.php Так как вручную ты замучаешься перечислять все диапазоны символов.
> intdiv(mb_strlen($text), 2)
Можно просто floor($x / 2)
> for($halfLength = intdiv(mb_strlen($text), 2), $i = 0;
Отсюда лучше вынести вверх вычисление $halfLength, чтобы шапка цикла была короче и читабельнее. Не надо тесниться и засовывать в одну строку много действий.
> goto end;
Надо использовать break. Он гораздо понятнее тут.
функции
Вообще, тут проще было бы без цикла и массива, сравни сам:
$result[] = calculateCredit('Bank1', 30000, 200, 5);
$result[] = calculateCredit('Bank2', 35000, 300, 10);
...
> function calcDebt($bankName, $percent, $servicePayment, $openPayment) {
Не очень понятно, как на расчет кредита влияет название банка. Хотя я не считаю это ошибкой.
В остальном, решено верно.
> if($creditBalance >= $monthlyPayment) {
> $paymentTotal += $monthlyPayment;
Здесь вместо if можно использовать функции min/max.
> ${"word".$j}
Вот тут уже проблемы. Не надо использовать "переменные переменные" вроде $$name. В такой ситуации надо использовать массив, то есть сделать массив
$sets[1] = ...
$sets[2] = ...
И писать $sets[$j].
Массивы специально для этого придуманы, а ты лепишь какие-то костыли, в которых потом не разобраться
Далее, у тебя там 2 вложенных цикла, тоже сложно их понять:
для (i от 4 до 5) {
генерируем и выводим строку;
генерируем слово для последней строки;
}
Но почему так странно сделано? Почему генерация последней строки разбита на несколько шагов и перемешана с генерацией первых строк? Надо сделать так:
для (i от 1 до 2) {
генерируем и выводим строку;
}
генерируем и выводим последнюю строку;
Помни, что код пишется для людей и должен быть как можно понятнее. Твой код понятным назвать трудно, скорее запутанным.
палиндром
> [^а-я]
ё не входит в диапазон а-я и его надо указать отдельно.
Вообще, если ты захочешь написать "любой символ, кроме буквы любого алфавита", то тебе стоит почитать про Юникодные свойства символов: http://php.net/manual/ru/regexp.reference.unicode.php Так как вручную ты замучаешься перечислять все диапазоны символов.
> intdiv(mb_strlen($text), 2)
Можно просто floor($x / 2)
> for($halfLength = intdiv(mb_strlen($text), 2), $i = 0;
Отсюда лучше вынести вверх вычисление $halfLength, чтобы шапка цикла была короче и читабельнее. Не надо тесниться и засовывать в одну строку много действий.
> goto end;
Надо использовать break. Он гораздо понятнее тут.
функции
Вообще, тут проще было бы без цикла и массива, сравни сам:
$result[] = calculateCredit('Bank1', 30000, 200, 5);
$result[] = calculateCredit('Bank2', 35000, 300, 10);
...
> function calcDebt($bankName, $percent, $servicePayment, $openPayment) {
Не очень понятно, как на расчет кредита влияет название банка. Хотя я не считаю это ошибкой.
В остальном, решено верно.
> if($creditBalance >= $monthlyPayment) {
> $paymentTotal += $monthlyPayment;
Здесь вместо if можно использовать функции min/max.
Большинство разработчиков пилят только деньги инвесторов, если тебя это успокоит.
>>57941
Вообще, это неправильная логика. "Хотел подешевле" - а ты хочешь за услугу заплатить как можно больше? Либо делай как надо, либо вообще не берись.
> Скупой платит дважды
А нескупой трижды.
>>58002
$result = 0; можно было не писать,а так все верно.
>>58047
> $balance = $balance + $balance $percent;
$balance += ... или $balance = ....
Решено верно. В условии цикла можно было как раз прописать $balance >= 1000000.
>>58218
> SELECT from messages where (fromUserId = 4 and toUserId = 6) OR (fromUserId = 6 and toUserId = 4) ORDER BY timestamp.
OR не ложится на индексы
> Представь у тебя в одной таблице милион сообщений уже, и нужно вот так sql-ю бегать по всем и смотреть что бы 3 условия сочетались.
Нужны индексы: https://ruhighload.com/Индексы+в+mysql
Но вообще, когда у тебя число сообщений начинает превышать определенный объем (десятки-сотни миллионов например), то становится выгоднее вместо БД общего назначения сделать свою, заточенную под работу с сообщениями. Вконтакте так например сделал.
> Например можно изобразить что-то типа столбца chatId - и в него складывать некую хитрую пару вида юзерСМеньшимИд_юзерСБольшимИД.
Не надо так делать - это нарушает приницп нормализации (атомарность значений в ячейках).
То есть идея завести chatId неплохая, но городить там строки не стоит - выгоднее использовать либо число, либо пару колонок и индекс по ним.
Большинство разработчиков пилят только деньги инвесторов, если тебя это успокоит.
>>57941
Вообще, это неправильная логика. "Хотел подешевле" - а ты хочешь за услугу заплатить как можно больше? Либо делай как надо, либо вообще не берись.
> Скупой платит дважды
А нескупой трижды.
>>58002
$result = 0; можно было не писать,а так все верно.
>>58047
> $balance = $balance + $balance $percent;
$balance += ... или $balance = ....
Решено верно. В условии цикла можно было как раз прописать $balance >= 1000000.
>>58218
> SELECT from messages where (fromUserId = 4 and toUserId = 6) OR (fromUserId = 6 and toUserId = 4) ORDER BY timestamp.
OR не ложится на индексы
> Представь у тебя в одной таблице милион сообщений уже, и нужно вот так sql-ю бегать по всем и смотреть что бы 3 условия сочетались.
Нужны индексы: https://ruhighload.com/Индексы+в+mysql
Но вообще, когда у тебя число сообщений начинает превышать определенный объем (десятки-сотни миллионов например), то становится выгоднее вместо БД общего назначения сделать свою, заточенную под работу с сообщениями. Вконтакте так например сделал.
> Например можно изобразить что-то типа столбца chatId - и в него складывать некую хитрую пару вида юзерСМеньшимИд_юзерСБольшимИД.
Не надо так делать - это нарушает приницп нормализации (атомарность значений в ячейках).
То есть идея завести chatId неплохая, но городить там строки не стоит - выгоднее использовать либо число, либо пару колонок и индекс по ним.
> Пост-процессоры
Горите в аду.
> ECMAScript6
Горите в аду, как же достали сайты, которые ломаются в браузере 2-летней давности
Вот что меня жутко раздражает - "фронтент-специалисты" осваивают "пост-процессоры", а вот освоить искусство правильно разбивать CSS на файлы, верстать независимыми блоками, не городить в less/scss лестницы стилей - они не могут.
Пост-процессор дает дополнительные возможности, и как они их используют? Чтобы написать еще более нечитаемый код. Пишут лестницы на несколько экранов, разбивают названия классов на части, что их не найти поиском.
>>58548
Делай лендинги за 70 000.
>>58651
Какая цель? Показать пользователю файл, который он выбрал для загрузки? Тогда вполне можно.
Превью для сервера стоит генерировать на сервере, иначе тебе закачают одну картинку,а к ней другое превью.
>>58654
Также для привыкания к техническому англ. можно читать news.ycombinator.com
>>58859
Это жутко неэффективно так как требует полный обход таблицы.
>>58997
Это у тебя веб-сервер отдает кеширующие заголовки (говорит браузеру, что файл не скоро изменится и можно его кешировать). То есть твои кривые руки виноваты, ты скорее всего из какой-то статьи бездумно копипастил инструкции. Если ты используешь хостинг - то кривые руки его админов.
Когда открыты девтулз, можно там поставить галочку и кеш не будет использоваться по моему.
>>59005
Проще разобраться с кеширующими заголовками.
> Пост-процессоры
Горите в аду.
> ECMAScript6
Горите в аду, как же достали сайты, которые ломаются в браузере 2-летней давности
Вот что меня жутко раздражает - "фронтент-специалисты" осваивают "пост-процессоры", а вот освоить искусство правильно разбивать CSS на файлы, верстать независимыми блоками, не городить в less/scss лестницы стилей - они не могут.
Пост-процессор дает дополнительные возможности, и как они их используют? Чтобы написать еще более нечитаемый код. Пишут лестницы на несколько экранов, разбивают названия классов на части, что их не найти поиском.
>>58548
Делай лендинги за 70 000.
>>58651
Какая цель? Показать пользователю файл, который он выбрал для загрузки? Тогда вполне можно.
Превью для сервера стоит генерировать на сервере, иначе тебе закачают одну картинку,а к ней другое превью.
>>58654
Также для привыкания к техническому англ. можно читать news.ycombinator.com
>>58859
Это жутко неэффективно так как требует полный обход таблицы.
>>58997
Это у тебя веб-сервер отдает кеширующие заголовки (говорит браузеру, что файл не скоро изменится и можно его кешировать). То есть твои кривые руки виноваты, ты скорее всего из какой-то статьи бездумно копипастил инструкции. Если ты используешь хостинг - то кривые руки его админов.
Когда открыты девтулз, можно там поставить галочку и кеш не будет использоваться по моему.
>>59005
Проще разобраться с кеширующими заголовками.
Надо смотреть в инструментах разработчика, что куда отправлялось. Скорее всего ты отправляешь форму повторно, а там стоит параноидальный проверяльщик, который удаляет токен после использования.
Мне кстати их защита не нравится, она очень переусложненная. Проще использовать многоразовый токен в куке или просто проверку Referer/Origin.
>>59099
Какую? У тебя их несколько. но обычно для этого подходят float, или position absolute в зависимости от ситуации.
Какой кошмарный код.
Зачем ты везде ставишь overflow? Прочитал в какой-то статье от не разбирающегося в CSS человека? overflow обрезает выходящие за предел блока части, например, длинные слова.
Алсо, тебе не кажется, что дивов многовато? Если твоя верстка не похожа на бутстрап, то проще его не подключать. Бутстрап для сине-белых сайтов, а не всего подряд. Это какая-то бустрапоболезнь, ставить по 20 вложенных дивов.
>>59151
Ты не можешь нормально пользоваться бутстрапом, не зная CSS. Бросай эти глупости, бери мои задачи на CSS из ОП поста и решай.
>>59218
Бутстрап хорошо подходит для стандартный сине-белых сайтов. Если у тебя нестандартный дизайн, то не подходит.
Не используй автоинкремент, а вычисляй номера вручную.
>>59293
Я сталкивался с материал дизайн в админке Google Analytics, господи, как же это ужасно. Все огромное, рассчитано на огромные мониторы, и тормозит как будто там 3д игра запущена. И что меня больше всего раздражает, так это дизайн от андроида. Он хорошо смотрится на смартфоне, но ужасно на ноутбуке.
> один вечер не разобраться с флексбоксом
Ты серьезно? Я наверно час листал спецификацию и забил в итоге: https://www.w3.org/TR/css-flexbox-1/ - ты ее всю за один вечер освоил? А ты учел, что там еще есть баги в реализации? А как твой флексбокс будет выглядеть в неподдерживающих браузерах?
>>59352
То что ты предлашаешь, очень неэффективно, если у пользователя много бесед и много сообщений в них. Ты вытягиваешь из БД 10000 сообщений, чтобы отфильтровать 9500 из них. Это неэффективно.
ДВАЧ СРОЧНО ВЫРУЧАЙ, ПХП ОПЯТЬ ВЫТВОРЯЕТ СТРАННУЮ ХУЙНЮ
есть скрипт генератор паролей 32 символа с использованием rand и словаря. в цикле генерирую по 500 паролей за выполнение и пишу в базу.
1024 пароля записало, ок, и УГАДАЙТЕ ШТО, следующие 1024 пароля такие же как и предыдущие. ДОБРО ПОЖАЛОВАТЬ, НУФАГИ, ВЫ УБЬЕТЕ ЛЮДЕЙ СВОИМ КОДОМ, ТУТ ВСЕ РАБОТАЕТ НЕ КАК ДОЛЖНО.
тобиш rand просто берет 32768 цифр и все время их беребирает мол рандомные, нате
мимо все на локалке 5.6 ксампп, в хедерах кеш выключен,страница запрашивается по уникальному get
rand использует линейный конгруэнтный генератор: https://ru.wikipedia.org/wiki/Линейный_конгруэнтный_метод
mt_rand использует вихрь мерсенна: https://ru.wikipedia.org/wiki/Вихрь_Мерсенна
random_int/random_bytes берет данные из /dev/random. Их туда кладет ОС, собирая энтропию из случайных событий вроде времени прихода пакетов по сети.
Чем надежнее метод, тем медленнее он генерирует числа.
Также, существуют аппаратные ГСЧ.
пацаны бля mt_rand спас ахуеная вещь спасибо
mt_rand написано в 4 раза быстрее rand на пхп.нет
извини, спать хочу
Теку от таких дизайнов. Не то, что современное, вроде 9000 свистелок и перделок, а на деле с простой задачей "ПОКАЖИ ТЕКСТ И ДАЙ ПОЧИТАТЬ" - не справляются.
Не понял куда ты хочешь передавать переменную. Так то нормально но лучше все условия перевернуть и continue у тебя тут вообще не нужен
https://ideone.com/ovUzfA
Отдавать как результат работы функции. Просто непонятно можно ли при этом использовать переменную, или лучше сразу ставить
return true;
Просто в последнем случае я не понимаю как это делать в цикле. Поэтому у меня костыль с переменной.
>continue у тебя тут вообще не нужен
Это задание онлайн школы. Без него проверку не прозодило O_o;
Короче это не костыль, такая переменная называется флаг и по другому без ебли ты не сделаешь
Добра тебе анон.
Чот история притянутая за уши. И код явно неадекватный.
За такое в 2000 году даже чел из майкросфта нехило так по шапке получил (даже где-то журнал со статьёй валяется). А на практике такая вёрстка случалась только когда тётя Срака страничку в microsoft word 1997 верстала и постила её. В основном все клепали стиль для таблицы и применяли его. Никто не пилил стили для каждого тега каждой ячейки таблицы. Это во первых глупо, во вторых долго, в третьих весит овер дофига, в четрёртых область применения -1 ячейка.
Прошу объяснить без категоричных высказываний - туда ли я зашел?
Если мне придется работать не удаленно определенное время для стажа - я готов, не критично. Важна первоначальная цель.
>Прошу объяснить без категоричных высказываний - туда ли я зашел?
Нам тебя на работу устроить? Или что ты хочешь от PHP треда?
Уже сходил.
Пользуясь шапкой я получу в перспективе возможность работать удаленно плюс дальнейшее развитие навыка?
Я нудный и мне трудно конвертировать мысли в текст, бывает.
Так стоит ли игра свеч?
Беру квалификацию Red Hat пока и параллельно учу раковины, C и все что связано с шлинуксом. Если будут советы то прошу закинуть их сюда.
Конечно. В позапрошлом треде отписывались с десяток анонов которые на работу устроились благодаря обучению.
нет. мы тут все по приколу сидим. как хобби это у нас.
тебе в университет, высшее образование получать, потом по распределению.
Универсального вопроса на твой ответ нет, как говорил мне учитель математики Пока ты сидел печатал эту кучу текста, ты мог решить уже 100 конвертации из 0x в 0
Последнее: актуальность через n лет есть? Насколько я понял с набором знаний из шапки можно более плотно заняться JS, например. Если будет нужно, разумеется.
Буду отписываться здесь, чтоб не потерять мотивацию.
Через 1,5 года все это будет не актуально. не трать время. иди обучайся чему-нибудь другому, например шитью или кузнечному делу
Не трать время на пхп и бэкэнд. это стезя девствеников и чуханов.
вкатывайся в JS
вот ссылка тебе сюда. не благодари
https://2ch.hk/pr/res/1157660.html (М)
Подскажите, кто знаком с schema? Она актуальна?
В WhatWG пишут, что использование schema улучшает поисковые способности.
Пишу под своим постом
Потому что /web/ это /b/ только в другом виде.
Пришел какой-то залетный хуесос, который ни дня не учился и ни сделал ни одной задачи и сходу начинает спрашивать про работу и перспективы.
Я это с 2007 слышу. Самый смак был как раз в 2007, когда всё на C++ собирались переписать, Потом поспели джависты, потом Рубисты, потом питонисты, Потом приехал GO, а сейчас в моде node.js
При этом я как получал основной доход от PHP, так и получаю. А все эти говнофорсы улетают раз в 2 года в помойку.
Игнор?
Поддерживаю. Ебусь на php больше 10 лет. Постоянно изучаю что-то новое, но как был весь доход с PHP так и есть, остальное поиграться. Наверное лучше бы довел владение PHP до уровня Кришны.
Почему-то все думают, что сложно. Другое дело - что заёбывает делать одно и то же
> но к синтаксису PHP только привыкание идет туго
Чё там привыкать. Всё как во всех си-подобных языках. Только что function, -> вместо . (хотя в c++ есть и ->), строки склеиваются точкой, $ в названиях переменных и типы параметров функций декларируются своеобразно. Ну и всё вроди. Я после после паскаля и бейсика за день привык к синтаксису.
> macOS
Заебёшься фиксить конфликты homebrew, macports и приблуд, которые ставит XCode (если будешь ставить XCode, конечно). Многое придётся конпелировать, а не ставить apt-get'ом. Не рекомендую. macOS - конечно модно хотя хайп уже не тот, но для похапе - ну такое
https://dspace.vsb.cz/handle/10084/91028
нету
Конфигурация разная бывает. Но обычно смотрят на требования IDE. Будешь в нотпад++ писать, хоть целерон бери с 512 метрами и XP, Будешь PHPstorm юзать - готовь 8гиг и i5 минимум.
В шапке задание 2 по ксс/хтмл: https://github.com/codedokode/pasta/blob/master/html/html.md#Задание-2
Как сделать так, чтобы блок занимал столько места, сколько есть по высоте? max-height: 100% не помогает - скролл бар все равно появляется. overflow: hidden тоже - блок просто отрезается, а не подстраивается под height.
Показал бы хоть код что ли, я сам не спец, но как раз в силу того что мало опыта, самому стало интересно. Поковырялся бы сейчас, а нету. Вангую что у тебя блок в неправильном родителе сидит, и когда ты ему ставишь 100% то он берет высоту равную 100% от высоты родителя. Но при этом в родителе у тебя два блока друг над другом и вот такой вот конфликт выходит.
Такой задачи нет. В задаче 2 высота блока определяется его содержимым (текстом).
Но, если стоит задача сделать блок по высоте не менее чем высота окна, то делается это примерно так: ставим heigth 100% на html/body и min-height 100% на блок. Дело в том, что высота в процентах работает только если у всех родителей высота тоже задана в процентах или пикселях и может быть легко вычислена.
То, что ты пишешь, что появляется линейка прокрутки - это скорее всего из-за того, что у родительских блоков html или body есть margin или padding, а они не входят в высоту и получается с ними высота более 100%.
>>60944
https://jsfiddle.net/1zzyan6w/24/
уменьшите окно с результатом, будет видно, что блок увеличивается в размерах по вертикали.
> ставим heigth 100% на html/body и min-height 100% на блок
не работает
> будет видно, что блок увеличивается в размерах по вертикали.
Логично, ширина уменьшается, потому высота текста увеличивается.
>> ставим heigth 100% на html/body и min-height 100% на блок
> не работает
А ты попробуй. Ты ведь даже не выполнил мой совет, не поставил ни height 100% на html/body, ни min-height.
>как же достали сайты, которые ломаются в браузере 2-летней давности
Объясните, пожалуйста, убогому, покорнейше прошу, для чего нужны браузеры 2-летней давности? Я еще понимаю браузеры 10-летней давности в б/у телефонах купленных на рынке у барыг. Но это вопрос выжывача, а не веб разработки.
Ну вот есть допустим китайский планшет без обновлений. Или есть Windows XP, на которую нельзя поставить новый браузер. Или вот просто я привык, что все работает и не понимаю, зачем мне тратить свое время на обновление. При том что новый браузер будет работать хуже и медленнее.
Но речь вообще не обо мне. Факт в том, что в мире есть разные браузеры. Ответь теперь ты мне на вопрос, а какая выгода делать сайт только под последнюю версию хрома, а не такой, который будет работать везде?
Или возьми тот же стабильный дебиан: там весь софт не новый. Там предпочитают стабильные и проверенные программы, а не наспех слепленные новые версии.
Это же просто показывает компетентность разработчика: способен ли ты писать так, чтобы работало везде, а не только в твоем браузере.
Как я понимаю, среднестатистический "фронтенд специалист" вообще не разбирается в стандартах и их версиях и например не знает, с какой версии поддерживаются те же аргументры функций по умолчанию в JS (а я знаю: в браузерах 2-летней давности они не работают). К примеру, в Хромиуме 46 (реально, довольно новая версия, не старье какое-нибудь) параметры по умолчанию вызывают ошибку:
function x(a=1) { }.
Гнать надо вас всех на мороз, "фронтенд специалисты".
И конечно ада добавляют сайты для "фронтенд специалистов", которые спешат писать статьи про модные нововведения, но не объясняют, где они поддерживаются.
Вот пример: какой-то не очень умный автор радостно пишет 5 страниц про нововведения, и только в конце вскользь замечает, что это не везде работает: https://frontender.info/es6-in-depth-rest-parameters-and-defaults/
Это надо писать не вскользь,а большими буквами в начале: это не работает.
Разве babel не решает эту проблему?
https://github.com/sergnik1995/OOPtasks
Минимального просто не существует.
Но если хочется комфортной работы, добавь памяти. IDE ее любят жрать.
Лет через 5, после массового внедрения фичи, можно ее использовать. Зачем эти "фичи" нужны, если основной результат их использования - лишение части пользователей доступа к сервису?
Посмотри на ту же историю флексбокса. Они сделали 2 (!) ревизии, первая им чем-то не понравилась, они ее закопали, и все равно в браузерах есть баги с его поддержкой. Зачем так вообще делать?
Также, флексбоксом не умеют пользоваться. Я сам видел 2 случая, когда в верстке с флексбоксом размеры элемента высчислялись в ноль, и он исчезал. Решил проблему удалением флексбокса :)
Все должно внедряться не спеша и продуманно.
Ребята, не лезьте в это дело. Это дно. Все php-шники, исключая единицы, являются навозными жуками, которые разбирают кучу какашек, скатывают отдельные кусочки в шарик и переносят в другое место. Большинство из вас будет работать с 1С-Битрикс, Joomla, Wordpress и другими тошнотворными проектами. Вы будете делать одно и тоже из дня в день. Настанет момент, когда спадёт вся романтика и вы застрянете, не будет мотивации для развития (если, конечно, крупно не повезёт сходу). Не совершайте ошибок, которые совершил я. Стремитесь к изучению другого инструмента. Даже рядовым специалистов на каком-нибудь Java вы будете более ценными и высокооплачиваемыми. А так вас ждёт только разочарование. Да, в первый год или два, будет интересно, будет невероятный подъём сил, но дальше только пустота и однотипные заказы.
Я понял, спасибо!
ты нагло лгал в лицо мне и всем тут. Твое учение отстой. свой учебник засунь себе в гузно.
>>61296 этот открыл мне глаза.
Я пошел отсюда.
Все за мной в с++ тред
function connect() {
$dbc = new mysqli_connect('localhost', 'root', '', 'testsDB');
if ($dbc->connect_errno) {
echo ("Connect failed: '%s\n'", $dbc->connect_error);
exit();
}
return $dbc;
}
Выдаёт ошибку: Parse error: syntax error, unexpected ',' in C:\OSPanel\domains\studentlist\scripts.php on line 7
Двач, помогай, я сейчас с ума сойду, блять.
>echo ("Connect failed: '%s\n'", $dbc->connect_error);
Собственно в этой строчке вся проблемы, но я не пойму, что тут не так
Здесь автор наверно хотел printf вместо echo
или так
echo "Connect failed:", $dbc->connect_error,"\n";
или так
echo ("Connect failed:". $dbc->connect_error."\n");
или раз уж по форматы
printf ("Connect failed: '%s'\n", $dbc->connect_error);
И обрати внимание на '
Если все сам с нуля пишешь, то да. Но так не бывает.
Будешь брать чужие куски, а там в 99% случаев на это хуй ложили. Значит заебешься в них исправлять.
Нет, declare(strict_types=1) работает только в пределах текущего файла, поэтому и тайп-хинты скалярных типов будут проверяться на строгость только для тех функций/методов, которые объявлены в текущем классе.
>>61370
Да, надёжнее всегда использовать, чтобы избежать нежелательных конвертаций типов. Советую для автоматизации всего этого дела использовать PHP-CS-Fixer, он может сам проставлять declare(strict_types=1) для всех файлов. Ещё есть вариант настроить Class Template в PHPStorm, но это удобно только если у тебя абсолютно все проекты на PHP7+: https://plugins.jetbrains.com/plugin/9640-php-class-templates
>>60829
> Будешь PHPstorm юзать - готовь 8гиг и i5 минимум.
Я пользовался PHPStorm'ом на двухъядерном Intel Pentium + 4 RAM. Если отрубить кучу ненужных плагинов, чекеров, синхронизаций - то вполне юзабельно, в сети есть уйма статей по оптимизации. На i7 сейчас PHPStorm, конечно, летает.
В 90% случаев проще самому 30 минут потратить и написать с блэкджеком и дамысфривольнымотношениемкморали. Чем с гита разбирать ваяние очередного вендора.
Расскажи свою стори что ли. Я вот уже пол года хуи пинаю без работы и сейчас накатило что-то типа тревоги и не могу уснуть. Сижу вот боюсь, что как начну ходить по собеседованиям - так нахуй ни кому в свои 30 буду не нужен.
или
foo(&$arr){ $arr['bar'] = bazz; }
Что предпочтительней? Или вообще без разницы?
Зубов бояться - в рот не давать. Вообще-то, собеседования на то и собеседования, чтобы проверить скилл претендента. Если бы отбирали по возрасту, достаточно было бы указать в требованиях "иметь при себе паспорт". Другое дело, что тебе может быть психологически некомфортно выполнять ЦУ тимлида, который младше тебя на 10-12 лет. Или ему будет некомфортно командовать великовозрастным джуном. Интервьюер, разумеется, должен это учитывать и там уже имеют значения не только твои навыки, но и то, как ты себя поставишь в процессе беседы. Это сугубо моё имхо, бо я в свой 31 смог устроиться по знакомству, да и выгляжу как первокурсник ебаный, особенно если сравнить с нынешними детишками-акселератами.
<?
if($_POST['category']=="fish"){
$ft +=1;
}
echo "you have chosen ft" .$ft. "times";
?>
<form action="p1.php" method="POST">
<select size="3" name="category">
<option type="checkbox" value="fish"> Fishing </option>
</select>
<input type="submit" name="sub" value="choose">
</form>
И да, нужна именно эта html форма.
1. Если значение должно жить только пока пользователь не закроет вкладку в браузере, добавить input type="hidden" и держать значение там. Сломается если пользователь будет тыкать "Назад" в браузере.
2. Ставить куку с текущим значением.
2а. Ставить куку с идентификатором пользователя. Хранить на сервере в БД.
Будет сохранено пока пользователь не почистит куки.
3. Прикрутить систему авторизации. Будет сохранено пока жив сервис.
Можно через сессию сделать.
<?php
session_start();
if($_POST['category'] == 'fish'){
$_SESSION['category'] ? $_SESSION['category']++ : $_SESSION['category'] = 1;
echo "you have chosen ft {$_SESSION['category']} times";
}
Будет помнить значение до тех пор пока не закроешь страницу.
Только в условии перед первым $_SESSION['category'] поставить @, иначе при первом вызове выдаст варнинг. Вот так:
@$_SESSION['category'] ? $_SESSION['category']++ : $_SESSION['category'] = 1;
А сессию хранить в SQLite или отдельном файлике. HTTP он такой - ни чего не помнит. И еще юзверя надо сохранять по иду.
Ога. Сессию отдельно храни, сборщик мусора у пыхи ни разу не девелоперфредли.
У меня работает нормально. Скорее всего, тебе сессионная кука не передаётся почему-то. Или пробел перед кодом скрипта или BOM
<?php
$year = 16;
$yearAll = 0;
for($i = 10000; $i <= 1000000; $i *= 0.1) {
$year++;
$yearAll++;
}
echo $year,$yearAll
?>
<?php
$year = 16;
$yearAll = 0;
for($i = 10000; $i <= 1000000; $i *= 10) {
$year++;
$yearAll++;
}
echo $year,$yearAll
?>
Например так. У тебя границы цикла и шаг такие, что он бесконечный.
Спасибо
$tbl=$dbConn->prepare('SELECT * FROM `students` ORDER BY :sort ');
$tbl->execute(array('sort' => $_GET['sort']));
$students=$tbl->fetchALL(PDO::FETCH_ASSOC);
в гете лежит строка с названием колонки
Потому что имя колонки не может подставляться через переменные связывания. У тебя в итоге работает так:
/?sort=cpprulez
SELECT * FROM `students` ORDER BY 'cpprulez'
- то есть сортировка идёт по строковой константе, одинаковой для всех записей.
спасибо
заработало так
$tbl=$dbConn->prepare('SELECT * FROM `students` ORDER BY '.$_GET['sort']);
* - лишняя, и сега приклеилась
Лучше сделай sort - номер колонки, тогда всё будет работать со старым запросом, и без SQLi.
> https://dev.mysql.com/doc/refman/5.7/en/select.html#id756773
> ORDER BY {col_name | expr | position}
http://archive-ipq-co.narod.ru/l1/finals.html - предпоследнее задание, сделать чтобы числа прописью отображались.
https://ideone.com/7DImNa - мой код.
Аноны, хелп.
Делаю парсер на jquery.
Есть сайт с таблицей, количество колонок в которой меняется от 2 до 6 в зависимости от <select></select>. После смены значения - страница перезагружается и количество столбцов меняется. Нужно парсить значения со всех 6 столбцов. Делаю так:
$("select[name='DatesNum']").val(6)
$("select[name='DatesNum']").trigger('onchange')
Циферка в меню <select> меняется, но количество столбцов нет. Как решить проблему?
Говнокод: https://pastebin.com/QDMGAgZN
Подпись сделал, теперь надо разобраться с цветом.
Вот полный класс контейнера - https://text-share.com/view/56b73461
Может там проблема с this на 49 строке, и оно как-то влияет на класс хелпер? очень сложна
В PHP анонимная функция хранится как объект встроенного класса Closure. Потому, когда ты пытаешься сдампить массив с функциями, ты получаешь массив объектов Closure. В каждом объекте сохранены захваченные функцией переменные (они указаны в use) и значение $this на момент создания функции.
Это можно легко проверить, например
$x = function () {};
var_dump($x);
var_dump($x instanceof \Closure); // true
Меня смущала рекурсия этих функций в дампе, this в анонимных функциях я не юзаю, контейнер нормально все возвращает, так может его так и оставить? Я так подумал что в данном контексте мне должно быть немного похер к какой области видимости принадлежит анонимная функция.
> В 90% случаев проще самому 30 минут потратить
Вот тебе список пару из тысячи real-world задач, а ты напиши, как за 30 минут справишься со всем этим без сторонних библиотек:
1) Раньше все картинки хранились на том же сервере, что и сайт, но сейчас картинок стало очень много и оказывается выгоднее их хранить на каком-нибудь Digital Ocean Spaces или DropBox. Если бы для работы с файлами в проекте изначально использовалась сторонняя библиотека - flysystem ( https://github.com/thephpleague/flysystem ) - то в коде потребовалось бы очень мало изменений для переноса, так как flysystem предоставляет общий интерфейс для работы над множеством разных хранилищ файлов, а настраивается только через конфиг. То есть нужно спрыгнуть с DropBox на Amazon S3 - поменял пару строк в конфиге, а не код, который по всему проекту размазан. Конечно, это не работает, когда нужны специфичные особенности конкретного хранилища, но времени для правки всё равно ушло бы в разы меньше - в итоге работа выполнилась быстрее, бизнесу выгоднее, так так меньше платить разработчику за изменения, ты - хороший специалист, быстро решающий проблемы.
2) Нужно написать бота, то есть нужно взаимодействовать с каким-то API, слушать вебхуки. При этом важно, чтобы бота можно было без особых усилий переписать на другую платформу, например раньше в моде был ВК, теперь - Телеграм. Значит нужна какая-то абстракция для бота, ты можешь написать её сам и всё равно всего не учесть, а можешь взять готовую - BotMan: https://botman.io/
Популярная всесторонне оттестированная библиотека, в которую коммитили люди со всего мира, когда находили какие-то несостыковки или проблемы, не обнаруженные автором. Библиотека по-прежнему активно поддерживается, ты будешь свою поделку через 2-3 года поддерживать, когда API Телеграма или ВК поменяется?
Меня расстраивает, что есть такие люди как ты, да ладно вы бы молча сидели, так ещё распространяете свои недальновидные, дурные подходы среди других людей, не имея опыта написания и поддержки больших и сложных программ.
> В 90% случаев проще самому 30 минут потратить
Вот тебе список пару из тысячи real-world задач, а ты напиши, как за 30 минут справишься со всем этим без сторонних библиотек:
1) Раньше все картинки хранились на том же сервере, что и сайт, но сейчас картинок стало очень много и оказывается выгоднее их хранить на каком-нибудь Digital Ocean Spaces или DropBox. Если бы для работы с файлами в проекте изначально использовалась сторонняя библиотека - flysystem ( https://github.com/thephpleague/flysystem ) - то в коде потребовалось бы очень мало изменений для переноса, так как flysystem предоставляет общий интерфейс для работы над множеством разных хранилищ файлов, а настраивается только через конфиг. То есть нужно спрыгнуть с DropBox на Amazon S3 - поменял пару строк в конфиге, а не код, который по всему проекту размазан. Конечно, это не работает, когда нужны специфичные особенности конкретного хранилища, но времени для правки всё равно ушло бы в разы меньше - в итоге работа выполнилась быстрее, бизнесу выгоднее, так так меньше платить разработчику за изменения, ты - хороший специалист, быстро решающий проблемы.
2) Нужно написать бота, то есть нужно взаимодействовать с каким-то API, слушать вебхуки. При этом важно, чтобы бота можно было без особых усилий переписать на другую платформу, например раньше в моде был ВК, теперь - Телеграм. Значит нужна какая-то абстракция для бота, ты можешь написать её сам и всё равно всего не учесть, а можешь взять готовую - BotMan: https://botman.io/
Популярная всесторонне оттестированная библиотека, в которую коммитили люди со всего мира, когда находили какие-то несостыковки или проблемы, не обнаруженные автором. Библиотека по-прежнему активно поддерживается, ты будешь свою поделку через 2-3 года поддерживать, когда API Телеграма или ВК поменяется?
Меня расстраивает, что есть такие люди как ты, да ладно вы бы молча сидели, так ещё распространяете свои недальновидные, дурные подходы среди других людей, не имея опыта написания и поддержки больших и сложных программ.
Макет тянется, всё красиво, подстраивается под разрешение экрана. Но вот есть тут пара вопросов, да и может посоветуете чего, подскажете.
Почему колонка 2 стоит неравномерно относительно 1й, приходится подстраивать top: 8.9%; и прочее, чтобы стояли ровно. Но у 1й же именно 10 отступ, а со 2й колонкой отступ margin не работает, так как позиция абсолютная, поэтому использую top. В общем может подскажите почему я такой долбоем и как красиво оформлять в данном случае.
Второе - как сделать фиксированное положение 2й колонны, при этом чтобы можно было скроллить страницу. Ну как опять же в том же вк. Пока прихуячил фиксированную позицию, а внутрь засунул еще один блок с длиной больше экрана, но что-то не заработает (лол).
http://cssdeck.com/labs/natibfns а вот собсна и оно
а зачем ты судишь о производительности апача по его работе на домашней машинке и далеко не самой мощной? Или ты на ней хочешь хостить реальный сайт?
Залей на вебсервер.
Потом, хотя бы просто при помощи "ab", сделай 1000 по 100 запросов. Получишь стату.
AWS все еще дает EC2 бесплатно на год
Загрузка ЦП показывает лишь, что процессор работает и используется по назначению. Чтобы выяснить, какую нагрузку выдержит сайт, надо провести нагрузочное тестирование (желательно не локально, а на реальном хостинге). Для этого можно использовать программы apache benchmark или siege, например.
Рутина, школокодеры, низкий порог входа, курсы попова и вообще пыха это как школьный омеган, уже никто и не помнит почему его ненавидят.
<?php
$count = 0;
$arr = array();
for ($i = 0; $i < 5; $i++){
echo '<br>';
for ($j = 0; $j < 5; $j++){
$arr[$i][$j] = rand(0, 1);
echo ' '.$arr[$i][$j];
if ($arr[$i][$j] == 1 || $arr[$i][--$j] == 1 && $arr[--$i][$j] == 1){
$count++; }
}
}
как это сделать?
Недавно вкатываюсь в пхп, изучал c++ и там это работало так.
Условие опускает индекс массива до -1 и цикл бесконечно повторяется.
Аноны, ну зайдите хоть кто-то. Я там 1 в группе. Давайте вместе изучать. Я выложил пару сверстанных мной макетов
Спасибо
>
>Чем button отличается от input type="submit" ?
гораздо лучше поддаётся стилизации и можно прилепить на неё картинку.
<input type='hidden' value='$x'
Нубский ответ:
У тебя логика хромает. Разве есть смысл кэшировать шаблоны? Шаблон не нагружает твоё приложение.
По мне так кэшировать нужно как-то так: возьмем на примере социальной сети.
Вот ты грузишь страничку пользователя например.
У тебя подгрузились из одной таблицы все его личные данные: фоточки там, даты, имя, места и прочее.
Из другой список его друзей, из третьей список постов на стене, из четвертой паблики на которые он подписан, из пятой музыка которая у него добавлена и так далее. Там очень много кода и запросов в базу и по базе всё это в гигантских таблицах тоже ищется со всякими джойнами и прочим.
Далее наш код собирает его страничку в виде html и отдает юзеру.
Ну и представь что ты можешь всегда таким дерьмом заниматься на каждый запрос и на каждую перезагрузку юзером его страницы, либо ты можешь например после первой загрузки весь собраный html сложить в отдельную таблицу на хранение, как стенку текста. И когда юзер в очередной раз спросит свою страничку - сделать простейший селект быстренько и отдать заранее собранный html без выполнения кучи кода и селектов с джойнами. Профит? определенно.
Вообще, ты сильно все упростил и это вредно, так как ты запутал новичка. Из твоего рассказа выглядит что у кеша одни только плюсы. И новичок побежит радостно лепить везде кеш, а кому-то потом все это разгребать.
По моему, кеш - это последнее средство, когда невозможны другие оптимизации. У него много недостатков: поддержка актуальности кеша, прогрев.
В твоем примере соцсети гораздо лучше иметь хранилище, которое быстро возвращает данные, чем такой кеш. Так как ты его должен не забывать обновлять при любом изменении данных, от которых он зависит. Это называется проблема инвалидации, и по мере увеличения видов данных и связей между ними она очень усложняется.
Друг пользователя поменял имя - надо сбрасывать кеш. Удалил друга из друзей - надо сбрасывать кеш. И так далее.
Также, есть проблема прогрева - в начальный момент кеш пуст и вся нагрузка в твоем сценарии ляжет на базу.
Также, бывает проблема, когда у нас очень много сущностей и мало повторных запросов к одной сущности, а все они идут к разным. В этом случае кеш тоже малоэффективен- память он ест, а работу не выполняет (высокое количество misses и низкое hits).
Наконец, кеш можно делать на разных уровнях. Ты предложил кешировать фрагменты HTML, но и тут есть проблема - даже для разных пользователй HTML может выглядеть по-разному. Представь например топ пользователей, где текущий пользователь выделен цветом. Хотя пользователи в топе одинаковые, но HTML код для каждого из них получается разный.
Потому не все так просто. В каждой ситуации надо взвешивать плюсы и минусы.
Лучше было бы привести такой сценарий: блог, справа список самых популярных постов, который кладется в кеш, и обновляется раз в 15 минут.
Насколько я знаю, те же вконтакте для многих видов данных пришли к специализированным хранилищам от кеша, так как в их сценарии (данных очень много, запросы идут вразброс к разным данным, данные постоянно обновляются) кешировать эффективно сложно.
Могу также добавить ссылки на презентации (не знаю, где видео докладов, поищите по имени автора или названию):
- http://lib.custis.ru/images/6/6d/WebAppCache.pdf
- https://habrahabr.ru/company/oleg-bunin/blog/320044/
Вообще, ты сильно все упростил и это вредно, так как ты запутал новичка. Из твоего рассказа выглядит что у кеша одни только плюсы. И новичок побежит радостно лепить везде кеш, а кому-то потом все это разгребать.
По моему, кеш - это последнее средство, когда невозможны другие оптимизации. У него много недостатков: поддержка актуальности кеша, прогрев.
В твоем примере соцсети гораздо лучше иметь хранилище, которое быстро возвращает данные, чем такой кеш. Так как ты его должен не забывать обновлять при любом изменении данных, от которых он зависит. Это называется проблема инвалидации, и по мере увеличения видов данных и связей между ними она очень усложняется.
Друг пользователя поменял имя - надо сбрасывать кеш. Удалил друга из друзей - надо сбрасывать кеш. И так далее.
Также, есть проблема прогрева - в начальный момент кеш пуст и вся нагрузка в твоем сценарии ляжет на базу.
Также, бывает проблема, когда у нас очень много сущностей и мало повторных запросов к одной сущности, а все они идут к разным. В этом случае кеш тоже малоэффективен- память он ест, а работу не выполняет (высокое количество misses и низкое hits).
Наконец, кеш можно делать на разных уровнях. Ты предложил кешировать фрагменты HTML, но и тут есть проблема - даже для разных пользователй HTML может выглядеть по-разному. Представь например топ пользователей, где текущий пользователь выделен цветом. Хотя пользователи в топе одинаковые, но HTML код для каждого из них получается разный.
Потому не все так просто. В каждой ситуации надо взвешивать плюсы и минусы.
Лучше было бы привести такой сценарий: блог, справа список самых популярных постов, который кладется в кеш, и обновляется раз в 15 минут.
Насколько я знаю, те же вконтакте для многих видов данных пришли к специализированным хранилищам от кеша, так как в их сценарии (данных очень много, запросы идут вразброс к разным данным, данные постоянно обновляются) кешировать эффективно сложно.
Могу также добавить ссылки на презентации (не знаю, где видео докладов, поищите по имени автора или названию):
- http://lib.custis.ru/images/6/6d/WebAppCache.pdf
- https://habrahabr.ru/company/oleg-bunin/blog/320044/
И не такие чудеса вытворять умеем!
Ну ты соня. У JS версии 3. У java 10. Enjoy your ORACLE. Причём джависты от радости прыгают "ряяяяяя не надо больше писать определения в миллиард символов, такая то экономия времени".
Онооон. Поставил интерпритатор ПХП себе на линупс, читаю урок про строки. Дошел до функций mb_, этот пиздюк ругается, что не знает таких. ЧЯДНТ?
Лень гуглить спрошу анона.
Версия PHP? Какие функции mb_? На что ругается и как? Что пишет?
Щас бы изучать PHP на линуксе, чтобы с каждой ошибки по 4 часа гуглить.
>Да не более 3х минут заняло, няш.
Ну хз, мне страшновато так-то. Вылезает такое и я хз это от PHP или от линукса ошибка.
Тут просто опыт нужен, когда я только перекатился и стал учить си все и правда занимало время. А теперь ок
На пике код. Не могу понять в чём проблема. И в чём суть ошибки?
ну так объясни тупому, умник хуев
Голове было больно, да.
Есть еще линуксотред.
Не траль плиз, у байтоебов и так жизнь не сахар
у них с 14 марта вроде появилась возможность делать вайлдкард на все поддомены бесплатно. сам еще не пользовался
Вот прям нравится теперь, спасибо, ОП.
>Вообще, ты сильно все упростил и это вредно, так как ты запутал новичка.
Я понимал, что нужно будет при каждом чихе актуализировать как-то кэш, но это уже действительно более сложный для меня был вопрос и не стал ничего про него писать, на то я ответил с пометкой о том, что мой ответ едва-ли чуть менее нубский чем сам вопрос и наделялся на какое-то более развернутое пояснение в треде.
А еще твой ответ даже для меня сложен и местами не понятен. Не понимаю что подразумевается под хранилищами, которые как будто просто раз и быстрее чем база - как, что это?
>Также, бывает проблема, когда у нас очень много сущностей и мало повторных запросов к одной сущности, а все они идут к разным.
Это как если например ты закешируешь всех юзеров вконтакте, а многие из них очень даже и непопулярны, и на их странички никто не заходит, но при этом у них постоянно из друзей кто-то удаляется или меняет личные данные так, что страничку нашего непопулярного юзера будет проще каждый раз собирать заного, чем на каждый чих его друзей обновлять кэш?
>Представь например топ пользователей, где текущий пользователь выделен цветом. Хотя пользователи в топе одинаковые, но HTML код для каждого из них получается разный.
Представил что в нашей соц-сети для разных пользователей будет страничка юзера отображаться по разному. Его близкие друзья видят её полностью, а просто болтающиеся в френд-листе рандомы вообще не видят почти персональных данных, да еще и каждый из них видит списки друзей нашего юзера по разному, так что бы общие друзья были в топе этого списка или как-то так, что по сути ведет к тому, что нужно кешировать страницу одного пользователя несколько раз в разных вариантах, начиная с версии для близких и заканчивая для совсем незарегестрированных. Надеюсь правильно представил.
Вообще спасибо за ответ, понял что можно было бы пожалуй на средних проектах для теста попробовать прикрутить кэширование например главной страницы. Какое-нибудь простенькое, что бы юзеры банально не дергали с базы все новости и прочие баннеры, а например просто брали закешированную, которая будет обновляться раз в пол часа кроном каким-нибудь.
Печально, что за пару лет опыта я сижу на каких-то макако-задачах в среде таких же не шарящих ребят и не с кем даже банально на теоритическом уровне по обмениваться подобным опытом, не говоря уже о том что бы писать вместе с кем-то сложный проект и всякие вот такие вот задачи решать, а не просто прикручивать всякие перделки к лендингам и костыли к старым сайтам на cms-ках.
>Вообще, ты сильно все упростил и это вредно, так как ты запутал новичка.
Я понимал, что нужно будет при каждом чихе актуализировать как-то кэш, но это уже действительно более сложный для меня был вопрос и не стал ничего про него писать, на то я ответил с пометкой о том, что мой ответ едва-ли чуть менее нубский чем сам вопрос и наделялся на какое-то более развернутое пояснение в треде.
А еще твой ответ даже для меня сложен и местами не понятен. Не понимаю что подразумевается под хранилищами, которые как будто просто раз и быстрее чем база - как, что это?
>Также, бывает проблема, когда у нас очень много сущностей и мало повторных запросов к одной сущности, а все они идут к разным.
Это как если например ты закешируешь всех юзеров вконтакте, а многие из них очень даже и непопулярны, и на их странички никто не заходит, но при этом у них постоянно из друзей кто-то удаляется или меняет личные данные так, что страничку нашего непопулярного юзера будет проще каждый раз собирать заного, чем на каждый чих его друзей обновлять кэш?
>Представь например топ пользователей, где текущий пользователь выделен цветом. Хотя пользователи в топе одинаковые, но HTML код для каждого из них получается разный.
Представил что в нашей соц-сети для разных пользователей будет страничка юзера отображаться по разному. Его близкие друзья видят её полностью, а просто болтающиеся в френд-листе рандомы вообще не видят почти персональных данных, да еще и каждый из них видит списки друзей нашего юзера по разному, так что бы общие друзья были в топе этого списка или как-то так, что по сути ведет к тому, что нужно кешировать страницу одного пользователя несколько раз в разных вариантах, начиная с версии для близких и заканчивая для совсем незарегестрированных. Надеюсь правильно представил.
Вообще спасибо за ответ, понял что можно было бы пожалуй на средних проектах для теста попробовать прикрутить кэширование например главной страницы. Какое-нибудь простенькое, что бы юзеры банально не дергали с базы все новости и прочие баннеры, а например просто брали закешированную, которая будет обновляться раз в пол часа кроном каким-нибудь.
Печально, что за пару лет опыта я сижу на каких-то макако-задачах в среде таких же не шарящих ребят и не с кем даже банально на теоритическом уровне по обмениваться подобным опытом, не говоря уже о том что бы писать вместе с кем-то сложный проект и всякие вот такие вот задачи решать, а не просто прикручивать всякие перделки к лендингам и костыли к старым сайтам на cms-ках.
А ты сам как себе сайт про мавроди представляешь, скажем на питоне или на руби?
<table bgcolor="#ba639C"><tr><td align="center">Как легко заработать с нашей компанией</td></tr></table>
Ты забыл cellspacing=0 cellpadding=0 border=0.
$arr = ["Привет", "Двач"];
$arr[0][2];
Даа по сравнению с $arr[0][2] такой костыль конечно, не перестаю удивляться пыхе.
Анонче, респект и уважуха
Щелкните правой кнопкой на панели закладок (чтобы показать ее в Хроме, используйте Ctrl + Shift + B) или найдите в меню пункт "добавить закладку". В поле "название" введите что хотите, в поле URL введите:
javascript:var t = document.querySelectorAll('.post-wrapper:not(.watched-posts-marker)');Array.prototype.map.call(t, function (el) { var ref = el.querySelectorAll('.ABU-refmap a'); if (!ref.length) { var bg = el.querySelector('.post'); bg.style.backgroundColor = '#fbfb9d'; } });
(проверьте, что на сайте латинские буквы не заменены на кирилицу).
После этого сохраните закладку. Теперь при нажатии на эту кнопку запустится скрипт в контексте страницы и подсветит неотвеченные посты желтым.
В хроме работает легко, а вот как этим в лисе пользоваться что-то не понял сразу. В любом случае спасибо - крутая штука.
В шапке есть задача на Студентов, где как раз полно советов по этой теме.
>- Далее простая, но полезная задача сделать список студентов, в ней много полезных советов: https://github.com/codedokode/pasta/blob/master/student-list.md
С помощью протокола OAuth2.
Я создал компанию ООО "Вектор" в которой департаменты, в которых работают работники, которые работают в депортаментах, в которых работают работники, которые... ну в общем ты понял. Что то рекурсивное вышло. Незнаю насколько верно так делать.
У меня не сильно запутано. Достаточно ли комментариев натыкал для ясности?
Времени потрачено на эту небольшую задачку, мать чесная! Если столько времени вектор ковырл, боюсь что даже маленький сайтик буду годы делать(если до этого смогу дойти).
Там ещё ideon.com жалуется на str_repeat() и mb_strlen(). Ни чего с этим поделать не могу. На компе с апачем нет ни каких проблем. Пришлось с русского на английский текст всё заменить и stlen() испльзовать.
И ещё смотрю как фреймворки написаны голова взрывается что сильно запутано. Пока разбираю одну часть, успеваю забыть для чего она предназначена. Как их читать что б разобраться?
на 65 строке почему не return $this->professions ? Сразу за ним в следующем методе getData почему бы просто не возвращать список департаментов, а уже в классе рапорта гетами выводить содержимое?
>>64112
https://ideone.com/rn2Js5
Ты смотрика и вправду так можно. Спасибо за подсказку.
Всё было так потому что функции я не сразу написал так как она есть. Несколько раз там переправлял логику. Опыта видать мало. Ну и так получилась что образовались бесполезные конструкции. На которые не обратил внимание или забыл почистить.
>>64128
Не ОП, но замечания внесу.
>Я создал компанию ООО "Вектор" в которой департаменты, в которых работают работники, которые работают в депортаментах, в которых работают работники, которые... ну в общем ты понял. Что то рекурсивное вышло. Незнаю насколько верно так делать.
Это имело бы смысл в случае если бы сущности представляли структуру денормализованной таблицы в базе данных, для ускорения выполнения запроса. Но, в нашем случае, база данных не используется, поэтому в этом нет необходимости.
Подробней о денормализации, если интересно:
https://ru.wikipedia.org/wiki/Денормализация
https://ruhighload.com/Денормализация+данных
>У меня не сильно запутано. Достаточно ли комментариев натыкал для ясности?
Наличие комментариев - плохая практика. Код должен быть легко читаемым и интуитивно понятным. Если где-то появилась необходимость в комментариях, то, скорее всего, значит что где-то допущена ошибка.
* Исключение: Аннотации для составления документации и т.п.
>И ещё смотрю как фреймворки написаны голова взрывается что сильно запутано. Пока разбираю одну часть, успеваю забыть для чего она предназначена. Как их читать что б разобраться?
Приходит с практикой. Для начала советую написать пару собственных приложений на этих же фреймворках, чтобы иметь представление о том как это будет работать в конечном итоге.
Но ты можешь меня не слушать и сразу параллельно учиться читать код - лишнем не будет.
https://ideone.com/rn2Js5
Небольшие придирки к оформлению кода:
>class Report{
>Открывающие фигурные скобки классов НЕОБХОДИМО переносить на следующую строку, а закрывающие фигурные скобки переносить на следующую строку после тела.
>public function writeTable(Company $company){
>public function pushDepartmen(Department $department){
>и т.д.
>НЕДОПУСТИМО объявлять методы с пробелом после названия метода. Открывающую фигурную скобку НЕОБХОДИМО располагать на отдельной строке; закрывающую фигурную скобку НЕОБХОДИМО располагать на следующей строке после тела метода. НЕДОПУСТИМО оставлять пробел после открывающей круглой скобки и перед закрывающей.
>$departmentsCompany = $company->getDepartments();
Здесь правильнее было бы написать $departmentsOfCompany или $companyDepartments. Или если никакие другие Департаменты не используются, то можно написать просто $departments.
>public function createEmloye
Название функции написано с опечаткой.
Везде employee написано с одной e на конце.
https://github.com/samdark/fig-standards-ru/blob/master/accepted/ru/PSR-1-basic-coding-standard.md
https://github.com/samdark/fig-standards-ru/blob/master/accepted/ru/PSR-2-coding-style-guide.md
>public function __construct(string $name, array $d, Company $company)
Сразу не понятно что за параметр $d
Далее по коду идёт конструкция перебора сотрудников, которая является не очевидным действием. По моему ощущению кажется, что лучше отдельно добавлять босса и отдельно добавлять сотрудников, или сделать у сущности Сотрудника поле isBoss, и далее выполнять работу с боссом исходя из этого свойства.
>public function createEmloye(string $professionName, int $rangEmploye, Department $department){
Департамент не должен создавать сотрудников, а только добавлять их.
>$professionList = $this->company->getProfessionList();
Список кодов профессий совершенно ни к чему.
>//создаются список профессий востребованных в этой компании b
>$manager = new Manager(); // 'MN'
>$marketer = new Marketer(); // 'MR'
>$engineer = new Engineer(); // 'EN'
>$analyst = new Analyst(); // 'AN'
>
>//все профессии заталкиваются в эту саму компанию
>$company->pushProfession($manager);
>$company->pushProfession($marketer);
>$company->pushProfession($engineer);
>$company->pushProfession($analyst);
Вместо этого должен создаваться массив сотрудников с данными сущностями сотрудников и передаваться в Департамент.
>class Employe{
private $profession;
private $employeLevel;
private $department;
>>64128
Не ОП, но замечания внесу.
>Я создал компанию ООО "Вектор" в которой департаменты, в которых работают работники, которые работают в депортаментах, в которых работают работники, которые... ну в общем ты понял. Что то рекурсивное вышло. Незнаю насколько верно так делать.
Это имело бы смысл в случае если бы сущности представляли структуру денормализованной таблицы в базе данных, для ускорения выполнения запроса. Но, в нашем случае, база данных не используется, поэтому в этом нет необходимости.
Подробней о денормализации, если интересно:
https://ru.wikipedia.org/wiki/Денормализация
https://ruhighload.com/Денормализация+данных
>У меня не сильно запутано. Достаточно ли комментариев натыкал для ясности?
Наличие комментариев - плохая практика. Код должен быть легко читаемым и интуитивно понятным. Если где-то появилась необходимость в комментариях, то, скорее всего, значит что где-то допущена ошибка.
* Исключение: Аннотации для составления документации и т.п.
>И ещё смотрю как фреймворки написаны голова взрывается что сильно запутано. Пока разбираю одну часть, успеваю забыть для чего она предназначена. Как их читать что б разобраться?
Приходит с практикой. Для начала советую написать пару собственных приложений на этих же фреймворках, чтобы иметь представление о том как это будет работать в конечном итоге.
Но ты можешь меня не слушать и сразу параллельно учиться читать код - лишнем не будет.
https://ideone.com/rn2Js5
Небольшие придирки к оформлению кода:
>class Report{
>Открывающие фигурные скобки классов НЕОБХОДИМО переносить на следующую строку, а закрывающие фигурные скобки переносить на следующую строку после тела.
>public function writeTable(Company $company){
>public function pushDepartmen(Department $department){
>и т.д.
>НЕДОПУСТИМО объявлять методы с пробелом после названия метода. Открывающую фигурную скобку НЕОБХОДИМО располагать на отдельной строке; закрывающую фигурную скобку НЕОБХОДИМО располагать на следующей строке после тела метода. НЕДОПУСТИМО оставлять пробел после открывающей круглой скобки и перед закрывающей.
>$departmentsCompany = $company->getDepartments();
Здесь правильнее было бы написать $departmentsOfCompany или $companyDepartments. Или если никакие другие Департаменты не используются, то можно написать просто $departments.
>public function createEmloye
Название функции написано с опечаткой.
Везде employee написано с одной e на конце.
https://github.com/samdark/fig-standards-ru/blob/master/accepted/ru/PSR-1-basic-coding-standard.md
https://github.com/samdark/fig-standards-ru/blob/master/accepted/ru/PSR-2-coding-style-guide.md
>public function __construct(string $name, array $d, Company $company)
Сразу не понятно что за параметр $d
Далее по коду идёт конструкция перебора сотрудников, которая является не очевидным действием. По моему ощущению кажется, что лучше отдельно добавлять босса и отдельно добавлять сотрудников, или сделать у сущности Сотрудника поле isBoss, и далее выполнять работу с боссом исходя из этого свойства.
>public function createEmloye(string $professionName, int $rangEmploye, Department $department){
Департамент не должен создавать сотрудников, а только добавлять их.
>$professionList = $this->company->getProfessionList();
Список кодов профессий совершенно ни к чему.
>//создаются список профессий востребованных в этой компании b
>$manager = new Manager(); // 'MN'
>$marketer = new Marketer(); // 'MR'
>$engineer = new Engineer(); // 'EN'
>$analyst = new Analyst(); // 'AN'
>
>//все профессии заталкиваются в эту саму компанию
>$company->pushProfession($manager);
>$company->pushProfession($marketer);
>$company->pushProfession($engineer);
>$company->pushProfession($analyst);
Вместо этого должен создаваться массив сотрудников с данными сущностями сотрудников и передаваться в Департамент.
>class Employe{
private $profession;
private $employeLevel;
private $department;
>Каждый джавист говорил про неявную типизацию в PHP
про динамическую типизацию. неявная облегчает жизнь во многих случаях auto в с++, var в c#, и теперь var в джаве
da
Я не знаю как это отправилось, но ладно.
Продолжу.
>class Employe{
>private $profession;
>private $employeLevel;
>private $department;
>abstract class Profession{
> private $name;
> private $moneyRate;
> private $coffeeRate;
>Class Manager Extends Profession{
> private $name = 'MN';
> private $reportListCount = 200; //Манагер делает 200 листов отчёта
> private $moneyRate = 500;
> private $coffeeRate = 20;
Профессии должны наследоваться от класса Employee, и класс Employee должен быть абстрактным.
>private $reportListCount
Правильнее будет назвать это свойство $documentsCount или просто $documents.
Абстрактный класс тоже должен содержать это свойство, и в его наследниках количество любых типов отчетов должно храниться в этом свойстве абстрагируемся в задаче от типов отчетов.
>public function getSalary(){
>public function getCoffee()
>public function getListCount(){
У этого метода класса Department, лучше написать название getTotal...()
>$rateLevel = $this->employeLevel0.25 + 0.75
>return $rateMoneyProfession$rateLevel*$bossRate;
>и т.д.
Выражения проще читать, если перед и после оператором стоит пробел.
>$bossRate
Лучше назвать проще $rate
>>public function createEmloye(string $professionName, int $rangEmploye, Department $department){
>Департамент не должен создавать сотрудников, а только добавлять их.
Также, забыл добавить, что сотрудники должны создаваться при инициализации кода, т.е. там где создается Департамент.
$employees[] = new Manager($rang = 3, $boss = true);
$employees[] = new Engineer($rang = 1);
...
$department = new Department($employees);
Пока на этом всё.
Чувствую себя свободно задавать любые вопросы, если что-то не понятно.
Я не знаю как это отправилось, но ладно.
Продолжу.
>class Employe{
>private $profession;
>private $employeLevel;
>private $department;
>abstract class Profession{
> private $name;
> private $moneyRate;
> private $coffeeRate;
>Class Manager Extends Profession{
> private $name = 'MN';
> private $reportListCount = 200; //Манагер делает 200 листов отчёта
> private $moneyRate = 500;
> private $coffeeRate = 20;
Профессии должны наследоваться от класса Employee, и класс Employee должен быть абстрактным.
>private $reportListCount
Правильнее будет назвать это свойство $documentsCount или просто $documents.
Абстрактный класс тоже должен содержать это свойство, и в его наследниках количество любых типов отчетов должно храниться в этом свойстве абстрагируемся в задаче от типов отчетов.
>public function getSalary(){
>public function getCoffee()
>public function getListCount(){
У этого метода класса Department, лучше написать название getTotal...()
>$rateLevel = $this->employeLevel0.25 + 0.75
>return $rateMoneyProfession$rateLevel*$bossRate;
>и т.д.
Выражения проще читать, если перед и после оператором стоит пробел.
>$bossRate
Лучше назвать проще $rate
>>public function createEmloye(string $professionName, int $rangEmploye, Department $department){
>Департамент не должен создавать сотрудников, а только добавлять их.
Также, забыл добавить, что сотрудники должны создаваться при инициализации кода, т.е. там где создается Департамент.
$employees[] = new Manager($rang = 3, $boss = true);
$employees[] = new Engineer($rang = 1);
...
$department = new Department($employees);
Пока на этом всё.
Чувствую себя свободно задавать любые вопросы, если что-то не понятно.
Он берёт содержимое файла и преобразует в массив. Затем этот массив ты можешь изменить как тебе угодно, и далее сохранить в этот же файл.
Ознакомься так же с функцией https://secure.php.net/manual/ru/function.file-get-contents.php
Она преобразует содержимое файла в строку.
Я еще не дочитав дотуда решил написать свой, получилось это: https://ideone.com/w3PoNi
Вопрос, не логичнее ли мое решение в том смысле, что я в классах потомках наследую от абстрактного класса общие поля( каждый вопрос имеет вопрос и правильный ответнет не каждый), в то время как у ОПа в классе NumbericQuestion переопределяется поле для ответа, а в классе ChoiceQuestion - поле для правильного ответа?
Надеюсь не косноязычно обьяснил
А где он у тебя находится сейчас?
Можешь использовать встроенный в пхп веб-сервер, но тогда не сможешь так просто использовать mod_rewrite. Если не хочешь ставить апач на пеку, то попробуй Vagrant.
Более того, именно в этой категории ставится сервер, облако и все что связано с сетью.
Надеюсь помог.
выложил сюда: https://github.com/7Y2RPXK3ETDCNRDD/webpaint
скажите что у меня так и не так.
public function getImagesList() {} или
public static function getImagesList() {}? В чём разница в использовании static конкретно для синглтона?
>>64325
Вектор небольшие доделки на сегодня. Остальное завтра попробую доделать. https://ideone.com/VWL6NT
Спасибо за ссылки на денормализацию.
>Помните, при дублировании данных вырастит количество записей
А то прикинул на глаз чем больше ссылок и тем легче доставать данные(ЛОЛ). Сча всё нормально переделаю.
>Профессии должны наследоваться от класса Employee, и класс Employee должен быть абстрактным.
Професси наследуются от абстрактного класса Profession. а класс Employee это сотрудник.
Мне кажеться это совсем разные сущности. Вася - это Вася, а его - профессия это его профессия, поправьте если ошибаюсь.
>Наличие комментариев - плохая практика. Код должен быть легко читаемым и интуитивно понятным.
Буду стараться
>Правильнее будет назвать это свойство $documentsCount или просто $documents. Абстрактный класс тоже должен содержать это свойство, и в его наследниках количество любых типов отчетов должно храниться в этом свойстве абстрагируемся в задаче от типов отчетов
Хорошо, переделаю. Но меня смутило то, что по условию задачи одни профессионалы создают отчёты, другие чертежи, третьи планы. Надо ОПа спросить что там имелось в виду(я наверно сам себе лишнего допридумал).
вот ещё вопрос. Тут в примерах в абстрактной функции обьявляются публичные методы. И они вроде как наследуются. http://php.net/manual/ru/language.oop5.abstract.php
Я объявил "public function getDocumentsCount()" в "abstract class Profession" и этот метод у нследников не заработал. Пришлось в каждом наследнике одну и ту же функцию писать.
>>64325
Вектор небольшие доделки на сегодня. Остальное завтра попробую доделать. https://ideone.com/VWL6NT
Спасибо за ссылки на денормализацию.
>Помните, при дублировании данных вырастит количество записей
А то прикинул на глаз чем больше ссылок и тем легче доставать данные(ЛОЛ). Сча всё нормально переделаю.
>Профессии должны наследоваться от класса Employee, и класс Employee должен быть абстрактным.
Професси наследуются от абстрактного класса Profession. а класс Employee это сотрудник.
Мне кажеться это совсем разные сущности. Вася - это Вася, а его - профессия это его профессия, поправьте если ошибаюсь.
>Наличие комментариев - плохая практика. Код должен быть легко читаемым и интуитивно понятным.
Буду стараться
>Правильнее будет назвать это свойство $documentsCount или просто $documents. Абстрактный класс тоже должен содержать это свойство, и в его наследниках количество любых типов отчетов должно храниться в этом свойстве абстрагируемся в задаче от типов отчетов
Хорошо, переделаю. Но меня смутило то, что по условию задачи одни профессионалы создают отчёты, другие чертежи, третьи планы. Надо ОПа спросить что там имелось в виду(я наверно сам себе лишнего допридумал).
вот ещё вопрос. Тут в примерах в абстрактной функции обьявляются публичные методы. И они вроде как наследуются. http://php.net/manual/ru/language.oop5.abstract.php
Я объявил "public function getDocumentsCount()" в "abstract class Profession" и этот метод у нследников не заработал. Пришлось в каждом наследнике одну и ту же функцию писать.
Чет не похоже чтобы он запрос делал локалке, я думаю ему страницу нужно отобразить.
https://github.com/mlmn/vector.loc
Что написано в /etc/apache2/apache2.conf и /etc/apache2/sites-available/000-default.conf?
>Професси наследуются от абстрактного класса Profession. а класс Employee это сотрудник.
>Мне кажеться это совсем разные сущности. Вася - это Вася, а его - профессия это его профессия, поправьте если ошибаюсь.
Инженер тоже является Сотрудником и, соответственно, должен наследоваться от соответствующего класса.
Класс Профессий является не нужным, и нарушает принцип KISS Верно же? т.к. вносит в программу избыточные знания о программе, которые нужно знать перед тем как с ней работать.
Код пишется не для машин, а для людей, которые в будущем будут его читать и работать с ним.
https://ru.wikipedia.org/wiki/KISS_(принцип)
>>Правильнее будет назвать это свойство $documentsCount или просто $documents. Абстрактный класс тоже должен содержать это свойство, и в его наследниках количество любых типов отчетов должно храниться в этом свойстве абстрагируемся в задаче от типов отчетов
>Хорошо, переделаю. Но меня смутило то, что по условию задачи одни профессионалы создают отчёты, другие чертежи, третьи планы. Надо ОПа спросить что там имелось в виду(я наверно сам себе лишнего допридумал).
Конечно, в реальной задаче могут быть документы разного типа, но в аншей учебной задаче можно абстрагироваться от этого и иметь только одно свойство документы. К тому же, в результирующей таблице важно только это. В конечном итоге, цель задачи научить тебя подходу ООП, а не тонкостям вычисления свойств, которые в итоге придут к тебе сами.
>вот ещё вопрос. Тут в примерах в абстрактной функции обьявляются публичные методы. И они вроде как наследуются. http://php.net/manual/ru/language.oop5.abstract.php
>
>Я объявил "public function getDocumentsCount()" в "abstract class Profession" и этот метод у нследников не заработал.
Покажи код.
>protected $professions = array();//массив профессий
Как я уже говорил, массив профессий является лишним.
>public function createDepartment(string $name, array $employeesData)
Компания не должна создавать а только добавлять Департамент.
В нашем случае, Департамент проще создавать самому при инициализации кода.
$company = new Company();
$department = new Department(...);
$company->addDepartment($department);
Возможно, созданием Департамента должен заниматься отдельный класс DepartmentBuilder.
https://designpatternsphp.readthedocs.io/ru/latest/Creational/Builder/README.html
>public function createEmploye(string $professionName, int $rang, string $isBoss = "NOTBOSS")
Компания не должна создавать сотрудника. Это является нарушением одного из принципов SOLID - Single Responsibility Principle.
Можно только добавлять его в классе Департамента, либо создавать с помощью класса EmployeeBuilder.
https://ru.wikipedia.org/wiki/SOLID_(объектно-ориентированное_программирование)
https://ru.wikipedia.org/wiki/Принцип_единственной_ответственности
https://blog.byndyu.ru/2009/10/solid.html
https://blog.byndyu.ru/2009/10/blog-post.html
В остальном, те же самые замечания.
И как всегда,
Чувствуй себя свободно задавать вопросы.
>Професси наследуются от абстрактного класса Profession. а класс Employee это сотрудник.
>Мне кажеться это совсем разные сущности. Вася - это Вася, а его - профессия это его профессия, поправьте если ошибаюсь.
Инженер тоже является Сотрудником и, соответственно, должен наследоваться от соответствующего класса.
Класс Профессий является не нужным, и нарушает принцип KISS Верно же? т.к. вносит в программу избыточные знания о программе, которые нужно знать перед тем как с ней работать.
Код пишется не для машин, а для людей, которые в будущем будут его читать и работать с ним.
https://ru.wikipedia.org/wiki/KISS_(принцип)
>>Правильнее будет назвать это свойство $documentsCount или просто $documents. Абстрактный класс тоже должен содержать это свойство, и в его наследниках количество любых типов отчетов должно храниться в этом свойстве абстрагируемся в задаче от типов отчетов
>Хорошо, переделаю. Но меня смутило то, что по условию задачи одни профессионалы создают отчёты, другие чертежи, третьи планы. Надо ОПа спросить что там имелось в виду(я наверно сам себе лишнего допридумал).
Конечно, в реальной задаче могут быть документы разного типа, но в аншей учебной задаче можно абстрагироваться от этого и иметь только одно свойство документы. К тому же, в результирующей таблице важно только это. В конечном итоге, цель задачи научить тебя подходу ООП, а не тонкостям вычисления свойств, которые в итоге придут к тебе сами.
>вот ещё вопрос. Тут в примерах в абстрактной функции обьявляются публичные методы. И они вроде как наследуются. http://php.net/manual/ru/language.oop5.abstract.php
>
>Я объявил "public function getDocumentsCount()" в "abstract class Profession" и этот метод у нследников не заработал.
Покажи код.
>protected $professions = array();//массив профессий
Как я уже говорил, массив профессий является лишним.
>public function createDepartment(string $name, array $employeesData)
Компания не должна создавать а только добавлять Департамент.
В нашем случае, Департамент проще создавать самому при инициализации кода.
$company = new Company();
$department = new Department(...);
$company->addDepartment($department);
Возможно, созданием Департамента должен заниматься отдельный класс DepartmentBuilder.
https://designpatternsphp.readthedocs.io/ru/latest/Creational/Builder/README.html
>public function createEmploye(string $professionName, int $rang, string $isBoss = "NOTBOSS")
Компания не должна создавать сотрудника. Это является нарушением одного из принципов SOLID - Single Responsibility Principle.
Можно только добавлять его в классе Департамента, либо создавать с помощью класса EmployeeBuilder.
https://ru.wikipedia.org/wiki/SOLID_(объектно-ориентированное_программирование)
https://ru.wikipedia.org/wiki/Принцип_единственной_ответственности
https://blog.byndyu.ru/2009/10/solid.html
https://blog.byndyu.ru/2009/10/blog-post.html
В остальном, те же самые замечания.
И как всегда,
Чувствуй себя свободно задавать вопросы.
Изучил html, css, javascript. Имел честь знакомства и написания простых алгоритмов сортировок и обхода деревьев, а так же всяких списков на C++, так же имел честь познакомиться с java, да и на C# немного работал в одном проекте. В общем то и на PHP как то начинал, но забил на программирование и не помню уже php, так как там синтаксис отличный от вышеперечисленных яп.
Подскажите пожалуйста сайт где можно изучить php, но без воды для совсем новичков, где нет объяснений что такое html и всего такого. Хочу чтобы было все четко, кратко и по теме.
И еще не помешала бы информация по архитектуре веб-приложений (mvc, mvvm и остальные, о которых я не знаю), потому что я хочу разбираться в том как устроен готовый фреймворк типа Laravel. Спасибо!
бамп
https://jsfiddle.net/sxc20ngx/
> Класс Профессий является не нужным, вносит в программу избыточные знания о программе, которые нужно знать перед тем как с ней работать.
Эх, а хотелось всё так стойно реализовать. Но ты прав, этого в условии задачи нет, а значит лишне.
Я объявил "public function getDocumentsCount()" в "abstract class Profession" и этот метод у наследников не заработал...
>Покажи код.
вот примерно такой код https://ideone.com/YKA1Pn
как правильно написать, так что б дочерний класс давал свои переменные, а не переменные абстрактного класса? Увы не нагуглил.
Адрес найти не может.
> И ещё смотрю как фреймворки написаны голова взрывается что сильно запутано. Пока разбираю одну часть, успеваю забыть для чего она предназначена. Как их читать что б разобраться?
Попробуй рисовать диаграмму классов на бумаге или где-то еще. Какой класс от какого наследуется, что в себе содержит, какие объекты порождает. Попробуй разобраться, за что отвечает каждый класс и что представляет его объект.
По коду:
> private function padLeft($string, $length)
Если ты используешь PHP7 (давно пора), то в тайп-хинтах можно писать string, int и так далее. Также, можно указывать тип возвращаемого функцией значения. Изучи мануал и применяй это в коде:
- http://php.net/manual/ru/functions.arguments.php#functions.arguments.type-declaration
- http://php.net/manual/ru/functions.returning-values.php
Это сделает код более понятным и позволит раньеш обнаруживать ошибки.
> $length - strlen($string)
Надо использовать mb_strlen, так как strlen не работает с кирилицей в utf-8. https://github.com/codedokode/pasta/blob/master/php/strings-utf8.md
Оформление не очень аккуратное, если вдруг ты пишешь код прямо на ideone, то переходи на редактор кода или IDE, где это делать удобнее для больших программ. Ну и освой форматирование кода.
> public function getProfessionList(){
> $professionList = array();
> foreach ($this->professions as $value) {
> $professionList[] = $value;
Это копирование массива? Массивы и так копируются, ты мог бы написать rпросто eturn $this->professions и это вернет копию массива.
> public function getData(){
> $companyData = array();
Эта функция ведь нужна только для построения отчета и больше нигде не нужна. Значит, ее логичнее было бы поместить в класс Report - это не задача Компании генерировать данные для отчетов. А в класс Company помещать методы, которые могут быть полезны в разных случаях, методы общего назначения. А еще, если посмотреть, этот метод не нужен, так как Report мог бы сам брать эти данные, вызывать getEmployeeCount и сразу выводить, без промежуточных массивов.
Насчет ссылок между объектами. У тебя они двунаправленные - от Company к Department и наоборот, от Department к Company. Такие двунаправленные связи сложнее в использовании из-за того, что надо их синхронизировать - когда мы добавляем Департамент, мы ставим в него ссылку на Компанию, а если вдруг удаляем, то удаляем и ссылку. И хотя их можно использовать, но эта задача решается без них и код был бы проще.
Ну например, у тебя в Department есть ссылка на Company, но она никак не используется.
Дальше, насчет добавления работников. У тебя сделано так, что добавить их можно только в конструкторе и только как массив параметров. Но это выглядит как переусложнение - удобнее просто сделать метод вроде addEmployee(Employee $e) и может быть fireEmployee(Employee $e) - он более универсальный и позволяет передать любой объект с любыми настройками (а у тебя возможности ограничены. Например, нельзя создать класс-наследник Employee и передать его объект в Департамент). Ты тут возлагаешь на Департамент лишнюю обязанность по созданию Работников, хотя проще было бы сделать систему, когда в Департамент можно увольнять или нанимать уже существующих работников.
И тогда тебе не понадобится в Департаменте ссылка на Компанию и не надо получать из нее список профессий.
> createEmloye
Постарайся избегать опечаток и быть более внимательным. Правильно пишется employee.
Далее, ты хранишь босса в отдельном поле. Но разве босс сам не является сотрудником? Не будет ли из-за этого сложностей?
> public function isBoss(){
> $boss = $this->department->getBoss();
Вот здесь тоже не очень удачный момент. Мы вынуждены хранить ссылку на департамент, чтобы узнать, босс мы или нет. В такой ситуации лучше поступить по-другому, есть разные варианты:
- убрать метод isBoss из Работника и перенести его в Департамент как isBoss(Employee $e). Пусть Департамент отвечает, кто в нем Босс.
- сделать в Работнике свойство boss (true/false) и убрать в Департаменте свойство boss.
> //расчёт зарплаты сотрудника
> public function getSalary()
> $rateMoneyProfession = $this->profession->getMoneyRate(); //узнаём коэфициент зарплаты для его професси
У тебя здесь будут сложности, когда надо будет менять зарплату индивидуально отдельным сотрудникам.
> Class Manager Extends Profession{
> private $reportListCount = 200;
Проще было не делать эти поля, а просто написать
> public function getListRate()
> {
> return 200;
> }
> abstract class Profession{
> private $name;
Это поле не имеет никакого смысла, так как оно видно только в этом классе, не в наследниках, и никак не используется.
> foreach ($professionList as $profession) {
> //создает работника необходимой профессии.
> if ($profession->getName() == $professionName) {
Если передано неверное название профессии, надо сигнализировать об ошибке. Иначе она может остаться незамеченной.
> У меня не сильно запутано. Достаточно ли комментариев натыкал для ясности?
Достаточно.
> Времени потрачено на эту небольшую задачку,
С опытом ты начнешь интуитивно понимать ООП, я надеюсь.
> Там ещё ideon.com жалуется на str_repeat() и mb_strlen().
да, это его проблема, надо использовать другие сервисы тогда. Гуглятся по run php online. Например, можно попробовать repl.it
Насчет отдельного класса профессии - это допустимо. Ну то есть есть сущность Работник, а есть сущность Профессия (хотя у тебя правильнее будет сказать Должность - так как в разных компаниях одна и та же профессия может по-разному оплачиваться). Это позволяет делать интересные вещи - Работник может менять Профессию, или даже иметь несколько Профессий. Хотя, если переименовать ее в Должность, то конечно несколько Должностей занимать работник не может. Но может их менять.
Также, твой подход позволяет централизованно менять во всей Компании оплату за определенную Должность.
Есть еще вариант, когда мы не делаем Профессии, а просто делаем базовый класс Работник и от него наследуем Инженер, Менеджер и тд. Этот вариант имеет тот недостаток, что поменять профессию тут невозможно.
> И ещё смотрю как фреймворки написаны голова взрывается что сильно запутано. Пока разбираю одну часть, успеваю забыть для чего она предназначена. Как их читать что б разобраться?
Попробуй рисовать диаграмму классов на бумаге или где-то еще. Какой класс от какого наследуется, что в себе содержит, какие объекты порождает. Попробуй разобраться, за что отвечает каждый класс и что представляет его объект.
По коду:
> private function padLeft($string, $length)
Если ты используешь PHP7 (давно пора), то в тайп-хинтах можно писать string, int и так далее. Также, можно указывать тип возвращаемого функцией значения. Изучи мануал и применяй это в коде:
- http://php.net/manual/ru/functions.arguments.php#functions.arguments.type-declaration
- http://php.net/manual/ru/functions.returning-values.php
Это сделает код более понятным и позволит раньеш обнаруживать ошибки.
> $length - strlen($string)
Надо использовать mb_strlen, так как strlen не работает с кирилицей в utf-8. https://github.com/codedokode/pasta/blob/master/php/strings-utf8.md
Оформление не очень аккуратное, если вдруг ты пишешь код прямо на ideone, то переходи на редактор кода или IDE, где это делать удобнее для больших программ. Ну и освой форматирование кода.
> public function getProfessionList(){
> $professionList = array();
> foreach ($this->professions as $value) {
> $professionList[] = $value;
Это копирование массива? Массивы и так копируются, ты мог бы написать rпросто eturn $this->professions и это вернет копию массива.
> public function getData(){
> $companyData = array();
Эта функция ведь нужна только для построения отчета и больше нигде не нужна. Значит, ее логичнее было бы поместить в класс Report - это не задача Компании генерировать данные для отчетов. А в класс Company помещать методы, которые могут быть полезны в разных случаях, методы общего назначения. А еще, если посмотреть, этот метод не нужен, так как Report мог бы сам брать эти данные, вызывать getEmployeeCount и сразу выводить, без промежуточных массивов.
Насчет ссылок между объектами. У тебя они двунаправленные - от Company к Department и наоборот, от Department к Company. Такие двунаправленные связи сложнее в использовании из-за того, что надо их синхронизировать - когда мы добавляем Департамент, мы ставим в него ссылку на Компанию, а если вдруг удаляем, то удаляем и ссылку. И хотя их можно использовать, но эта задача решается без них и код был бы проще.
Ну например, у тебя в Department есть ссылка на Company, но она никак не используется.
Дальше, насчет добавления работников. У тебя сделано так, что добавить их можно только в конструкторе и только как массив параметров. Но это выглядит как переусложнение - удобнее просто сделать метод вроде addEmployee(Employee $e) и может быть fireEmployee(Employee $e) - он более универсальный и позволяет передать любой объект с любыми настройками (а у тебя возможности ограничены. Например, нельзя создать класс-наследник Employee и передать его объект в Департамент). Ты тут возлагаешь на Департамент лишнюю обязанность по созданию Работников, хотя проще было бы сделать систему, когда в Департамент можно увольнять или нанимать уже существующих работников.
И тогда тебе не понадобится в Департаменте ссылка на Компанию и не надо получать из нее список профессий.
> createEmloye
Постарайся избегать опечаток и быть более внимательным. Правильно пишется employee.
Далее, ты хранишь босса в отдельном поле. Но разве босс сам не является сотрудником? Не будет ли из-за этого сложностей?
> public function isBoss(){
> $boss = $this->department->getBoss();
Вот здесь тоже не очень удачный момент. Мы вынуждены хранить ссылку на департамент, чтобы узнать, босс мы или нет. В такой ситуации лучше поступить по-другому, есть разные варианты:
- убрать метод isBoss из Работника и перенести его в Департамент как isBoss(Employee $e). Пусть Департамент отвечает, кто в нем Босс.
- сделать в Работнике свойство boss (true/false) и убрать в Департаменте свойство boss.
> //расчёт зарплаты сотрудника
> public function getSalary()
> $rateMoneyProfession = $this->profession->getMoneyRate(); //узнаём коэфициент зарплаты для его професси
У тебя здесь будут сложности, когда надо будет менять зарплату индивидуально отдельным сотрудникам.
> Class Manager Extends Profession{
> private $reportListCount = 200;
Проще было не делать эти поля, а просто написать
> public function getListRate()
> {
> return 200;
> }
> abstract class Profession{
> private $name;
Это поле не имеет никакого смысла, так как оно видно только в этом классе, не в наследниках, и никак не используется.
> foreach ($professionList as $profession) {
> //создает работника необходимой профессии.
> if ($profession->getName() == $professionName) {
Если передано неверное название профессии, надо сигнализировать об ошибке. Иначе она может остаться незамеченной.
> У меня не сильно запутано. Достаточно ли комментариев натыкал для ясности?
Достаточно.
> Времени потрачено на эту небольшую задачку,
С опытом ты начнешь интуитивно понимать ООП, я надеюсь.
> Там ещё ideon.com жалуется на str_repeat() и mb_strlen().
да, это его проблема, надо использовать другие сервисы тогда. Гуглятся по run php online. Например, можно попробовать repl.it
Насчет отдельного класса профессии - это допустимо. Ну то есть есть сущность Работник, а есть сущность Профессия (хотя у тебя правильнее будет сказать Должность - так как в разных компаниях одна и та же профессия может по-разному оплачиваться). Это позволяет делать интересные вещи - Работник может менять Профессию, или даже иметь несколько Профессий. Хотя, если переименовать ее в Должность, то конечно несколько Должностей занимать работник не может. Но может их менять.
Также, твой подход позволяет централизованно менять во всей Компании оплату за определенную Должность.
Есть еще вариант, когда мы не делаем Профессии, а просто делаем базовый класс Работник и от него наследуем Инженер, Менеджер и тд. Этот вариант имеет тот недостаток, что поменять профессию тут невозможно.
> Это имело бы смысл в случае если бы сущности представляли структуру денормализованной таблицы в базе данных, для ускорения выполнения запроса
Не только. Двунаправленные связи есть например в DOM - там родитель имеет ссылку на детей, а дети на родителя. Минус - надо все это поддерживать в согласованном состоянии, плюс - можно ходить по такому дереву в любую сторону.
> Наличие комментариев - плохая практика.
Не соглашусь. Я часто перед классом пишу довольно длинный комментарий про него, про то, как устроена та или иная система, иногда даже с кусочками кода-примерами использования. Ну например, если ты пишешь класс-парсер страницы форума, можно описать в комментарии подробности парсинга, алгоритм, что парсится, что нет и так далее.
Также, можно комментировать какие-то не очевидные вещи или пояснять, почему выбран такой вариант решения.
Вот пример класса с подробными комментариями: https://github.com/symfony/form/blob/master/Form.php (и я бы даже добавил еще).
>>62779
В Яве она все-таки строгая, то есть если ты там пишешь auto или var, или как это называется, то тип там все равно есть, просто ты его не пишешь явно, а его вычисляет компилятор. Это сокращает писанину, но может снизить читаемость.
В PHP же типа может не быть, и в переменной могут по очереди храниться значения разных типов, в функцию они могут передаваться и тд.
>>64325
> Профессии должны наследоваться от класса Employee, и класс Employee должен быть абстрактным.
Не соглашусь. Есть 2 варианта: одна сущность Работник, или отдельно Работник, отдельно Должность. Во втором случае, например, Работник может менять Должность.
Загружаешь содержимое файла в переменную (file_get_contents), затем функциями mb_substr вырезаешь нужные куски и склеиваешь как тебе надо. Сохраняешь обратно (file_put_contents).
Тут есть маленький минус - если ты перезаписываешь исходный файл и что-то сломается в процессе (например, кто-то грохнет программу или отключится питание) - ты получишь испорченный, не дописанный файл. Так как вызов file_put_contents не атомарен и записывает файл не мгновенно, а постепенно в течение какого-то времени. Безопаснее делать перезапись файла атомарно. То есть вместо перезаписи создаем рядом временный файл, а затем вызовом rename переименовываем его в исходный, тем самым атомарно его заменяя. Это безопасно.
>>64584
Можно заморочиться с nginx + php-fpm, можно исопльзовать встроенный в PHP сервер.
>>64591
В твоем варианте есть недостаточек. По идее, поле "правильный ответ" в разных типах вопросах разное. В числовом вопросе оно имеет тип "дробное число" (float) и обозначает число, а в вопросе с выбором это может быть "строка" или "целое число" (int) и оно указывает на номер опции в списке.
Также, это может создать путаницу, так как код должен понимать, что именно хранится в поле и в зависимости от этого по-разному с ним работать.
Как ты заметил, в варианте из учебника эти поля специально названы по-разному, чтобы подчеркнуть, что это разные, не связанные друг с другом поля. Это защищает от ошибок при написании кода. Код, который работает с выбранной опцией не обратится случайно к полю с числовым ответом.
То есть, лучше и безопаснее считать это двумя разными полями и не пытаться объединить в одно.
> у ОПа в классе NumbericQuestion переопределяется поле для ответа,
Правильнее сказать, "добавляется". "переопределяется" это когда поле было в предке и мы меняем его в наследнике.
>>64607
Скорее всего, не запущен веб-сервер. Проверить можно командой ps lax.
Загружаешь содержимое файла в переменную (file_get_contents), затем функциями mb_substr вырезаешь нужные куски и склеиваешь как тебе надо. Сохраняешь обратно (file_put_contents).
Тут есть маленький минус - если ты перезаписываешь исходный файл и что-то сломается в процессе (например, кто-то грохнет программу или отключится питание) - ты получишь испорченный, не дописанный файл. Так как вызов file_put_contents не атомарен и записывает файл не мгновенно, а постепенно в течение какого-то времени. Безопаснее делать перезапись файла атомарно. То есть вместо перезаписи создаем рядом временный файл, а затем вызовом rename переименовываем его в исходный, тем самым атомарно его заменяя. Это безопасно.
>>64584
Можно заморочиться с nginx + php-fpm, можно исопльзовать встроенный в PHP сервер.
>>64591
В твоем варианте есть недостаточек. По идее, поле "правильный ответ" в разных типах вопросах разное. В числовом вопросе оно имеет тип "дробное число" (float) и обозначает число, а в вопросе с выбором это может быть "строка" или "целое число" (int) и оно указывает на номер опции в списке.
Также, это может создать путаницу, так как код должен понимать, что именно хранится в поле и в зависимости от этого по-разному с ним работать.
Как ты заметил, в варианте из учебника эти поля специально названы по-разному, чтобы подчеркнуть, что это разные, не связанные друг с другом поля. Это защищает от ошибок при написании кода. Код, который работает с выбранной опцией не обратится случайно к полю с числовым ответом.
То есть, лучше и безопаснее считать это двумя разными полями и не пытаться объединить в одно.
> у ОПа в классе NumbericQuestion переопределяется поле для ответа,
Правильнее сказать, "добавляется". "переопределяется" это когда поле было в предке и мы меняем его в наследнике.
>>64607
Скорее всего, не запущен веб-сервер. Проверить можно командой ps lax.
Во-первых, скорее всего тебе не нужен синглтон. Это во многом вредный паттерн. Зачем он тебе тут? Что тебе мешает просто создать объект через new? Почему ты решил, что не может быть более 1 экземпляра объекта?
> В чём разница в использовании static конкретно для синглтона?
Никаких особенностей у static в синглтоне нет. static относится к методам, которые принадлежат классу, а не объекту. Такие методы не используют this и их можно вызывать, даже не имея объекта.
>>64908
Плохо, что список должностей заложен в Компании. Не понятно, в чем выгода, а недостаток в том, что нельзя создать компанию с другим набором Должностей.
Опять же, создание Работников лучше вынести из компании и департамента наружу.
> string $isBoss = "NOTBOSS")
Для этого надо использовать тип bool и значения true/false.
Ну и смотри замечания к предыдущей версии программы.
> Хорошо, переделаю. Но меня смутило то, что по условию задачи одни профессионалы создают отчёты, другие чертежи, третьи планы. Надо ОПа спросить что там имелось в виду(я наверно сам себе лишнего допридумал).
Ну там важно только количество листов, эти отчеты все равно никто не читает. Но если строго придираться, то тогда конечно пришлось бы делать разные поля и разные цифры. Не думаю. что это нужно.
> Тут в примерах в абстрактной функции обьявляются публичные методы. И они вроде как наследуются.
В примерах абстрактного класса, ты хотел сказать?
Абстрактный класс никак не запрещает создавать в нем не-абстрактные (конкретные) методы. Абстрактный класс не обязан содержать абстрактные методы. Единственное, что делает слово abstract - помечает класс как "недоделанный" и потому запрещает создавать его объекты.
Так что все должно работать. Покажи код, если не работает.
>>64945
По моему опыту, sphinxQL мощнее и гибче. И по моему, некоторые фичи через АПИ не сделать вообще. Все же язык SQL специально придумывался для поиска данных. Изучи внимательно документацию по обоим и может найдешь различия.
Во-первых, скорее всего тебе не нужен синглтон. Это во многом вредный паттерн. Зачем он тебе тут? Что тебе мешает просто создать объект через new? Почему ты решил, что не может быть более 1 экземпляра объекта?
> В чём разница в использовании static конкретно для синглтона?
Никаких особенностей у static в синглтоне нет. static относится к методам, которые принадлежат классу, а не объекту. Такие методы не используют this и их можно вызывать, даже не имея объекта.
>>64908
Плохо, что список должностей заложен в Компании. Не понятно, в чем выгода, а недостаток в том, что нельзя создать компанию с другим набором Должностей.
Опять же, создание Работников лучше вынести из компании и департамента наружу.
> string $isBoss = "NOTBOSS")
Для этого надо использовать тип bool и значения true/false.
Ну и смотри замечания к предыдущей версии программы.
> Хорошо, переделаю. Но меня смутило то, что по условию задачи одни профессионалы создают отчёты, другие чертежи, третьи планы. Надо ОПа спросить что там имелось в виду(я наверно сам себе лишнего допридумал).
Ну там важно только количество листов, эти отчеты все равно никто не читает. Но если строго придираться, то тогда конечно пришлось бы делать разные поля и разные цифры. Не думаю. что это нужно.
> Тут в примерах в абстрактной функции обьявляются публичные методы. И они вроде как наследуются.
В примерах абстрактного класса, ты хотел сказать?
Абстрактный класс никак не запрещает создавать в нем не-абстрактные (конкретные) методы. Абстрактный класс не обязан содержать абстрактные методы. Единственное, что делает слово abstract - помечает класс как "недоделанный" и потому запрещает создавать его объекты.
Так что все должно работать. Покажи код, если не работает.
>>64945
По моему опыту, sphinxQL мощнее и гибче. И по моему, некоторые фичи через АПИ не сделать вообще. Все же язык SQL специально придумывался для поиска данных. Изучи внимательно документацию по обоим и может найдешь различия.
Ой-ой, смесь PHP и HTML, почитай-ка про шаблоны: https://github.com/codedokode/pasta/blob/master/php/templates.md
У тебя очень сложно понять структуру HTML-кода, так как он раскидан по куче функций. И перемежается с кавычками, echo и другим кодом. Такой код очень тяжело редактировать. Изучи шаблоны.
> static public function pageHeader() {
А не надо тут статический метод использовать, зачем? Используй обычный.
> public function addDepartment(Department $dep) {
> if (!in_array($dep, $this->departments, true)) {
При попытке дважды добавить департамент наверно лучше выкидывать исключение. Чтобы сообщить об ошибке.
> if (is_object($employee) and get_parent_class($employee) == 'Employee') {
То же самое, надо сообщать об ошибке, а не тихо ее игнорировать.
> get_parent_class($employee) == 'Employee')
Лучше использовать instanceof
> $info = new stdClass();
Не надо использовать stdClass. Это как массив (так как нигде не описаны его поля), только плохой, так как с ним не работают функции работы с массивами. Тут лучше либо сделать отдельные методы вроде getTotalSalary(), либо специальный объект CompanyStat где описаны все поля.
> public function __construct($name) {
Если ты используешь PHP7, то можно добавить тайп-хинты вроде string, а также тайп-хинты на возвращаемые функцией значения: public function getName(): string
> if (in_array($employee->getName(), $fireList)) {
Мне кажется, лучше удалять не по имени, а по объекту. Так как объект обладает идентичностью и отличается от всех других объектов. И придумывать дополнительные идентификаторы не надо.
> public function makeLeaderByName($name) {
То же самое, не надо придумывать идентификатор, передавай сам объект.
> public function getTopAnalyst() {
Это очень узкоспециальная функция, нужная только антикризисному комитету. Надо ее перенести в антикризисный комитет, а в департаменте сделать универсальный метод поиска по любым критериям.
> if(get_class($employee) == 'Analyst') {
лучше instanceof
> public function demoteLeader() {
нужен ли этот метод? Лучше наверно сделать метод замены босса. А то у тебя можно департамент без босса оставить.
> public function makeLeaderByName($name) {
> public function promoteLeaderByName($name) {
Одинаковые методы же?
> class Names {
Лучше NameGenerator или NameUtil.
Насчет наследовния. У тебя есть негласное правило, что при наследовании профессии от работника надо задать базовые параметры. Но это никак не документировано и никак не проверяется. Легко забыть это сделать. Чтобы этого избежать, можно использовать абстрактные методы - то есть методы, которые не дописаны в базовом классе и которые обязаны реализовать потомки. Попробуй добавить абстрактные методы вроде getDefaultBaseSalary() и тогда их нельзя будет забыть определить.
> class OrganisationBuilder {
> public $org;
> public $dep;
Вообще, эти поля ведь не нужны, вместо них можно использовать обычные переменные.
> class AntiCrisis {
> private $departments;
Мне кажется это поле не нужно, если у тебя есть компания, ты из нее всегда можешь получить департаменты. Получается дублирование данных.
Отбирать работников для увольнения проще так:
- получаем список кандидатов на увольнение
- сортируем его по приоритету (кто в прервую очередь) с помощью usort + анонимная функция
- с помощью array_slice отрезаем нужное число кандидатов
- увольняем
Это будет читаться лучше, чем твой код с вложенными циклами и брейками.
Также, надо чтобы программа применила все 3 метода и вывела таблицы для сравнения. Для этого надо научиться делать копии (клоны) организации, чтобы работать с ними, не трогая исходную компанию.
Ой-ой, смесь PHP и HTML, почитай-ка про шаблоны: https://github.com/codedokode/pasta/blob/master/php/templates.md
У тебя очень сложно понять структуру HTML-кода, так как он раскидан по куче функций. И перемежается с кавычками, echo и другим кодом. Такой код очень тяжело редактировать. Изучи шаблоны.
> static public function pageHeader() {
А не надо тут статический метод использовать, зачем? Используй обычный.
> public function addDepartment(Department $dep) {
> if (!in_array($dep, $this->departments, true)) {
При попытке дважды добавить департамент наверно лучше выкидывать исключение. Чтобы сообщить об ошибке.
> if (is_object($employee) and get_parent_class($employee) == 'Employee') {
То же самое, надо сообщать об ошибке, а не тихо ее игнорировать.
> get_parent_class($employee) == 'Employee')
Лучше использовать instanceof
> $info = new stdClass();
Не надо использовать stdClass. Это как массив (так как нигде не описаны его поля), только плохой, так как с ним не работают функции работы с массивами. Тут лучше либо сделать отдельные методы вроде getTotalSalary(), либо специальный объект CompanyStat где описаны все поля.
> public function __construct($name) {
Если ты используешь PHP7, то можно добавить тайп-хинты вроде string, а также тайп-хинты на возвращаемые функцией значения: public function getName(): string
> if (in_array($employee->getName(), $fireList)) {
Мне кажется, лучше удалять не по имени, а по объекту. Так как объект обладает идентичностью и отличается от всех других объектов. И придумывать дополнительные идентификаторы не надо.
> public function makeLeaderByName($name) {
То же самое, не надо придумывать идентификатор, передавай сам объект.
> public function getTopAnalyst() {
Это очень узкоспециальная функция, нужная только антикризисному комитету. Надо ее перенести в антикризисный комитет, а в департаменте сделать универсальный метод поиска по любым критериям.
> if(get_class($employee) == 'Analyst') {
лучше instanceof
> public function demoteLeader() {
нужен ли этот метод? Лучше наверно сделать метод замены босса. А то у тебя можно департамент без босса оставить.
> public function makeLeaderByName($name) {
> public function promoteLeaderByName($name) {
Одинаковые методы же?
> class Names {
Лучше NameGenerator или NameUtil.
Насчет наследовния. У тебя есть негласное правило, что при наследовании профессии от работника надо задать базовые параметры. Но это никак не документировано и никак не проверяется. Легко забыть это сделать. Чтобы этого избежать, можно использовать абстрактные методы - то есть методы, которые не дописаны в базовом классе и которые обязаны реализовать потомки. Попробуй добавить абстрактные методы вроде getDefaultBaseSalary() и тогда их нельзя будет забыть определить.
> class OrganisationBuilder {
> public $org;
> public $dep;
Вообще, эти поля ведь не нужны, вместо них можно использовать обычные переменные.
> class AntiCrisis {
> private $departments;
Мне кажется это поле не нужно, если у тебя есть компания, ты из нее всегда можешь получить департаменты. Получается дублирование данных.
Отбирать работников для увольнения проще так:
- получаем список кандидатов на увольнение
- сортируем его по приоритету (кто в прервую очередь) с помощью usort + анонимная функция
- с помощью array_slice отрезаем нужное число кандидатов
- увольняем
Это будет читаться лучше, чем твой код с вложенными циклами и брейками.
Также, надо чтобы программа применила все 3 метода и вывела таблицы для сравнения. Для этого надо научиться делать копии (клоны) организации, чтобы работать с ними, не трогая исходную компанию.
Да, они тут пригодятся.
>>65085
Вообще, у отдельного класса Должность есть свои преимущества.
> Возможно, созданием Департамента должен заниматься отдельный класс DepartmentBuilder.
Да, можно, если поместить туда метод массового создания работников например.
>>65144
Если тебе не нравится учебник в ОП посте, то могу предложить официальный мануал: http://php.net/manual/ru/index.php
> И еще не помешала бы информация по архитектуре веб-приложений (mvc, mvvm и остальные, о которых я не знаю), потому что я хочу разбираться в том как устроен готовый фреймворк типа Laravel. Спасибо!
Открой задание на список студентов в ОП посте. Там несколько страниц комментариев и ссылок, все по веб-приложениям.
>>65373
На мой взгляд, допустимо сделать Должность отдельным классом.
>>65373
private поля видны только в одном классе и не видны в наследнике. Попробуй protected.
>>65484
У тебя указан хост MySQL для соединения, и он не резолвится.
Да, они тут пригодятся.
>>65085
Вообще, у отдельного класса Должность есть свои преимущества.
> Возможно, созданием Департамента должен заниматься отдельный класс DepartmentBuilder.
Да, можно, если поместить туда метод массового создания работников например.
>>65144
Если тебе не нравится учебник в ОП посте, то могу предложить официальный мануал: http://php.net/manual/ru/index.php
> И еще не помешала бы информация по архитектуре веб-приложений (mvc, mvvm и остальные, о которых я не знаю), потому что я хочу разбираться в том как устроен готовый фреймворк типа Laravel. Спасибо!
Открой задание на список студентов в ОП посте. Там несколько страниц комментариев и ссылок, все по веб-приложениям.
>>65373
На мой взгляд, допустимо сделать Должность отдельным классом.
>>65373
private поля видны только в одном классе и не видны в наследнике. Попробуй protected.
>>65484
У тебя указан хост MySQL для соединения, и он не резолвится.
Обычно там есть пара вариантов: регистрозависимый и независимый. Соответственно, думай, каким полям что подходит.
В случае с Юникодом collation еще может влиять на сортировку. Дело в том, что в разных странах разные правила сортировки, особенно что касается букв с точками вверху в европейских языках. И надо смотреть, на какую страну ориентирован твой сервис.
Она платная, но вопросы для подготовки есть тут, полезно глянутьF: https://github.com/certificationy/symfony-pack/tree/master/data
Там не только вопросы по Symfony, но и по HTTP, PSR, PHP.
Вкатываюсь в вашу тему и на задачке с кредитом на айфон у меня возник некоторый затык.
Решить я её решил, но мне кажется, что дублирование кода - плохой признак.
https://ideone.com/FWWZPI
Так вот, у меня вопрос...
У меня в условиях дублируется вывод echo.
Если я поставлю вывод после условий, то у меня будет 12 месяцев, т.к. в условии elseif имеется break, соответственно, я выхожу из цикла на 12 месяце, а должен быть и 13, где я буду видеть, что долга нет.
Так вот, как же мне сделать так, чтоб вывод у меня был только один и показывал актуальную информацию по долгу?
Спасибо!
>>64908
Спасибо за советы и ссылки на чтиво. Много прочитал мало усвоил.
Сделал некоторые правки в задачке. Проверьте пожалуйста.
https://repl.it/repls/AcclaimedWhirlwindSoftwareengineer
Решение Антикризисной задачи видится тривиальным. Клонирование компании и изменение клона в соответствии условиям. Потому скорей всего её делать не буду, пойду дальше материал осваивать.
(Проверка на палиндромность)
http://sandbox.onlinephpfunctions.com/code/24d670387948db2802f2fa2669f3c1e13353a412
Можно ли как-то укоротить данную регулярку?
[\s\-]?\d[\s\-]?\d[\s\-]?\d[\s\-]?\d[\s\-]?\d[\s\-]?\d
Она проверяет 6,7 любых цифр между которыми могут быть пробел или тире
Как все просто оказывается, спасибо!
Проверь пожалуйста задачу с кредитом на айпад.
http://sandbox.onlinephpfunctions.com/code/a0aac4898a6cb43f67a26f8864fe396f1f200562
Спасибо!
А нет, сам увидел, что что-то не так...
Функцию то ты никак не использовал
Не правильно. Сумма кредита, проценты, комиссия, плата за открытия счета и ежемесячная выплата должны передаваться в аргументы функции.
https://secure.php.net/manual/ru/functions.arguments.php
Также, программа не должна определять какое из предложений наиболее выгодное, а просто посчитать его. См. скрин как должны выглядеть результаты.
> if ($balanceSoftBank || $balanceHomoCredit || $balanceStrawberryBank < $payment) {
Такое условие означает, если, хотя бы, $balanceSoftBank равен true (см. преобразование в булев тип), или $balanceHomoCredit равен true, или $balanceStrawberryBank меньше чем $payment, то...
Т.е. если, хотя бы, один единственный $balanceSoftBank будет true, то условие выполниться.
Изучи приоритеты операторов ссылка внизу.
https://secure.php.net/manual/ru/language.types.boolean.php#language.types.boolean.casting
https://secure.php.net/manual/ru/language.operators.precedence.php
>$paymentForSoftBank = $balanceSoftBank - $payment + $payment;
Вычитание и последующие прибавление не имеет смысла, т.к. это действие в итоге даст 0.
>$balanceSoftBank -= $paymentForSoftBank;
Это тоже не имеет смысла, т.к. это тоже самое что $balanceSoftBank - $balanceSoftBank, что, опять же, в итоге даст 0.
>$paymentTotalSoftBank += $paymentForSoftBank;
Следовательно, можно было написать просто $paymentTotalSoftBank += $balanceSoftBank, что не является формулой расчета кредита. Если не можешь составить как отнимать от стоимости ежемесячную плату, проценты, комиссию и плату за открытия счета, то попроси подсказку. Хоть ты и должен это сделать самому.
<div>
<input name = 'gender' type="radio" value="male"> Мужской
<input name = 'gender' type="radio" value="female"> Женский
</div>
Я пробую записать значение выбраной кноопки в переменную этим кодом:
var radio = document.getElementsByName('gender');
var gender;
for (var i = 0; i <= radio.length; i++) {
if (radio.checked) {
gender = radio.value;
}
}
но ничего не получается, исполнение проги дальше этого цикла не идёт. Но если в условии вывести значение кнопки алертом:
alert(radio.value);
то всё получается, т.е всё наёбывется именно при попытке аписи в переменную. В чём может быть проблема?
разобрался. Вместо i <= radio.length написал i < radio.length. Хороший тред, ещё зайду.
Пожалуйста, подскажите насколько верно решение и как его можно модифицировать https://regex101.com/r/U8ivvI/1
Если его нет — можно выкатываться?
Каждый раз после рестарта или перезахода в систему просит passphrase от ssh-ключа.
eval $(ssh-agent -s) && ssh-add 'путь'
Помогает только до перезахода-рестарта.
Можно ли как-нибудь перманентно добавить ключ в агент?
Ох, разобрался! Спасибо, анон.
У меня только один вопрос: в функции у тебя есть переменная $totalPayment = 0
Так вот... зачем её объявлять здесь:
function calculateCredit($percent, ... $totalPayment = 0) {
}
Спасибо.
Я задал значение аргумента по умолчанию, потому что изначально количество выплат по всем банкам одинаковое =0.
http://php.net/manual/ru/functions.arguments.php
Листай до значений аргументов по умолчанию.
Тут >>52780 мое решение одобрил ОП, значит все правильно.
Кстати можно было и внутри функции задать эту переменную.
И это кстати, мы почти на одном уровне, можешь оставить свою телегу будем няшиться в дымоход проверять друг другу задачки:3
Зачем тебе мускуль? Сессию не хочешь использовать?
Ну если надо мускуль, то берешь создаешь таблицу. В ней в простейшем варианте например у тебя лежит:
id юзера, id товара.
Когда юзер с id например 1 кликает по ссылке добавить товар_нейм, с id например 100 в корзину, то в таблице с помощью пхп создается запись: 1 - 100
Потом он еще кликает например добавить товар с id 101.
В итоге когда юзер захочет смотреть свои товары, ты делаешь из этой таблицы селект по id юзера как-то так:
select from korzina where user_id = 1;
Получаешь ответочку.
1 - 100
1 - 101
В реальности конечно всё немного не так будет, ты захочешь не просто id селектить, а заджойнишь например еще из таблицы товаров сразу товары по идишнику, что бы вывести в корзине их названия и прочее.
Выводишь юзеру полученную от базы инфу.
Когда юзер захочет очистить корзину, то делаешь так, что бы твой код стирал из таблицы все записи этого юзера
DELETE FROM korzina WHERE user_id = 1;
Ну как-то так.
Не знаю. Но есть ощущение, что ты что-то пытаешься там переусложнить.
Вообще, а нужна ли тебе отдельная СУБД? Не лучше ли использовать встроенную?
>>59523
> ну и еще, тот самый хэдер, у которого высота в процентах не меняет свои размеры при зуме (а ссылки меняют).
Это какой-то странный зум, если он не увеличивает. Не надо так.
Также, тебе надо подучить CSS, и понимать, как работает каждое свойство, а не перебирать их наугад.
>>59573
Для начала, открыть инструменты разработчика (Ctrl + Shift + I) на вкладке Network и перезагрузить страницу. Посмотреть, нет ли там ошибок вроде 404 в процессе загрузки.
Да, мануал запутанный. Наверно, слово "экранирующие символы". "Экранирование" - в данном случае это когда мы перед символом добавляем бекслеш и он, может быть, меняет свое значение. А экранирующий символ - это бекслеш.
Ну например, в регулярных выражениях точка значит "любой символ, кроме перевода строки". А если перед ней поставить бекслеш: \. то это значит просто "символ точки".
Или другой пример: если ты пишешь echo "1\n2", то \n - это комбинация, которая вставляет в строку символ перевода строки. И на экран выводится не бекслеш и буква n, а происходит перевод строки и цифра 2 оказывается на новой строке. Подробнее про это можно прочесть тут http://php.net/manual/ru/language.types.string.php#language.types.string.syntax.double
Функция stripslashes находит в строке все пары вида "бекслеш + любой символ" и удаляет из них бекслеш. Например, \x превращается в x, а \\ превращается просто в \.
Строка '\x\y\\z' превращается в 'xy\z'.
Там в мануале еще упоминается опция magic_quotes_gpc. Эта устаревшая опция, если ее включить, приводила к тому, что в массивах вроде $_GET в строках перед некоторыми символами добавлялись бекслеши. И с помощью stripslashes можно их убрать назад. Эта опция была задумана для борньбы с уязвимостями, но по факту не работала, создавала ложно чувство безопасности (из-за чего на хостингах ее часто включали) и заставляла везде писать этот stripslashes. В общем, была сделана очень глупо и непродуманно.
К безопасности stripslashes не имеет отношения и не делает ничего безопаснее. Вообще, это миф, что можно как-то волшебным образом "очистить" строку от вредных символов. Вредных символов не существует, просто когда ты вставляешь одну строку в другую (например, в SQL запрос или в HTML код) нужно знать, какие символы в SQL или в HTML имеют специальное значение и правильно из заменить/заэкранировать перед вставкой, чтобы они не были восприняты как спецсимволы. Особенно если ты вставляешь пришедшие от пользователя данные (которым доверять нельзя).
> htmlspecialchars
Если ты изучал HTML, то должен знать, зачем.
Как известно, в языке HTML некоторые символы имеют специальное значение. Например, символ < обозначает начало тега (вроде <img>), а символ & позволяет писать мнемоники вроде & copy; (символ копирайта).
Соответственно, если ты хочешь вставить текст в HTML код, то в этом тексте могут быть спецсимволы и они будут восприняты браузером, например, как часть тега, а не выведены на экран. Ну например, может ты хочешь вывести текст "<img>", а не вставить в HTML-код такой тег.
Чтобы избежать этой проблемы, нужно перед вставкой текста в HTML заменить в нем спецсимволы. Функция htmlspecialchars это и делает, и там в мануале указаны 5 символов, которые она заменяет. Ты должен помнить их наизусть, так что не трать время и начинай учить.
Я советую почитать еще про XSS уязвимость, когда ты вставляешь в HTML текст от пользователя (не заменяя спецсимволы) и пользователь таким образом может вставить в твой HTML вредоносные теги. Почитай: https://github.com/codedokode/pasta/blob/master/security/xss.md
Да, мануал запутанный. Наверно, слово "экранирующие символы". "Экранирование" - в данном случае это когда мы перед символом добавляем бекслеш и он, может быть, меняет свое значение. А экранирующий символ - это бекслеш.
Ну например, в регулярных выражениях точка значит "любой символ, кроме перевода строки". А если перед ней поставить бекслеш: \. то это значит просто "символ точки".
Или другой пример: если ты пишешь echo "1\n2", то \n - это комбинация, которая вставляет в строку символ перевода строки. И на экран выводится не бекслеш и буква n, а происходит перевод строки и цифра 2 оказывается на новой строке. Подробнее про это можно прочесть тут http://php.net/manual/ru/language.types.string.php#language.types.string.syntax.double
Функция stripslashes находит в строке все пары вида "бекслеш + любой символ" и удаляет из них бекслеш. Например, \x превращается в x, а \\ превращается просто в \.
Строка '\x\y\\z' превращается в 'xy\z'.
Там в мануале еще упоминается опция magic_quotes_gpc. Эта устаревшая опция, если ее включить, приводила к тому, что в массивах вроде $_GET в строках перед некоторыми символами добавлялись бекслеши. И с помощью stripslashes можно их убрать назад. Эта опция была задумана для борньбы с уязвимостями, но по факту не работала, создавала ложно чувство безопасности (из-за чего на хостингах ее часто включали) и заставляла везде писать этот stripslashes. В общем, была сделана очень глупо и непродуманно.
К безопасности stripslashes не имеет отношения и не делает ничего безопаснее. Вообще, это миф, что можно как-то волшебным образом "очистить" строку от вредных символов. Вредных символов не существует, просто когда ты вставляешь одну строку в другую (например, в SQL запрос или в HTML код) нужно знать, какие символы в SQL или в HTML имеют специальное значение и правильно из заменить/заэкранировать перед вставкой, чтобы они не были восприняты как спецсимволы. Особенно если ты вставляешь пришедшие от пользователя данные (которым доверять нельзя).
> htmlspecialchars
Если ты изучал HTML, то должен знать, зачем.
Как известно, в языке HTML некоторые символы имеют специальное значение. Например, символ < обозначает начало тега (вроде <img>), а символ & позволяет писать мнемоники вроде & copy; (символ копирайта).
Соответственно, если ты хочешь вставить текст в HTML код, то в этом тексте могут быть спецсимволы и они будут восприняты браузером, например, как часть тега, а не выведены на экран. Ну например, может ты хочешь вывести текст "<img>", а не вставить в HTML-код такой тег.
Чтобы избежать этой проблемы, нужно перед вставкой текста в HTML заменить в нем спецсимволы. Функция htmlspecialchars это и делает, и там в мануале указаны 5 символов, которые она заменяет. Ты должен помнить их наизусть, так что не трать время и начинай учить.
Я советую почитать еще про XSS уязвимость, когда ты вставляешь в HTML текст от пользователя (не заменяя спецсимволы) и пользователь таким образом может вставить в твой HTML вредоносные теги. Почитай: https://github.com/codedokode/pasta/blob/master/security/xss.md
https://ideone.com/AiII2I
У меня еще два вопроса:
1. Регулярки что на картинке можно как-то объединить? http://joxi.ru/1A5d3PeiKdBx82
2. В задачке все переменные, кроме регулярки я обозвал $number. Нужно ли было их называть по задаче которую они выполняют? прим. $check $cleaned $matches и т.д.
Это важно?
Но вот стал это тестировать - и не получается. При делении на ноль (например) все мои catch-и игнорируются и скрипт вылетает. Я не понимаю, почему.
Кроме того, как делается наследование эксепшенов? Вот пример: https://github.com/codedokode
Как сделать так, чтобы ошибка, выловленная в самом низу вложенных функций, грамотно была передана самому вышестоящему скрипту и обработана им без вылета скрипта?
>1. Регулярки что на картинке можно как-то объединить? http://joxi.ru/1A5d3PeiKdBx82
Можно если загнать в preg_replace массив
https://ideone.com/B1kr1V
читай!
https://secure.php.net/manual/ru/function.preg-replace.php
>2. В задачке все переменные, кроме регулярки я обозвал $number. Нужно ли было их называть по задаче которую они выполняют?
И так понятно что это за номер. Не имеет особого смысла.
Но не для вот в этой строчки.
$number = preg_match('/^(\+\s?7|8)([-\s()]*\d){10}$/', $number, $matches);
preg_match отвечает на вопрос подходит ли номер регулярке или нет. Она не номер обрабатыват она true\false возвращает.
читай!
https://secure.php.net/manual/ru/function.preg-match.php
Большое спасибо!
Например, чтобы в $_SESSION['hui'], hui был бы массивом, куда я мог бы гетом добавлять новые значения
$_SESSION['hui'] = array();
$_SESSION['hui'][] = 'hyinia1';
$_SESSION['hui'][] = 'hyinia2';
$_SESSION['hui'][] = 'hyinia3';
$_SESSION['hui'][] = 'hyinia4';
Как лучше реализовать строку "Всего"?
Палю фишку. Чтобы сразу отвечали надо прикреплять боевую картиночку, примеры выше.
Это что-то вроде мер безопасности. Пользователи хорошо изолированы друг от друга. Потому, например, mysql и файлы баз данных в ней принадлежат пользователю mysql, чтобы никто не могу получить к ним доступ в обход сервера MySQL.
Так же и тут - Апач запускается от www-data, чтобы в случае взлома он не мог бы получить доступ к файлам других пользователей ОС. А только к тем файлам, к которым ему явно дан доступ. Ну и чтобы пользователи не могли как-то влиять на работу Апача, а только администратор.
Добра за ответ! Я только почему то не понял, когда я допустим создаю папку из пхп скрипта с помощью mkdir и там указываю права 0777 все равно почему то, только owner может в нее что то записывать.
"Как я за 9 месяцев превратился из неофита в разработчика ПО без отрыва от основной работы"
https://m.habrahabr.ru/company/everydaytools/blog/352878/
С помощью цикла вывести:
1×1 = 1
2×2 = 4
...
9x9 = 81
мне нужны 2 переменные? Я упускаю из вида что-то очень простое и важное, блждад.
Все книги по самосовершенствованию, GTD, мотивации, тайм-менеджменту и прочему сводятся к тому, что человек из Беверли-Хиллз советует человеку в Магадане выйти из зоны комфорта.
Калифорнию логичнее сравнивать с одним из двух столичных регионов. Ну и в России тебе не нужен гараж, можно в отличие от США жить в родительской квартире.
Ну у тебя там наверно есть цикл, в котором переменная получает по очереди значения 1, 2, и так далее заведи вторую переменную, клади в нее произведение первой переменной на саму себя и выводи обе переменные через echo.
Если что-то еще непонятно, запости код и задай вопрос.
Да, результат будет выведен верно. Только задача не совсем об этом, полагаю.
>>69089
Я об этом уже думал, но не знал где это написать.
for ($a = 1; $a <= 9; $a++) {
$b = $a * $a; оказывается можно добавить строку после фигурной скобки
Сам код http://codepad.org/wUPKGKrj
Не знаю как я должен был на это выйти кроме метода тыка. Или я что-то упустил?
А, ты подумал, что в фигурных скобках (в теле цикла) можно написать только одну строку? Наверно, тогда проблема в учебнике, который об этом не рассказал. Или дело в чем-то другом? Почему-то много людей на этой задаче спотыкается.
Сделал две таблицы первая user со стоблцами user_id, first_name, last_name другая likes
содержит внешний ключ user _id (кто поставил лайк) и стобец whom_like(кому поставли)
select u.user_id, u.first_name, u.last_name,count(*)
from users u
inner join
likes as l
on u.user_id = l.user_id
order by u.user_id
этим кодом получаю всех кто поставили лайки
изменив последнию строчку на on u.user_id = l.who_like
могу получить юзеров кому поставили лайки, но как это сделать одним запросом не понимаю?
помогите пожалуста
сори не order by а group by
Ну, то же самое. У меня там немного лишнего есть.
>>69125
Это сарказм?
Если нет - можно внести немного конкретики в этот момент. Судя по шапке автор тут бывает.или же автор начального гайда и есть ОП
До этого момента все было прозрачно.
У меня в играх часто такой тупняк "а че так можно было?". Потому что шли конкретные инструкции > я для себя рисую рамки.
1. Дейтинг для двачеров (тян, кун, геи)
2. Обменник валюты (можно криптовалютный)
3. Букинг сервис
4. Партнерскую программу
5. Баннерную сеть
6. Хайп-лохотрон
7. Cs-рулетка
8. Дурак онлайн (можно играть на криптовалюту)
9. Сервис поиска жилья
10. Городскую мини-барахолку
Допишу если еще что-нибудь придумаю.
P.S. Зацените плз, можно ли так решить? https://ideone.com/9E6VL0
А точно правильно?
разобрался
|-()\/|-|() |))|3()|/| (|<|)|/||—||))
>Если это цифра — добавляем ее к числу $number (умножаем на 10 и прибавляем цифру)
Можно уточнить, а зачем умножать на 10?
А, до меня допёрло, там же десятки. Если идёт 5 и 6, то чтобы ,прибавив их к номеру, вышло 56, а не 11.
Ложись спать и попробуй решить завтра, мне почти всегда это помогает.
Нужно чтобы оно сперва сохраняло операцию и выполняло её лишь только тогда, когда появилась новая.
Тут регулярные выражения нужны? То есть, если есть число, операция, число, то выполнить и сохранить результат?
Извиняюсь, перед айфоном в кредит задача.
Для начала лучше научиться использовать консольный клиент, потом переход на графические клиенты будет прост.
>>67573
Если не нужен поиск по этим данным, то можешь хоть сериализованную строку хранить. Если нужен поиск/фильтр, то json в postgres хорошо подходит: http://schinckel.net/2014/05/25/querying-json-in-postgres/
>>68953
Пост ДЕмотивационный. Человек без реального опыта коммерческой разработки получает шестизначную сумму (это минимум 100 000$ в год - 8000$ в месяц?). Автору повезло запрыгнуть в поезд с модными технологиями, которые сейчас у всех на слуху (React + Redux). Я сам по работе с удовольствием использую эти технологии, но давайте будем честными - заказчикам (во всяком случае западным) просто промыли мозг и они готовы платить большие суммы за React + Redux, у нас например именно такие заказчики.
Подобные посты всегда можно переименовать в "Как я убедил себя, что за 9 месяцев..."
При нажатии на "добавить в корзину":
$items = $_GET['id'];
$_SESSION['items'] = $items;
Сама корзина:
$lol[] = $_SESSION['items'];
if (is_array($lol)) {
foreach ($lol as $item) {
echo $item;
}
Выводится только последнее добавленное значение в S_SESSION['items'], а мне нужно вывести все id товаров.
ЧЯДНТ?
вот живой пример:
if (!isset($_SESSION['cart'])) {
$_SESSION['cart'] = [];
}
$_SESSION['cart'][] = $_GET['product'];
var_dump($_SESSION['cart']);
Все, понял. Спасибо, ананас
https://ideone.com/clnO5D - задача по ООП "ООО Вектор"
Как нормально отрисовать название департаментов?
https://ideone.com/3TqhWy -почему-то через раз считает неправильно,так и не понял в чем дело.
https://ideone.com/1oS6Y1
https://ideone.com/nL1A2m
https://ideone.com/Z4KTPg -айфон
https://ideone.com/s9o64T
https://ideone.com/02a0bc
https://ideone.com/rE0GSK
https://ideone.com/qWiUEG
https://ideone.com/dZF4qO
https://ideone.com/x0qY04
https://ideone.com/SPTW2e
http://sandbox.onlinephpfunctions.com/code/ddbfd936d08c514e856f076c0b08c1e55b93ebc1 -палиндром
https://ideone.com/foQz1L -айпад
https://ideone.com/0Oex0b
У тебя тут нет ооп, точнее есть два класса и дальше лапша из процедурщины и хардкода по созданию всего в ручную.
Сделай класс департамент для начала. С полями необходимыми: название, сотрудники. Далее методы туда перенеси, что бы отчет по департаменту делался департаментом. В общем тут еще много работы у тебя.
Таааак, а если я засуну все методы, которые относятся к подсчету по департаменту, то куда определить методы на общие и средние значения и как их лучше сделать?
Сделать минимальный класс и использовать в нем трейт. Трейт ведь предназначен для включения в класс - значит и тестировать его надо так же.
Вообще, мне не нравится в трейтах то, что их зависимости (какие им нужны поля, методы) никак не определены.
Мне надо чтобы переменную (кол-во дней), которую указал пользователь указалась а батнике.
По сути, создается батник, юзер вводит число, строка кода для батника с числом юзера записывается в батник и запускается.
$edit1 = c('Form2->edit1')->text;
$batcode = "forfiles -p "c:\kursach\" -s -m . /D -$edit1 /C "cmd /c del @path"" //код bat, который будет записатн в файл: 1.bat
$file = 'run.bat'; //название файла ( с расширением)
file_put_contents($file, $batcode.'"'. EXE_NAME . '"'); //записать значение "run" в файл $file (1.bat)
run($file); //запустить $file (1.bat)
Вынеси логику трейта в отдельный класс, его передавай как зависимость туда, где нужны его функции. Трейты - это не объектно-ориентированный, а процедурный подход, если ты напихал туда столько логики, что её понадобилось тестировать, то архитектура 100% хромает. Почитай исходники Laravel - сплошная лапша из трейтов и непонятно откуда берущихся зависимостей. Интересные мнения по поводу трейтов в PHP:
- https://habrahabr.ru/post/333398/#comment_10316684
- https://blog.ircmaxell.com/2011/07/are-traits-new-eval.html
public function getShit(){
return $this->shit;
}
public function setShit($shit) {
$this->shit = $shit;
}
Тем что в сеттер ты напишешь тайпхинт и у тебя никогда не будет в $this->shit попадать что-то ненужное? Единственное что реально приходит на ум.
public function setShit(exactTypeOfShit $shit) {
$this->shit = $shit;
}
Они дают инкапсуляцию. Возможность в дальнейшем добавить какой-то код в методы или вообще поменять их. И возможность вместо выставления наружу полей выставлять только методы, тем самым ограничивая список возможных действий с объектом.
Например, если завтра ты захочешь запретить менять значение поля, ты можешь влепить в сеттер выброс исключения или удалить его вообще. Можешь сделать проверки в сеттере. Можешь подправить геттер, чтобы в полнолуние он умножал результат на два.
В некоторых языках (C#) сделан специальный короткий синтаксис для геттеров/сеттеров: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/auto-implemented-properties
Использовать их конечно никто не заставляет. Выбор за тобой. Но если ты будешь работать с полем напрямую, то не сможешь реализовать инкапсуляцию.
Далее, паста:
-------------
Инкапсуляция. У этого слова есть разные определения, в том числе такие что ничего не понять, потому объясню простыми словами.
Суть инкапсуляции в том, что класс скрывает (инкапслирует) в себе логику работы с данными и сами данные, а наружу выставляет только методы. Пользователю этих методов не важно, как класс устроен внутри, как он хранит данные, какие у него есть поля, ему достаточно вызвать нужный метод чтобы получить результат.
Это упрощает понимание кода: тебе не надо читать и разбирать код класса, достаточно прочитать название метода (и может быть комментарий к нему). Также, это упрощает изменение кода: если какое-то свойство имеет уровень private, то доступ к нему возможен только из того же класса и тебе не надо бегать по всему коду и смотреть что там с этим свойством делается, тебе достаточно просмотреть один файл с этим классом.
При инкапсуляции автор класса задает ограничения, что можно делать с объектом.
Как плюс, мы можем поставить какие-то проверки в методах, и запретить установку неправильных значений свойств. Таким образом, снаружи записать неправильное значение в объект будет нельзя и автор класса может гарантировать его корректную работу в любой ситуации.
Инкапсуляция это хорошо. Так как весь код, который занимается одной задачей, оказывается заключен внутри одного класса. Противоположный случай это когда код (или знание о его внутреннем устройстве) вылезает из класса и размазывается по всей программе.
Если проводить аналогии, то можно представить кофе-машину. Ты нажимаешь кнопку (=вызываешь публичный метод) и получаешь кофе (=результат вызова этого метода), при этом ты не видишь что происходит внутри нее и тебе не надо в этом разбираться.
Лучше наверно привести пример, чем обсуждать абстрактные вещи. Допустим, мы решили представить ломаную линию из нескольких отрезков (например, маршрут на карте) в виде объекта. Для начала, мы спроектируем, что можно будет делать с нашим объектом:
- создать, указав начальную точку (мы решили, что ломаная линия, не содержащая ни одной точки, невозможна, потому требуем передать начальные координаты в конструктор. Я сейчас не могу сказать как выгоднее - разрешить линии без точек вообще, требовать наличие минимум одной или требовать минимум 2 точки. Это надо сравнивать)
- добавить еще одну точку к линии
- найти длину линии (т.е сумму длин всех ее отрезков)
Теперь, имея этот список, мы можем написать класс PolyLine:
class PolyLine
{
// Массив со списком точек
private $points = [];
public function __construct($x, $y)
{
$this->points[] = [$x, $y];
}
public function addPoint($x, $y)
{
$this->points[] = [$x, $y];
}
/ Посчитать общую длину линии */
public function calculateLength()
{
$length = 0;
for ($i = 1; $i < count($this->points)) {
$length += $this->calculateSegmentLength(
$this->points[$i - 1][0],
$this->points[$i - 1][1],
$this->points[$i][0],
$this->points[$i][1]
);
}
return $length;
}
private function calculateSegmentlength($x1, $y1, $x2, $y2) { ... }
}
Вот в этом классе мы делаем публичными только те методы, которые запроектировали выше. А все остальное мы закрываем. Например, мы закрываем от доступа снаружи массив points. Это имеет такие преимущества:
- мы гарантируем что никто нам не положит в массив что-то не то, например, какую-то строку или что-то еще
- людям, которые изучают наш код, не надо смотреть на то, как класс реализован внутри, им достаточно увидеть заголовки и комментарии публичных методов и использовать их
- мы можем в любой момент поменять что-то во внутренней реализации класса, и не трогать остальной код, который его использует.
Ну например завтра мы решим что хранить координаты точки удобнее не в числовом массиве [$x, $y], а в таком ['x' => $x, 'y' => $y]. Или в виде объектов класса Point. И так как этот массив у нас приватный, мы можем смело менять его и нам не придется править код снаружи класса PolyLine так как изменилась только внутренняя реализация, а внешний интерфейс остался таким же.
Если проводить аналогии с автоматом по продаже кофе - мы можем заменить внутреннюю начинку в нем, а пользователи этого даже не заметят, если он будет так же работать. Хороший ООП код как раз и должен состоять из таких вот классов.
До ООП зачастую никакой инкапсуляции и не было, код состоял из функций и глобальных переменных, и можно было обращаться к любой. По мере роста объема программы разбираться в этом было сложнее. И разделение кода на классы нужно для того, чтобы справиться с этой сложностью, чтобы огромная программа могла бы оставаться относительно понятной, чтобы мы могли рассмтаривать класс отдельно от остального кода.
Они дают инкапсуляцию. Возможность в дальнейшем добавить какой-то код в методы или вообще поменять их. И возможность вместо выставления наружу полей выставлять только методы, тем самым ограничивая список возможных действий с объектом.
Например, если завтра ты захочешь запретить менять значение поля, ты можешь влепить в сеттер выброс исключения или удалить его вообще. Можешь сделать проверки в сеттере. Можешь подправить геттер, чтобы в полнолуние он умножал результат на два.
В некоторых языках (C#) сделан специальный короткий синтаксис для геттеров/сеттеров: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/auto-implemented-properties
Использовать их конечно никто не заставляет. Выбор за тобой. Но если ты будешь работать с полем напрямую, то не сможешь реализовать инкапсуляцию.
Далее, паста:
-------------
Инкапсуляция. У этого слова есть разные определения, в том числе такие что ничего не понять, потому объясню простыми словами.
Суть инкапсуляции в том, что класс скрывает (инкапслирует) в себе логику работы с данными и сами данные, а наружу выставляет только методы. Пользователю этих методов не важно, как класс устроен внутри, как он хранит данные, какие у него есть поля, ему достаточно вызвать нужный метод чтобы получить результат.
Это упрощает понимание кода: тебе не надо читать и разбирать код класса, достаточно прочитать название метода (и может быть комментарий к нему). Также, это упрощает изменение кода: если какое-то свойство имеет уровень private, то доступ к нему возможен только из того же класса и тебе не надо бегать по всему коду и смотреть что там с этим свойством делается, тебе достаточно просмотреть один файл с этим классом.
При инкапсуляции автор класса задает ограничения, что можно делать с объектом.
Как плюс, мы можем поставить какие-то проверки в методах, и запретить установку неправильных значений свойств. Таким образом, снаружи записать неправильное значение в объект будет нельзя и автор класса может гарантировать его корректную работу в любой ситуации.
Инкапсуляция это хорошо. Так как весь код, который занимается одной задачей, оказывается заключен внутри одного класса. Противоположный случай это когда код (или знание о его внутреннем устройстве) вылезает из класса и размазывается по всей программе.
Если проводить аналогии, то можно представить кофе-машину. Ты нажимаешь кнопку (=вызываешь публичный метод) и получаешь кофе (=результат вызова этого метода), при этом ты не видишь что происходит внутри нее и тебе не надо в этом разбираться.
Лучше наверно привести пример, чем обсуждать абстрактные вещи. Допустим, мы решили представить ломаную линию из нескольких отрезков (например, маршрут на карте) в виде объекта. Для начала, мы спроектируем, что можно будет делать с нашим объектом:
- создать, указав начальную точку (мы решили, что ломаная линия, не содержащая ни одной точки, невозможна, потому требуем передать начальные координаты в конструктор. Я сейчас не могу сказать как выгоднее - разрешить линии без точек вообще, требовать наличие минимум одной или требовать минимум 2 точки. Это надо сравнивать)
- добавить еще одну точку к линии
- найти длину линии (т.е сумму длин всех ее отрезков)
Теперь, имея этот список, мы можем написать класс PolyLine:
class PolyLine
{
// Массив со списком точек
private $points = [];
public function __construct($x, $y)
{
$this->points[] = [$x, $y];
}
public function addPoint($x, $y)
{
$this->points[] = [$x, $y];
}
/ Посчитать общую длину линии */
public function calculateLength()
{
$length = 0;
for ($i = 1; $i < count($this->points)) {
$length += $this->calculateSegmentLength(
$this->points[$i - 1][0],
$this->points[$i - 1][1],
$this->points[$i][0],
$this->points[$i][1]
);
}
return $length;
}
private function calculateSegmentlength($x1, $y1, $x2, $y2) { ... }
}
Вот в этом классе мы делаем публичными только те методы, которые запроектировали выше. А все остальное мы закрываем. Например, мы закрываем от доступа снаружи массив points. Это имеет такие преимущества:
- мы гарантируем что никто нам не положит в массив что-то не то, например, какую-то строку или что-то еще
- людям, которые изучают наш код, не надо смотреть на то, как класс реализован внутри, им достаточно увидеть заголовки и комментарии публичных методов и использовать их
- мы можем в любой момент поменять что-то во внутренней реализации класса, и не трогать остальной код, который его использует.
Ну например завтра мы решим что хранить координаты точки удобнее не в числовом массиве [$x, $y], а в таком ['x' => $x, 'y' => $y]. Или в виде объектов класса Point. И так как этот массив у нас приватный, мы можем смело менять его и нам не придется править код снаружи класса PolyLine так как изменилась только внутренняя реализация, а внешний интерфейс остался таким же.
Если проводить аналогии с автоматом по продаже кофе - мы можем заменить внутреннюю начинку в нем, а пользователи этого даже не заметят, если он будет так же работать. Хороший ООП код как раз и должен состоять из таких вот классов.
До ООП зачастую никакой инкапсуляции и не было, код состоял из функций и глобальных переменных, и можно было обращаться к любой. По мере роста объема программы разбираться в этом было сложнее. И разделение кода на классы нужно для того, чтобы справиться с этой сложностью, чтобы огромная программа могла бы оставаться относительно понятной, чтобы мы могли рассмтаривать класс отдельно от остального кода.
Дополню анона выше, что в 2018-м во всех нормальных редакторах кода есть средства генерации геттеров/сеттеров, поэтому время написания кода не увеличивается: https://www.jetbrains.com/help/phpstorm/generating-getters-and-setters.html
я еще дополню анонов, что бывают поля, содержащие например ArrayCollection и по уму ты с ними даже не сможешь работать, не реализовав методы типа addElement(), removeElement().
Поздравляю всех с юбилейным тредом!
Только вот он больно глубоко уже.
У меня вопрос к прошареным анонам.
Есть приложение на vue.js, нужен бекенд для него.
Выбор между Node.js + Symfony 4 или просто Node.js .
Стоит ли брать первый вариант, ради скорости и экосистемы или не париться и пробовать писать всё на ноде?
Приложение не очень большое, но важно быстродействие.
я тебе так скажу, симфони4 охуенна во всем кроме одного - у нее пока нет совместимости со многими популярными бандлами. поэтому, если будешь использовать и не знаешь точно, во что оно вырастет и когда, будь готов рыться по пулл реквестам на гитхабе. так что я бы наверное пока ставил трешку.
трешка по бенчмаркам медленнее четверки, но 99% тормозов приложения - это обращения к бд или другим сервисам, так что я бы не парился.
по ноде хз, не знаток в этом.
public function getData()
{
$dataKey = $this->isAPIv2() ? 'body' : 'message';
return array_merge(array($dataKey => $this->getMessage()), $this->data);
}
> Node.js + Symfony 4
Зачем?
Для бэкэнда стоит брать то, на чём будет легче всего разрабатывать, задумываться о производительности стоит только когда она начинает быть узким местом, а большинство проектов до этого просто не доживают.
> Приложение не очень большое, но важно быстродействие.
Здесь подробнее, быстродействие какого формата?
Если нужен реалтайм, то лучше взять node, особенно если есть мазохизм на уровне попытаться поднять свои очереди/бэкэнд для реалтайма.
Если быстродействие формата быстро отправить запрос и быстро получить ответ, тогда без разницы, +- (только PHP чаще всего умирает, кроме ReactPHP, что добавляет оверхед) по этим параметрам вся динамика равна, особенно если обмазаться некоторыми оптимизационными техниками.
Я кстати сейчас пишу "книжку", в которой часть этих моментов так или иначе покрывается, если будет интересно, то https://getjump.me/posts/backends-book
P.S. Для первого "вскрывшего" (и второго описавшего логику вскрытия) https://getjump.me/posts/test-encryption и сообщившего об этом мне в телеграм @getjump дам доступ на халяву
Спасибо за ответ.
https://ideone.com/xRdLQA - переписал, вроде выглядит менее убого.
Можно еще советов?
Ох, анон ты меня выручил. Вчера весь день пытался сделать задачку про кредитный айфон.не знал что можно вставить в условие выражение, которое будет равно/не равно и тд
Может организовать чат для начинающих? Не хочется постить глупые вопросы здесь, так в бамплимит уйдет быстро тред.
Не самое лучшее применение для этого термина. Типичный PHP, например в случае видео, ГЕНЕРИРУЕТ HTML, который в свою очередь рендерится браузером
Как за один раз сходить на два туалета?
Очевидно, что стандартными средствами это сделать нельзя, если ты про тэг form. Можно попытаться сделать это с помощью JS в браузере, но какая цель преследуется?
Если ты хочешь что-то отсылать ОДНОМУ обработчику, то делай ОДНУ форму. На это можно навешать JS.
Нет. В твоей ситуации нужно не использовать триггеры, а прописать нужные действия в коде.
Также, есть такой вариант: триггер кладет данные в особую таблицу, а PHP скрипт проверяет ее по крону.
да уже придумал как обойти эту надобность, но всё равно благодарю за ответ!
сделать один сервис + контроллер + шаблон попапа
pros: унитарный дизайн, можно заложить все возможное поведение в одном месте, инжектить только один сервис, написать подробную документацию, сделал один раз и забыл
cons: __нужно__ заложить все поведение в одном месте, много кода на файл, лапша из условий etc
или
свой попап везде где он нужен
pros: легко читаемый код
cons: каждый раз описывать по новой, возможно даже полностью копировать все с заменой названий пары переменных
Пробовал уже и то и то, в обоих случаях от чего-то жопа горит.
Может быть есть третий стул?
https://ideone.com/I45sbK
Твоя регулярка считает ошибкой запятую перед "а" и "но".
Побуду за ОПа
https://ideone.com/3TqhWy
11-ая строка. У компьютера {$compDice2} и {$compDice2}. Переменная $compDice2 написана дважды
https://ideone.com/Z4KTPg
> if(($credit=($creditBalance$percent)+$servicePayment)>=5000) {
для чего смешиваешь вычисление и условие в одну строку?
Ну проще же для восприятия так?
$credit=($creditBalance$percent)+$servicePayment;
if ($credit>=5000) {
https://ideone.com/foQz1L
Вай какая страшная функция. countPayment
>$initialPayment=7777;
>if($commission==0){
>$creditBalance=$creditBalance+$initialPayment;
Вот этот вот костыль в функции создавался под 1 конкретный банк.
Можно сделать функцию чуть универсальнее. Добавив 1 необязательный аргумент. И убрав то не нужное условие.
подробнее - http://php.net/manual/ru/functions.arguments.php
function countPayment($percent,$commission, $addPay = 0){
$creditBalance=39999 + $addPay;
>}elseif(($credit=($creditBalance$percent)+$commission)<$monthlyPayment){
опять в кучу налепил.
да и в каждом условии по новой вчисляешь одино и тоже значение.
можно же так
$credit=($creditBalance$percent)+$commission;
if ($credit>=$monthlyPayment) {
...
}elseif($credit<$monthlyPayment){ // опять же если условие ($credit>=$monthlyPayment) не выполнилось, очевидно кредит меньше месячной платы
// вместо elseif($credit<$monthlyPayment) можно написать просто else {
...
}
>else{
>
> }
Вот эта пустая конструкция для чего? Её писать не обязательно
> } elseif(($softBankTotal<$homoCreditTotal)&&($softBankTotal<$strawberryBankTotal)){
36 строка вот это
можно заменить на
} elseif($softBankTotal<$strawberryBankTotal){
очевидно что Homocredit не выгоден. Мы его в прошлом условии проверили, что его сравнивать, то?
>} elseif(($strawberryBankTotal<$homoCreditTotal)&&($strawberryBankTotal<$softBankTotal)){
38 строка тоже самое
мы ведь уже все банки сравнили осталось вывести оставшийся банк.
теперь по стилю кода
https://ideone.com/3TqhWy https://ideone.com/rE0GSK https://ideone.com/SPTW2e https://ideone.com/0Oex0b
> Закрывающий тэг ?> НЕОБХОДИМО удалять из файлов, содержащих только PHP.
подробнее
http://php.net/manual/ru/language.basic-syntax.phptags.php
http://php.net/manual/ru/language.basic-syntax.phpmode.php
https://ideone.com/foQz1L
>function countPayment($percent,$commission){
> $creditBalance=39999;
> В коде НЕОБХОДИМО использовать отступ в 4 пробела и НЕДОПУСТИМО применять табы для отступов.
> для функции открывающую фигурную скобку НЕОБХОДИМО располагать на отдельной строке
>В списке аргументов НЕДОПУСТИМЫ пробелы перед запятыми и НЕОБХОДИМ один пробел после каждой запятой.
>for($i=0;$creditBalance>0;$i++) {
>Общие правила стиля для управляющих структур таковы:
>после ключевого слова управляющей структуры НЕОБХОДИМ один пробел;
>}elseif(($credit=($creditBalance*$percent)+$commission)>=$monthlyPayment){
>НЕОБХОДИМ один пробел между закрывающей круглой скобкой и открывающей фигурной скобкой;
Обрати внимание на расположение пробелов, круглых и фигурных скобок https://github.com/samdark/fig-standards-ru/blob/master/accepted/ru/PSR-2-coding-style-guide.md#51-if-elseif-else
вот тут подробнее по стандартам.
https://github.com/samdark/fig-standards-ru/blob/master/accepted/ru/PSR-1-basic-coding-standard.md
https://github.com/samdark/fig-standards-ru/blob/master/accepted/ru/PSR-2-coding-style-guide.md
Побуду за ОПа
https://ideone.com/3TqhWy
11-ая строка. У компьютера {$compDice2} и {$compDice2}. Переменная $compDice2 написана дважды
https://ideone.com/Z4KTPg
> if(($credit=($creditBalance$percent)+$servicePayment)>=5000) {
для чего смешиваешь вычисление и условие в одну строку?
Ну проще же для восприятия так?
$credit=($creditBalance$percent)+$servicePayment;
if ($credit>=5000) {
https://ideone.com/foQz1L
Вай какая страшная функция. countPayment
>$initialPayment=7777;
>if($commission==0){
>$creditBalance=$creditBalance+$initialPayment;
Вот этот вот костыль в функции создавался под 1 конкретный банк.
Можно сделать функцию чуть универсальнее. Добавив 1 необязательный аргумент. И убрав то не нужное условие.
подробнее - http://php.net/manual/ru/functions.arguments.php
function countPayment($percent,$commission, $addPay = 0){
$creditBalance=39999 + $addPay;
>}elseif(($credit=($creditBalance$percent)+$commission)<$monthlyPayment){
опять в кучу налепил.
да и в каждом условии по новой вчисляешь одино и тоже значение.
можно же так
$credit=($creditBalance$percent)+$commission;
if ($credit>=$monthlyPayment) {
...
}elseif($credit<$monthlyPayment){ // опять же если условие ($credit>=$monthlyPayment) не выполнилось, очевидно кредит меньше месячной платы
// вместо elseif($credit<$monthlyPayment) можно написать просто else {
...
}
>else{
>
> }
Вот эта пустая конструкция для чего? Её писать не обязательно
> } elseif(($softBankTotal<$homoCreditTotal)&&($softBankTotal<$strawberryBankTotal)){
36 строка вот это
можно заменить на
} elseif($softBankTotal<$strawberryBankTotal){
очевидно что Homocredit не выгоден. Мы его в прошлом условии проверили, что его сравнивать, то?
>} elseif(($strawberryBankTotal<$homoCreditTotal)&&($strawberryBankTotal<$softBankTotal)){
38 строка тоже самое
мы ведь уже все банки сравнили осталось вывести оставшийся банк.
теперь по стилю кода
https://ideone.com/3TqhWy https://ideone.com/rE0GSK https://ideone.com/SPTW2e https://ideone.com/0Oex0b
> Закрывающий тэг ?> НЕОБХОДИМО удалять из файлов, содержащих только PHP.
подробнее
http://php.net/manual/ru/language.basic-syntax.phptags.php
http://php.net/manual/ru/language.basic-syntax.phpmode.php
https://ideone.com/foQz1L
>function countPayment($percent,$commission){
> $creditBalance=39999;
> В коде НЕОБХОДИМО использовать отступ в 4 пробела и НЕДОПУСТИМО применять табы для отступов.
> для функции открывающую фигурную скобку НЕОБХОДИМО располагать на отдельной строке
>В списке аргументов НЕДОПУСТИМЫ пробелы перед запятыми и НЕОБХОДИМ один пробел после каждой запятой.
>for($i=0;$creditBalance>0;$i++) {
>Общие правила стиля для управляющих структур таковы:
>после ключевого слова управляющей структуры НЕОБХОДИМ один пробел;
>}elseif(($credit=($creditBalance*$percent)+$commission)>=$monthlyPayment){
>НЕОБХОДИМ один пробел между закрывающей круглой скобкой и открывающей фигурной скобкой;
Обрати внимание на расположение пробелов, круглых и фигурных скобок https://github.com/samdark/fig-standards-ru/blob/master/accepted/ru/PSR-2-coding-style-guide.md#51-if-elseif-else
вот тут подробнее по стандартам.
https://github.com/samdark/fig-standards-ru/blob/master/accepted/ru/PSR-1-basic-coding-standard.md
https://github.com/samdark/fig-standards-ru/blob/master/accepted/ru/PSR-2-coding-style-guide.md
Когда уже новый тред? А то заебалось искать этот тред на дне доски
Приветствую. Посмотрите как я скопировал код https://ideone.com/JkOu26. У меня единственный вопрос по этой задаче, строка 19:
$credit = $creditmonthly - $creditmonthly
Это можно вычислить как - нибудь еще? Я больше дня просидел потому что не мог сам придумать эту строку.
И еще вопрос другого плана: если у меня такой ступор, то можно читать дальше чтобы не терять время? Где можно брать примеры/шаблоны решения не сложных, стандартных задач?
Только что дошло чего нет в учебнике ОПа - примерчиков, шаблонов
https://ideone.com/JkOu26.
Not Found. Ссылка не работает.
>$credit = $creditmonthly - $creditmonthly
Попробю пованговать
возможно в этой строке ты хочешь указать, что кредит выплачен и равен 0 (я угадал?)
то, так и присваиваешь кредиту 0.
$credit = 0;
>for ($i=0; $creditBalance>0; $i++) {
тут у тебя за чем то вставлен счётчик переменная $i ни где не используется, она тут у тебя ни какой роли не играет.
А цикл выполняется пока выполняется условие $creditBalance>0
можно было вместо for использовать цикл while
while ($creditBalance>0) {
меньше лишних переменных которые не придётся читать.
подробнее по for - http://php.net/manual/ru/control-structures.for.php
подробнее по while http://php.net/manual/ru/control-structures.while.php
https://ideone.com/JkOu26.
Not Found. Ссылка не работает.
>$credit = $creditmonthly - $creditmonthly
Попробю пованговать
возможно в этой строке ты хочешь указать, что кредит выплачен и равен 0 (я угадал?)
то, так и присваиваешь кредиту 0.
$credit = 0;
>for ($i=0; $creditBalance>0; $i++) {
тут у тебя за чем то вставлен счётчик переменная $i ни где не используется, она тут у тебя ни какой роли не играет.
А цикл выполняется пока выполняется условие $creditBalance>0
можно было вместо for использовать цикл while
while ($creditBalance>0) {
меньше лишних переменных которые не придётся читать.
подробнее по for - http://php.net/manual/ru/control-structures.for.php
подробнее по while http://php.net/manual/ru/control-structures.while.php
>возможно в этой строке ты хочешь указать, что кредит выплачен и равен 0 (я угадал?)
Так и есть.
Вроде рабочая https://ideone.com/86cp9P
В 19 строке можно написать $credit = 0; и все будет так же.
Я специально не использую что-либо кроме рубрики из ОПповского гайда. Про while ничего не было, поэтому и не использовал.
Я хотел каким-то образом заставить вычитать из остатка кредита ровно ту сумму, которая остается с помощью for и if, но не понимал как это сделать. Может с помощью этого и нельзя.
Впредь буду чаще обращаться к справочнику.боюсь что могу загрузить голову не нужной инфой на данной стадии обучения
Кто-нибудь знает, как на стороне сервера, сделать ограничение на запрос страницы,
чтобы не нагружали хостинг множественными, быстрыми запросами из браузера,
например всякими window.open в цикле, без таймаута на JS?
Что-то вроде "Попробуйте обновить страницу через 5...4...3...2...1... сек" и пустой ответ по HTTP?
Я вот смотрю на это, и мне кажется что капча ну вообще нахер не нужна. Что мешает этим ботам сразу хуярить пост запросы на form.php, минуя все капчи? Я канеш могу просто поменять пару строк и заработать свой доширак, но все же, мой вопрос, я все правильно понял и капча не нужна, или все там норм? Просто на form.php даже валидации никакой нет, хорошо хоть эта инфа на почту сразу отправляется а не в базу например.
Это эффективнее всего делать на уровне nginx, чтобы такие запросы минимально нагружали сервер и не доходили до приложения на PHP.
Мануал http://nginx.org/ru/docs/http/ngx_http_limit_req_module.html
Надо это тщательно тестировать, так как при неправильной настройке можно потерять пользователей.
Желательно не ставить ограничения на статические файлы, которые отдаются без вызова PHP скриптов.
>>71223
> Я специально не использую что-либо кроме рубрики из ОПповского гайда. Про while ничего не было, поэтому и не использовал.
Вообще, можно использовать. В учебнике ее нет в начале, чтобы не усложнять ситуацию.
> if ($creditmonthly > $payPerMonth) {
> } elseif ($creditmonthly < $payPerMonth) {
А что, если числа равны? Лучше вместо elseif поставить просто else без условия.
А еще лучше - вместо if вычислять выплату в текущем месяце с помощью min/max.
выплата = меньшее из (5000, остаток долга);
>>71137
> Где можно брать примеры/шаблоны решения не сложных, стандартных задач?
Это бессмысленно. Кому нужен программист, который умеет решать только "стандартные" задачи? Тебе надо понимать, какие команды и функции есть в твоем распоряжении, и как из них составить программу, которая делает то, что нужно.
Если тебе какая-то тема непонятна, ты можешь попросить дополнительные задачи по ней или задать тут вопрос.
Это эффективнее всего делать на уровне nginx, чтобы такие запросы минимально нагружали сервер и не доходили до приложения на PHP.
Мануал http://nginx.org/ru/docs/http/ngx_http_limit_req_module.html
Надо это тщательно тестировать, так как при неправильной настройке можно потерять пользователей.
Желательно не ставить ограничения на статические файлы, которые отдаются без вызова PHP скриптов.
>>71223
> Я специально не использую что-либо кроме рубрики из ОПповского гайда. Про while ничего не было, поэтому и не использовал.
Вообще, можно использовать. В учебнике ее нет в начале, чтобы не усложнять ситуацию.
> if ($creditmonthly > $payPerMonth) {
> } elseif ($creditmonthly < $payPerMonth) {
А что, если числа равны? Лучше вместо elseif поставить просто else без условия.
А еще лучше - вместо if вычислять выплату в текущем месяце с помощью min/max.
выплата = меньшее из (5000, остаток долга);
>>71137
> Где можно брать примеры/шаблоны решения не сложных, стандартных задач?
Это бессмысленно. Кому нужен программист, который умеет решать только "стандартные" задачи? Тебе надо понимать, какие команды и функции есть в твоем распоряжении, и как из них составить программу, которая делает то, что нужно.
Если тебе какая-то тема непонятна, ты можешь попросить дополнительные задачи по ней или задать тут вопрос.
Зависит от того, как использован. Перевод - маршрутизация/диспетчеризация/распределение. В вебе обычно обозначает определение имени контроллера по URL из HTTP запроса.
Простейший пример кода роутера:
- Если URL = /news то контроллер = 'NewsController', действие = 'indexAction'
- Если URL соответствует шаблону /news/{date}, то контроллер = 'NewsController', действие = 'viewAction', параметр date берется из URL
- Иначе, контроллер и действие определить не удалось
>>70855
Ну да, нет смысла показывать пользователю сообщение об ошибке, которую он не может исправить.
Но проверять, конечно, надо все тщательно. А именно:
- все обязательные поля заполнены
- parentId указывает на существующий, не скрытый, не удаленный, комментарий, который действительно выводится на сайте
- при добавлении не превышается лимит на число комментариев в ветке и глубину
>>70770
Наверно лучше было сделать несколько регулярок, по одной на каждое правило, и массив с пояснением типа ошибки:
$errors = [
'нет пробела перед запятой' => '/..../',
...
];
"зделаем" не обнаружится.
> \s(а|но)
Тут непонятно, в чем ошибка. Перед "а" нельзя ставить пробел?
"разделанный на части" будет воспринято как ошибка.
Зависит от того, как использован. Перевод - маршрутизация/диспетчеризация/распределение. В вебе обычно обозначает определение имени контроллера по URL из HTTP запроса.
Простейший пример кода роутера:
- Если URL = /news то контроллер = 'NewsController', действие = 'indexAction'
- Если URL соответствует шаблону /news/{date}, то контроллер = 'NewsController', действие = 'viewAction', параметр date берется из URL
- Иначе, контроллер и действие определить не удалось
>>70855
Ну да, нет смысла показывать пользователю сообщение об ошибке, которую он не может исправить.
Но проверять, конечно, надо все тщательно. А именно:
- все обязательные поля заполнены
- parentId указывает на существующий, не скрытый, не удаленный, комментарий, который действительно выводится на сайте
- при добавлении не превышается лимит на число комментариев в ветке и глубину
>>70770
Наверно лучше было сделать несколько регулярок, по одной на каждое правило, и массив с пояснением типа ошибки:
$errors = [
'нет пробела перед запятой' => '/..../',
...
];
"зделаем" не обнаружится.
> \s(а|но)
Тут непонятно, в чем ошибка. Перед "а" нельзя ставить пробел?
"разделанный на части" будет воспринято как ошибка.
Попап можно разделить на "обертку" и "содержимое". Ту часть JS кода, которая позиционирует попап, затеняет фон за ним, выводит крестик, можно сделать общей, а содержимое делать разное.
Зачем нужны сервис и контроллер, я не понял. Ты про серверный код или про фреймворки вроде Angular? Ты аяксом загружаешь содержимое попапа? Или что? Я не понимаю.
Если ты "содержимое" попапа загружаещь с сервера аякс-запросом, то конечно надо использовать разные контроллеры и шаблоны. Ты ведь не пытаешься для всех страниц на сайте сделать один контроллер, попап в этом плане ничем от страницы не отличается.
>>70700
Вообще, там объяснение, на мой взгляд, сделано путанно. Вот, например, с 20 секунды:
> MVC is a ... pattern, that basically allows you to separate your views from your models
> which update and give you data basically
> and the controllers will handle that data from the models and will update the view
Тут автор явно путает серверный MVC с клиентским MVC. В клиентском MVC, действительно, view обновляется (updates) при изменении модели, но в серверном ничего не обновляется. Там просто генерируется HTML код, отдается клиенту и скрипт завершается. Эта разница объяснена в моем уроке https://github.com/codedokode/pasta/blob/master/arch/mvc.md
Те, кто про нее не знают, и пытаются гуглить, натыкаются на схему клиентского MVC с активной моделью (где все идет по кругу) и путают ее с серверным MVC.
> at the moment what it's doing it's rendering out the home index view
Думаю, здесь можно перевести rendering как "выводит" (может, контроллер генерирует (выводит) HTML код и отдает браузеру, который отображает (выводит) его на странице). "Он [контроллер? браузер?] выводит index view [представление главной страницы]".
> or the home index controller and that's rendering out the home index view or the home index controller and that's rendering out a view here
По моему преподаватель тут сам запутался, кто кого рендерит. То ли контроллер рендерит вью, то ли еще кто-то. Я сам не понимаю.
> so this is the view coming from the home index controller
Ну тут тоже получается путаница, так как преподаватель очевидно говорит про страницу в браузере (this is the view), но страница в браузере - это не вью, а результат работы вью, HTML-код, который вью сгенерировало и который отобразил браузер.
>>70594
Это веб-сервер или (корректнее) HTTP-сервер. Давай разберем слово на части. Что такое "веб"? Это "всемирная паутина", но здесь это синоним слова HTTP. Что такое HTTP? Это протокол (язык взаимодействия двух компьютерных программ). Есть языки программирования, а есть языки для общения программ между собой.
Что такое сервер? Это программа, которая принимает запросы и дает на них ответы. А программа, которая посылает запросы серверу, называется клиент. Клиент и сервер общаются с использованием определенного "языка" - протокола.
Таким образом, HTTP-сервер - это программа, которая принимает HTTP-запросы по протоколу HTTP и дает на них ответы. А кто является HTTP-клиентом? Им является браузер.
Когда ты заходишь на какой-то сайт, браузер соединяется с HTTP-сервером этого сайта, и в роли HTTP-клиента запрашивает (по протоколу HTTP) страницу с этого сайта. HTTP-сервер в ответ на запрос отдает HTML-страницу и браузер отображает ее на экране.
Основная задача протокола HTTP - это дать возможность клиенту скачать файл с сервера.
Таким образом, HTTP-сервер нужен для того, чтобы раздавать файлы браузерам и, возможно, другим HTTP-клиентам. Кроме раздачи файлов, он еще умеет генерировать страницы динамически с помощью скриптов, например, на PHP.
Подробнее это описано в моем уроке:
- https://github.com/codedokode/pasta/blob/master/soft/web-server.md
- подробно про HTTP: https://github.com/codedokode/pasta/blob/master/network/http.md
Попап можно разделить на "обертку" и "содержимое". Ту часть JS кода, которая позиционирует попап, затеняет фон за ним, выводит крестик, можно сделать общей, а содержимое делать разное.
Зачем нужны сервис и контроллер, я не понял. Ты про серверный код или про фреймворки вроде Angular? Ты аяксом загружаешь содержимое попапа? Или что? Я не понимаю.
Если ты "содержимое" попапа загружаещь с сервера аякс-запросом, то конечно надо использовать разные контроллеры и шаблоны. Ты ведь не пытаешься для всех страниц на сайте сделать один контроллер, попап в этом плане ничем от страницы не отличается.
>>70700
Вообще, там объяснение, на мой взгляд, сделано путанно. Вот, например, с 20 секунды:
> MVC is a ... pattern, that basically allows you to separate your views from your models
> which update and give you data basically
> and the controllers will handle that data from the models and will update the view
Тут автор явно путает серверный MVC с клиентским MVC. В клиентском MVC, действительно, view обновляется (updates) при изменении модели, но в серверном ничего не обновляется. Там просто генерируется HTML код, отдается клиенту и скрипт завершается. Эта разница объяснена в моем уроке https://github.com/codedokode/pasta/blob/master/arch/mvc.md
Те, кто про нее не знают, и пытаются гуглить, натыкаются на схему клиентского MVC с активной моделью (где все идет по кругу) и путают ее с серверным MVC.
> at the moment what it's doing it's rendering out the home index view
Думаю, здесь можно перевести rendering как "выводит" (может, контроллер генерирует (выводит) HTML код и отдает браузеру, который отображает (выводит) его на странице). "Он [контроллер? браузер?] выводит index view [представление главной страницы]".
> or the home index controller and that's rendering out the home index view or the home index controller and that's rendering out a view here
По моему преподаватель тут сам запутался, кто кого рендерит. То ли контроллер рендерит вью, то ли еще кто-то. Я сам не понимаю.
> so this is the view coming from the home index controller
Ну тут тоже получается путаница, так как преподаватель очевидно говорит про страницу в браузере (this is the view), но страница в браузере - это не вью, а результат работы вью, HTML-код, который вью сгенерировало и который отобразил браузер.
>>70594
Это веб-сервер или (корректнее) HTTP-сервер. Давай разберем слово на части. Что такое "веб"? Это "всемирная паутина", но здесь это синоним слова HTTP. Что такое HTTP? Это протокол (язык взаимодействия двух компьютерных программ). Есть языки программирования, а есть языки для общения программ между собой.
Что такое сервер? Это программа, которая принимает запросы и дает на них ответы. А программа, которая посылает запросы серверу, называется клиент. Клиент и сервер общаются с использованием определенного "языка" - протокола.
Таким образом, HTTP-сервер - это программа, которая принимает HTTP-запросы по протоколу HTTP и дает на них ответы. А кто является HTTP-клиентом? Им является браузер.
Когда ты заходишь на какой-то сайт, браузер соединяется с HTTP-сервером этого сайта, и в роли HTTP-клиента запрашивает (по протоколу HTTP) страницу с этого сайта. HTTP-сервер в ответ на запрос отдает HTML-страницу и браузер отображает ее на экране.
Основная задача протокола HTTP - это дать возможность клиенту скачать файл с сервера.
Таким образом, HTTP-сервер нужен для того, чтобы раздавать файлы браузерам и, возможно, другим HTTP-клиентам. Кроме раздачи файлов, он еще умеет генерировать страницы динамически с помощью скриптов, например, на PHP.
Подробнее это описано в моем уроке:
- https://github.com/codedokode/pasta/blob/master/soft/web-server.md
- подробно про HTTP: https://github.com/codedokode/pasta/blob/master/network/http.md
> var $departments = [];
var писали в PHP4, это было 15 лет назад, выкинь свой устаревший учебник. Сейчас пишут public/protected/private.
> public function totalEmployees()
Имена функций принято начинать с глагола, сделатьЧтоТо. Например, countEmployees() - посчитатьСотрудников.
> function __construct($departments) {
Вместо того, чтобы передавать массив департаментов, лучше сделать функцию для добавления одного департамента. Это удобнее, а также позволяет поставить тайп-хинт.
> return $avarageEmployees = totalEmployees($this->departments) / count($this->departments);
Не нужно тут создавать переменную $avarageEmployees.
Также, а почему используется функция totalEmployees() ? Разве не логичнее использовать метод в классе Company? Ты наверно пропустил $this->.
По Департаменту то же самое - гораздо удобнее сделать в нем методы для найма/увольнения работника, чем передавать список работников один раз при создании.
> dpEmployees()
Непонятно, что значит dp. Нужно просто было написать countEmployees или getEmployeesCount.
> public function dpCoffeConusmption ()
> foreach ($this->employees as $employee){
> if ($employee->isBoss == true) {
> $dpCoffeConsumption += $employee->amountOfCoffe * 2;
> } else {
> $dpCoffeConsumption += $employee->amountOfCoffe;
Вот эту ошибку хотелось бы разобрать поподробнее. Одна из идей ООП - это разделение отвественности, обязанностей, между классами. В отличие от монолитного не-ООП кода, в ООП у нас код разделен на классы и каждый отвечает за свою часть функционала. Каждый класс в какой-то степени независим от других.
Это позволяет нам рассматривать класс отдельно от остального кода. Мы, глядя только на класс, можем понять, как он работает, делать какие-то изменения. Это разделение на части позволяет нам бороться со сложностью кода по мере роста объема программы.
Расчет, сколько кофе потребляет работник - это ответственность работника. У него есть все нужные данные для этого, значит нет никакого смысла делать этот расчет в Департаменте. У Работника должен быть готовый метод узнатьПотреблениеКофе().
Ты здесь нарушаешь разделение ответственности, и теряешь преимущества ООП. Если проводить аналогии с предприятием - ты вместо того, чтобы спросить у начальника склада, сколько на складе товаров, идешь сам на склад и считаешь их. Вот в ООП мы не лезем на склад в обход начальника склада. В ООП только начальник склада может по нему ходить и мы получаем нужные данные у него.
Когда ты решаешь ООП-задачу, то, прежде чем писать код, ты должен решить, какие у тебя будут классы, за что каждый отвечает, какие у них будут методы. И на этом этапе ты должен был запроектировать в классе Работника все нужные методы для получения информации по нему.
Такие же нарушения в методе dbSalary.
> class Manager extends Employee
> public $baseSalary = 500;
> public $amountOfCoffe = 25;
> public $reports = 200;
Здесь другая проблема. Чтобы добавить новую профессию, надо сделать класс и в нем заполнить значения полей. Но где это задокументировано? И кто проверяет, что они заполнены? Никто, и непонятно, как об этом догадаться.
Решение проблемы - абстрактные классы и методы.
Абстрактный класс - это недоделанный класс, объект которого нельзя создать. От него можно только наследоваться.
Абстрактный метод - это "недописанный" метод в абстр. классе, который обязаны дописать его наследники.
Чтобы заставить программиста при создании профессии определить зарплату, кофе, итд., мы можем сделать в базовом классе Employee абстрактные методы getBaseSalary() и тд. Тогда нельзя будет сделать наследника класса, не дописав эти методы.
Как видишь, использование возможностей ООП позволяет исключить ошибки еще на этапе написания программы.
> $pdEmployees = [
> $pdBoss = new Manager(2, true),
> $pdMe = new Manager(1, false),
> $pdMe = new Manager(1, false),
Это надо как-то минимально автоматизировать с помощью вспомогательных функций создания экземпляров работников.
Ну и ждем вторую часть задачи, с антикризисными мерами.
Также, если ты используешь PHP7, то расставь везде тайпхинты:
---------
Тайп хинты позволяют указать, что аргумент функции должен быть определенного типа (например быть объектом определенного класса или его наследника). Тайп хинт делает код понятнее (так как видно какого типа переменная) и надежнее (так как PHP не позволит передать что-то неразрешенное и ты сразу увидишь ошибку). Используй их везде.
Мануал: http://php.net/manual/ru/language.oop5.typehinting.php
Обрати внимание, что php7 усовершенствовал систему тайп-хинтов - теперь можно в их качестве указывать примитивные типы вроде int/string, а в php7.1 стало можно указывать тайп-хинт для возвращаемого функцией значения: https://habrahabr.ru/post/267799/ , причем можно указать тип void, значащий, что функция ничего не возвращает.
---------
> var $departments = [];
var писали в PHP4, это было 15 лет назад, выкинь свой устаревший учебник. Сейчас пишут public/protected/private.
> public function totalEmployees()
Имена функций принято начинать с глагола, сделатьЧтоТо. Например, countEmployees() - посчитатьСотрудников.
> function __construct($departments) {
Вместо того, чтобы передавать массив департаментов, лучше сделать функцию для добавления одного департамента. Это удобнее, а также позволяет поставить тайп-хинт.
> return $avarageEmployees = totalEmployees($this->departments) / count($this->departments);
Не нужно тут создавать переменную $avarageEmployees.
Также, а почему используется функция totalEmployees() ? Разве не логичнее использовать метод в классе Company? Ты наверно пропустил $this->.
По Департаменту то же самое - гораздо удобнее сделать в нем методы для найма/увольнения работника, чем передавать список работников один раз при создании.
> dpEmployees()
Непонятно, что значит dp. Нужно просто было написать countEmployees или getEmployeesCount.
> public function dpCoffeConusmption ()
> foreach ($this->employees as $employee){
> if ($employee->isBoss == true) {
> $dpCoffeConsumption += $employee->amountOfCoffe * 2;
> } else {
> $dpCoffeConsumption += $employee->amountOfCoffe;
Вот эту ошибку хотелось бы разобрать поподробнее. Одна из идей ООП - это разделение отвественности, обязанностей, между классами. В отличие от монолитного не-ООП кода, в ООП у нас код разделен на классы и каждый отвечает за свою часть функционала. Каждый класс в какой-то степени независим от других.
Это позволяет нам рассматривать класс отдельно от остального кода. Мы, глядя только на класс, можем понять, как он работает, делать какие-то изменения. Это разделение на части позволяет нам бороться со сложностью кода по мере роста объема программы.
Расчет, сколько кофе потребляет работник - это ответственность работника. У него есть все нужные данные для этого, значит нет никакого смысла делать этот расчет в Департаменте. У Работника должен быть готовый метод узнатьПотреблениеКофе().
Ты здесь нарушаешь разделение ответственности, и теряешь преимущества ООП. Если проводить аналогии с предприятием - ты вместо того, чтобы спросить у начальника склада, сколько на складе товаров, идешь сам на склад и считаешь их. Вот в ООП мы не лезем на склад в обход начальника склада. В ООП только начальник склада может по нему ходить и мы получаем нужные данные у него.
Когда ты решаешь ООП-задачу, то, прежде чем писать код, ты должен решить, какие у тебя будут классы, за что каждый отвечает, какие у них будут методы. И на этом этапе ты должен был запроектировать в классе Работника все нужные методы для получения информации по нему.
Такие же нарушения в методе dbSalary.
> class Manager extends Employee
> public $baseSalary = 500;
> public $amountOfCoffe = 25;
> public $reports = 200;
Здесь другая проблема. Чтобы добавить новую профессию, надо сделать класс и в нем заполнить значения полей. Но где это задокументировано? И кто проверяет, что они заполнены? Никто, и непонятно, как об этом догадаться.
Решение проблемы - абстрактные классы и методы.
Абстрактный класс - это недоделанный класс, объект которого нельзя создать. От него можно только наследоваться.
Абстрактный метод - это "недописанный" метод в абстр. классе, который обязаны дописать его наследники.
Чтобы заставить программиста при создании профессии определить зарплату, кофе, итд., мы можем сделать в базовом классе Employee абстрактные методы getBaseSalary() и тд. Тогда нельзя будет сделать наследника класса, не дописав эти методы.
Как видишь, использование возможностей ООП позволяет исключить ошибки еще на этапе написания программы.
> $pdEmployees = [
> $pdBoss = new Manager(2, true),
> $pdMe = new Manager(1, false),
> $pdMe = new Manager(1, false),
Это надо как-то минимально автоматизировать с помощью вспомогательных функций создания экземпляров работников.
Ну и ждем вторую часть задачи, с антикризисными мерами.
Также, если ты используешь PHP7, то расставь везде тайпхинты:
---------
Тайп хинты позволяют указать, что аргумент функции должен быть определенного типа (например быть объектом определенного класса или его наследника). Тайп хинт делает код понятнее (так как видно какого типа переменная) и надежнее (так как PHP не позволит передать что-то неразрешенное и ты сразу увидишь ошибку). Используй их везде.
Мануал: http://php.net/manual/ru/language.oop5.typehinting.php
Обрати внимание, что php7 усовершенствовал систему тайп-хинтов - теперь можно в их качестве указывать примитивные типы вроде int/string, а в php7.1 стало можно указывать тайп-хинт для возвращаемого функцией значения: https://habrahabr.ru/post/267799/ , причем можно указать тип void, значащий, что функция ничего не возвращает.
---------
Также, я думаю, что тебе надо познакомиться с преимуществами инкапсуляции. Она затрудняет нарушение разделения отвественности (не дает пролезть на склад в обход его начальника). Сделай все поля либо private либо protected, и дай доступ к ним только через методы. Паста про инкапсуляцию:
----------
Инкапсуляция. У этого слова есть разные определения, в том числе такие что ничего не понять, потому объясню простыми словами.
Суть инкапсуляции в том, что класс скрывает (инкапслирует) в себе логику работы с данными и сами данные, а наружу выставляет только методы. Пользователю этих методов не важно, как класс устроен внутри, как он хранит данные, какие у него есть поля, ему достаточно вызвать нужный метод чтобы получить результат.
Это упрощает понимание кода: тебе не надо читать и разбирать код класса, достаточно прочитать название метода (и может быть комментарий к нему). Также, это упрощает изменение кода: если какое-то свойство имеет уровень private, то доступ к нему возможен только из того же класса и тебе не надо бегать по всему коду и смотреть что там с этим свойством делается, тебе достаточно просмотреть один файл с этим классом.
При инкапсуляции автор класса задает ограничения, что можно делать с объектом.
Как плюс, мы можем поставить какие-то проверки в методах, и запретить установку неправильных значений свойств. Таким образом, снаружи записать неправильное значение в объект будет нельзя и автор класса может гарантировать его корректную работу в любой ситуации.
Инкапсуляция это хорошо. Так как весь код, который занимается одной задачей, оказывается заключен внутри одного класса. Противоположный случай это когда код (или знание о его внутреннем устройстве) вылезает из класса и размазывается по всей программе.
Если проводить аналогии, то можно представить кофе-машину. Ты нажимаешь кнопку (=вызываешь публичный метод) и получаешь кофе (=результат вызова этого метода), при этом ты не видишь что происходит внутри нее и тебе не надо в этом разбираться.
Лучше наверно привести пример, чем обсуждать абстрактные вещи. Допустим, мы решили представить ломаную линию из нескольких отрезков (например, маршрут на карте) в виде объекта. Для начала, мы спроектируем, что можно будет делать с нашим объектом:
- создать, указав начальную точку (мы решили, что ломаная линия, не содержащая ни одной точки, невозможна, потому требуем передать начальные координаты в конструктор. Я сейчас не могу сказать как выгоднее - разрешить линии без точек вообще, требовать наличие минимум одной или требовать минимум 2 точки. Это надо сравнивать)
- добавить еще одну точку к линии
- найти длину линии (т.е сумму длин всех ее отрезков)
Теперь, имея этот список, мы можем написать класс PolyLine:
class PolyLine
{
// Массив со списком точек
private $points = [];
public function __construct($x, $y)
{
$this->points[] = [$x, $y];
}
public function addPoint($x, $y)
{
$this->points[] = [$x, $y];
}
/ Посчитать общую длину линии */
public function calculateLength()
{
$length = 0;
for ($i = 1; $i < count($this->points)) {
$length += $this->calculateSegmentLength(
$this->points[$i - 1][0],
$this->points[$i - 1][1],
$this->points[$i][0],
$this->points[$i][1]
);
}
return $length;
}
private function calculateSegmentlength($x1, $y1, $x2, $y2) { ... }
}
Вот в этом классе мы делаем публичными только те методы, которые запроектировали выше. А все остальное мы закрываем. Например, мы закрываем от доступа снаружи массив points. Это имеет такие преимущества:
- мы гарантируем что никто нам не положит в массив что-то не то, например, какую-то строку или что-то еще
- людям, которые изучают наш код, не надо смотреть на то, как класс реализован внутри, им достаточно увидеть заголовки и комментарии публичных методов и использовать их
- мы можем в любой момент поменять что-то во внутренней реализации класса, и не трогать остальной код, который его использует.
Ну например завтра мы решим что хранить координаты точки удобнее не в числовом массиве [$x, $y], а в таком ['x' => $x, 'y' => $y]. Или в виде объектов класса Point. И так как этот массив у нас приватный, мы можем смело менять его и нам не придется править код снаружи класса PolyLine так как изменилась только внутренняя реализация, а внешний интерфейс остался таким же.
Если проводить аналогии с автоматом по продаже кофе - мы можем заменить внутреннюю начинку в нем, а пользователи этого даже не заметят, если он будет так же работать. Хороший ООП код как раз и должен состоять из таких вот классов.
До ООП зачастую никакой инкапсуляции и не было, код состоял из функций и глобальных переменных, и можно было обращаться к любой. По мере роста объема программы разбираться в этом было сложнее. И разделение кода на классы нужно для того, чтобы справиться с этой сложностью, чтобы огромная программа могла бы оставаться относительно понятной, чтобы мы могли рассмтаривать класс отдельно от остального кода.
Также, я думаю, что тебе надо познакомиться с преимуществами инкапсуляции. Она затрудняет нарушение разделения отвественности (не дает пролезть на склад в обход его начальника). Сделай все поля либо private либо protected, и дай доступ к ним только через методы. Паста про инкапсуляцию:
----------
Инкапсуляция. У этого слова есть разные определения, в том числе такие что ничего не понять, потому объясню простыми словами.
Суть инкапсуляции в том, что класс скрывает (инкапслирует) в себе логику работы с данными и сами данные, а наружу выставляет только методы. Пользователю этих методов не важно, как класс устроен внутри, как он хранит данные, какие у него есть поля, ему достаточно вызвать нужный метод чтобы получить результат.
Это упрощает понимание кода: тебе не надо читать и разбирать код класса, достаточно прочитать название метода (и может быть комментарий к нему). Также, это упрощает изменение кода: если какое-то свойство имеет уровень private, то доступ к нему возможен только из того же класса и тебе не надо бегать по всему коду и смотреть что там с этим свойством делается, тебе достаточно просмотреть один файл с этим классом.
При инкапсуляции автор класса задает ограничения, что можно делать с объектом.
Как плюс, мы можем поставить какие-то проверки в методах, и запретить установку неправильных значений свойств. Таким образом, снаружи записать неправильное значение в объект будет нельзя и автор класса может гарантировать его корректную работу в любой ситуации.
Инкапсуляция это хорошо. Так как весь код, который занимается одной задачей, оказывается заключен внутри одного класса. Противоположный случай это когда код (или знание о его внутреннем устройстве) вылезает из класса и размазывается по всей программе.
Если проводить аналогии, то можно представить кофе-машину. Ты нажимаешь кнопку (=вызываешь публичный метод) и получаешь кофе (=результат вызова этого метода), при этом ты не видишь что происходит внутри нее и тебе не надо в этом разбираться.
Лучше наверно привести пример, чем обсуждать абстрактные вещи. Допустим, мы решили представить ломаную линию из нескольких отрезков (например, маршрут на карте) в виде объекта. Для начала, мы спроектируем, что можно будет делать с нашим объектом:
- создать, указав начальную точку (мы решили, что ломаная линия, не содержащая ни одной точки, невозможна, потому требуем передать начальные координаты в конструктор. Я сейчас не могу сказать как выгоднее - разрешить линии без точек вообще, требовать наличие минимум одной или требовать минимум 2 точки. Это надо сравнивать)
- добавить еще одну точку к линии
- найти длину линии (т.е сумму длин всех ее отрезков)
Теперь, имея этот список, мы можем написать класс PolyLine:
class PolyLine
{
// Массив со списком точек
private $points = [];
public function __construct($x, $y)
{
$this->points[] = [$x, $y];
}
public function addPoint($x, $y)
{
$this->points[] = [$x, $y];
}
/ Посчитать общую длину линии */
public function calculateLength()
{
$length = 0;
for ($i = 1; $i < count($this->points)) {
$length += $this->calculateSegmentLength(
$this->points[$i - 1][0],
$this->points[$i - 1][1],
$this->points[$i][0],
$this->points[$i][1]
);
}
return $length;
}
private function calculateSegmentlength($x1, $y1, $x2, $y2) { ... }
}
Вот в этом классе мы делаем публичными только те методы, которые запроектировали выше. А все остальное мы закрываем. Например, мы закрываем от доступа снаружи массив points. Это имеет такие преимущества:
- мы гарантируем что никто нам не положит в массив что-то не то, например, какую-то строку или что-то еще
- людям, которые изучают наш код, не надо смотреть на то, как класс реализован внутри, им достаточно увидеть заголовки и комментарии публичных методов и использовать их
- мы можем в любой момент поменять что-то во внутренней реализации класса, и не трогать остальной код, который его использует.
Ну например завтра мы решим что хранить координаты точки удобнее не в числовом массиве [$x, $y], а в таком ['x' => $x, 'y' => $y]. Или в виде объектов класса Point. И так как этот массив у нас приватный, мы можем смело менять его и нам не придется править код снаружи класса PolyLine так как изменилась только внутренняя реализация, а внешний интерфейс остался таким же.
Если проводить аналогии с автоматом по продаже кофе - мы можем заменить внутреннюю начинку в нем, а пользователи этого даже не заметят, если он будет так же работать. Хороший ООП код как раз и должен состоять из таких вот классов.
До ООП зачастую никакой инкапсуляции и не было, код состоял из функций и глобальных переменных, и можно было обращаться к любой. По мере роста объема программы разбираться в этом было сложнее. И разделение кода на классы нужно для того, чтобы справиться с этой сложностью, чтобы огромная программа могла бы оставаться относительно понятной, чтобы мы могли рассмтаривать класс отдельно от остального кода.
Название неудачное, так как data - ничего не значит и твой метод превращается в просто get().
>>70145
Ты все переусложнил. Зачем создавать батник, если команду можно выполнить напрямую через exec()?
Также, можно использовать неизменный bat-файл, а переменную передавать через аргументы командной строки или переменную окружения.
Ну и в твоем коде по моему проблема подстановки переменной решена.
>>69987
То, что можно посчитать в работнике, считаешь в работнике. То, что можно в департаменте - считаешь в департаменте. Иначе в компании.
>>69901
Выглядит верно. Если есть ошибки, то было бы хорошо привести пример чисел, для которых считает неверно (если ты изучил функции, ты можешь поместить код в функцию и в цикле вызывать ее для всех сочетаний чисел).
Правильно.
> $x<=1000000
Если есть ровно миллион, то цикл продолжать не надо.
> $x=$x+$x0.1
$x = 1.1;
А в остальном верно.
> https://ideone.com/Z4KTPg -айфон
> if(($credit=($creditBalance$percent)+$servicePayment)>=5000) {
Не надо пытаться в одну строчку уместить несколько разных действий. Присваивание значения $credit = ... надо вынести на отдельную строчку, так как иначе тяжело читать. А код должен быть как можно проще и понятнее.
> }elseif(($credit=($creditBalance$percent)+$servicePayment)<5000){
Тут лучше писать просто else без условия.
> $creditBalance=$credit-$credit;
$creditBalance = 0;
Результат верный, но код не очень понятен.
Верно.
Верно.
Верно.
Правильно.
Верно
Верно.
Ок, правильно
> http://sandbox.onlinephpfunctions.com/code/ddbfd936d08c514e856f076c0b08c1e55b93ebc1 -палиндром
> if(($first=mb_substr($textToLower,$i,1))==($last=mb_substr($textToLower,$lastLetter,1))){
Не надо писать такое длинное и непонятное условие.
Вместо переменной count проще было сделать переменную $isPalindrome = 1 и сбрасывать ее в 0 при обнаружении различий.
> https://ideone.com/foQz1L -айпад
> $initialPayment=7777;
Это лучше вынести из функции, и вообще, вынести из нее все числа, чтобы она была универсальнее.
> if($commission==0){
> $creditBalance=$creditBalance+$initialPayment;
> $commission--;
Это выглядит как костыль. Зачем ставить комиссию -1? Нелогично. Лучше просто сделать отдельный аргумент "доп. комиссия" и в начале функции добавлять ее к сумме.
В общем, код надо бы упростить.
Все правильно.
Название неудачное, так как data - ничего не значит и твой метод превращается в просто get().
>>70145
Ты все переусложнил. Зачем создавать батник, если команду можно выполнить напрямую через exec()?
Также, можно использовать неизменный bat-файл, а переменную передавать через аргументы командной строки или переменную окружения.
Ну и в твоем коде по моему проблема подстановки переменной решена.
>>69987
То, что можно посчитать в работнике, считаешь в работнике. То, что можно в департаменте - считаешь в департаменте. Иначе в компании.
>>69901
Выглядит верно. Если есть ошибки, то было бы хорошо привести пример чисел, для которых считает неверно (если ты изучил функции, ты можешь поместить код в функцию и в цикле вызывать ее для всех сочетаний чисел).
Правильно.
> $x<=1000000
Если есть ровно миллион, то цикл продолжать не надо.
> $x=$x+$x0.1
$x = 1.1;
А в остальном верно.
> https://ideone.com/Z4KTPg -айфон
> if(($credit=($creditBalance$percent)+$servicePayment)>=5000) {
Не надо пытаться в одну строчку уместить несколько разных действий. Присваивание значения $credit = ... надо вынести на отдельную строчку, так как иначе тяжело читать. А код должен быть как можно проще и понятнее.
> }elseif(($credit=($creditBalance$percent)+$servicePayment)<5000){
Тут лучше писать просто else без условия.
> $creditBalance=$credit-$credit;
$creditBalance = 0;
Результат верный, но код не очень понятен.
Верно.
Верно.
Верно.
Правильно.
Верно
Верно.
Ок, правильно
> http://sandbox.onlinephpfunctions.com/code/ddbfd936d08c514e856f076c0b08c1e55b93ebc1 -палиндром
> if(($first=mb_substr($textToLower,$i,1))==($last=mb_substr($textToLower,$lastLetter,1))){
Не надо писать такое длинное и непонятное условие.
Вместо переменной count проще было сделать переменную $isPalindrome = 1 и сбрасывать ее в 0 при обнаружении различий.
> https://ideone.com/foQz1L -айпад
> $initialPayment=7777;
Это лучше вынести из функции, и вообще, вынести из нее все числа, чтобы она была универсальнее.
> if($commission==0){
> $creditBalance=$creditBalance+$initialPayment;
> $commission--;
Это выглядит как костыль. Зачем ставить комиссию -1? Нелогично. Лучше просто сделать отдельный аргумент "доп. комиссия" и в начале функции добавлять ее к сумме.
В общем, код надо бы упростить.
Все правильно.
> Как нормально отрисовать название департаментов?
str_pad не работает с кирилицей. Тебе нужно вычислить длину строки через mb_strlen и добавить пробелов с помощью str_repeat. Урок: https://github.com/codedokode/pasta/blob/master/php/strings-utf8.md
>>69516
не знаю ((
>>69509
> foreach ($classmates as $name => $height) {
> }
У тебя цикл с пустым телом (тело цикла находится между { и }). То есть он обходит массив, и для каждого элемента ничего не делает.
> if ($height>$anonHeight);{
> $number++;
> }
Тут тоже ошибки:
- этот код должен быть внутри тела цикла, чтобы для каждого ученика ты бы проверял его рост. У тебя код - после цикла и выполняется всего 1 раз, а не много.
- точка с запятой завершает команду. То есть в теле if ничего нету, ни одной команды. Потому твой код читается как
if ($height>$anonHeight)
{
// ничего не делать
}
// Блок if на этом закончен, он ничего не делает
// Этот блок действий выполняется в любом случае независимо от условия в if
{
$number++;
}
Таким образом, в твоем коде один раз выполняется команда $number++ и $number всегда будет равен 1 независимо от исходных данных.
Давай я уточню еще про синтаксис. Одиночный if (без else) имеет такой синтаксис:
> if (условие) действие
Где действие - это:
- или одна команда, завершающаяся точкой с запятой: if (...) echo "Yes";
- или ничего (пустая команда): if (...);
- или блок команд в фигурных скобках if (...) { команда; команда; ... }
У тебя тут выбран вариант "ничего".
Синтаксис foreach такой:
> foreach (массив as $переменная) действие
где "действие" имеет тот же смысл, что и в if.
Будь внимательнее к знакам препинания.
> Как нормально отрисовать название департаментов?
str_pad не работает с кирилицей. Тебе нужно вычислить длину строки через mb_strlen и добавить пробелов с помощью str_repeat. Урок: https://github.com/codedokode/pasta/blob/master/php/strings-utf8.md
>>69516
не знаю ((
>>69509
> foreach ($classmates as $name => $height) {
> }
У тебя цикл с пустым телом (тело цикла находится между { и }). То есть он обходит массив, и для каждого элемента ничего не делает.
> if ($height>$anonHeight);{
> $number++;
> }
Тут тоже ошибки:
- этот код должен быть внутри тела цикла, чтобы для каждого ученика ты бы проверял его рост. У тебя код - после цикла и выполняется всего 1 раз, а не много.
- точка с запятой завершает команду. То есть в теле if ничего нету, ни одной команды. Потому твой код читается как
if ($height>$anonHeight)
{
// ничего не делать
}
// Блок if на этом закончен, он ничего не делает
// Этот блок действий выполняется в любом случае независимо от условия в if
{
$number++;
}
Таким образом, в твоем коде один раз выполняется команда $number++ и $number всегда будет равен 1 независимо от исходных данных.
Давай я уточню еще про синтаксис. Одиночный if (без else) имеет такой синтаксис:
> if (условие) действие
Где действие - это:
- или одна команда, завершающаяся точкой с запятой: if (...) echo "Yes";
- или ничего (пустая команда): if (...);
- или блок команд в фигурных скобках if (...) { команда; команда; ... }
У тебя тут выбран вариант "ничего".
Синтаксис foreach такой:
> foreach (массив as $переменная) действие
где "действие" имеет тот же смысл, что и в if.
Будь внимательнее к знакам препинания.
Поставить после цикла в конце программы echo. У тебя оно стоит в цикле и срабатывает на каждом шаге цикла.
>>69430
Достаточно просто переменной, куда запоминается предыдущее действие.
У тебя почти правильный код, просто там есть одна ошибка. Найдешь? Если сложно, сделай вывод всех переменых на каждом шаге цикла.
Вместо substr лучше приучаться использовать mb_substr, так как substr не работает с кирилицей в utf-8.
>>69223
Решено верно.
>>69245
the requested operation has failed - это ничего не говорит. Это значит только, что утилита запуска Апача не смогла запустить службу, но почему - не говорит. Смотри лог ошибок Апача (в папке Апача), там должна быть причина.
>>69210
Делай testHub из шапки на Симфони. ну или проект, который тебе самому нравится.
>>69167
Не, не сарказм, спасибр за такую обратную связь. Может, надо подробнее объяснить, что такое "тело цикла".
>>69145
Ну давай подумаем. Вот допустим, мы возьмем и заджойним таблицу юзеров на таблицу лайков по id пользователя. Мы получим что-то такое:
name | user_id | whom_like
Иван | 1 | 3
Иван | 1 | 4
Иван | 1 | 5
То есть к каждому пользователю приджойнятся все лайки, которые он поставил. Если мы сгруппируем таблицу по пользователю, то получим число лайков.
Как посчитать число полученных лайков? Ну ясен пень, аналогично, только джойнить надо по полю whom_like:
name | user_id | whom_like
Иван | 7 | 1
Иван | 8 | 1
Иван | 9 | 1
А как посчитать и то, и другое? Приджойнить к пользователям таблицу likes 2 раза по разным условиям. Тогда, правда, появляется проблема, что мы получим полное декартовое произведение таблиц лайков. То есть для Ивана мы получим 9 строк со всеми возможными комбинациями лайков, которые он ставил и получал. И после группировки COUNT() нам вернет число 9.
Выглядит оно как-то так (для одного пользователя):
name | l1.user_id | l1.whom_like | l2.user_id | l2.whom_like
Иван | 1 | 3 | 7 | 1
Иван | 1 | 3 | 8 | 1
Иван | 1 | 3 | 9 | 1
Иван | 1 | 4 | 7 | 1
Иван | 1 | 4 | 8 | 1
Иван | 1 | 4 | 9 | 1
Иван | 1 | 5 | 7 | 1
Иван | 1 | 5 | 8 | 1
Иван | 1 | 5 | 9 | 1
Но ведь мы можем использовать не только COUNT(), но и другие агрегатные функции:
- англ https://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html
- рус http://www.mysql.ru/docs/man/Group_by_functions.html
Остается только вопрос, как найти число взаимных лайков?
Посмотри на таблицу выше и подумай, как в ней выглядит взаимный лайк. Какое условие позволяет выделить строчки с ним? После чего SUM(условие) вернет число взаимных лайков в группе. Так как в Mysql выполняющееся условие дает 1, а невыполняющееся 0.
Поставить после цикла в конце программы echo. У тебя оно стоит в цикле и срабатывает на каждом шаге цикла.
>>69430
Достаточно просто переменной, куда запоминается предыдущее действие.
У тебя почти правильный код, просто там есть одна ошибка. Найдешь? Если сложно, сделай вывод всех переменых на каждом шаге цикла.
Вместо substr лучше приучаться использовать mb_substr, так как substr не работает с кирилицей в utf-8.
>>69223
Решено верно.
>>69245
the requested operation has failed - это ничего не говорит. Это значит только, что утилита запуска Апача не смогла запустить службу, но почему - не говорит. Смотри лог ошибок Апача (в папке Апача), там должна быть причина.
>>69210
Делай testHub из шапки на Симфони. ну или проект, который тебе самому нравится.
>>69167
Не, не сарказм, спасибр за такую обратную связь. Может, надо подробнее объяснить, что такое "тело цикла".
>>69145
Ну давай подумаем. Вот допустим, мы возьмем и заджойним таблицу юзеров на таблицу лайков по id пользователя. Мы получим что-то такое:
name | user_id | whom_like
Иван | 1 | 3
Иван | 1 | 4
Иван | 1 | 5
То есть к каждому пользователю приджойнятся все лайки, которые он поставил. Если мы сгруппируем таблицу по пользователю, то получим число лайков.
Как посчитать число полученных лайков? Ну ясен пень, аналогично, только джойнить надо по полю whom_like:
name | user_id | whom_like
Иван | 7 | 1
Иван | 8 | 1
Иван | 9 | 1
А как посчитать и то, и другое? Приджойнить к пользователям таблицу likes 2 раза по разным условиям. Тогда, правда, появляется проблема, что мы получим полное декартовое произведение таблиц лайков. То есть для Ивана мы получим 9 строк со всеми возможными комбинациями лайков, которые он ставил и получал. И после группировки COUNT() нам вернет число 9.
Выглядит оно как-то так (для одного пользователя):
name | l1.user_id | l1.whom_like | l2.user_id | l2.whom_like
Иван | 1 | 3 | 7 | 1
Иван | 1 | 3 | 8 | 1
Иван | 1 | 3 | 9 | 1
Иван | 1 | 4 | 7 | 1
Иван | 1 | 4 | 8 | 1
Иван | 1 | 4 | 9 | 1
Иван | 1 | 5 | 7 | 1
Иван | 1 | 5 | 8 | 1
Иван | 1 | 5 | 9 | 1
Но ведь мы можем использовать не только COUNT(), но и другие агрегатные функции:
- англ https://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html
- рус http://www.mysql.ru/docs/man/Group_by_functions.html
Остается только вопрос, как найти число взаимных лайков?
Посмотри на таблицу выше и подумай, как в ней выглядит взаимный лайк. Какое условие позволяет выделить строчки с ним? После чего SUM(условие) вернет число взаимных лайков в группе. Так как в Mysql выполняющееся условие дает 1, а невыполняющееся 0.
Не знаю, но при перед проектированием обязательно изучи нормализацию и внешние ключи.
У меня есть урочек про нормализацию:
- https://github.com/codedokode/pasta/blob/master/db/normalization.md
- и еще по теме https://github.com/codedokode/pasta/blob/master/db/trees.md
- и еще https://github.com/codedokode/pasta/blob/master/db/databases.md#Теория-по-проектированию-БД
>>68518
Лучше освоить консольный клиент (клиент для командной строки) и руками писать запросы первое время.
Также можно писать запросы в текстовом файле и выполнять командой вроде
mysql -uuser -ppassword database < file.sql
>>68516
Почитай про umask. Наверно у процесса Апача/PHP стоит umask который снимает часть прав.
>>68260
> $this->rate = 2;
Эта строчка сохраняет новое значение в поле rate и при втором вызове расчета он зарплату покажет в 2 раза выше. Попробуй несколько раз вызвать getTotalPayment() и сравни результаты.
> if($hour > 40) {
> $overdraft = $hour - 40;
Этот if заменяется на функции max/min.
> substr(
Не работает с кирилицей, используй mb_substr.
> '/([a-zA-Z]) /';
Нет флага u для поддержки кирилицы.
Строку "Всего" проще всего посчитать руками, то есть завести переменные, и в цикле добавлять в них данные по каждому работнику. После цикла вывести.
Еще можно заморочиться с array_sum/array_map. Сделать с помощью array_map массив зарплат и просуммировать с помощью array_sum.
Имена функций начинаются с глагола. В остальном верно.
Не знаю, но при перед проектированием обязательно изучи нормализацию и внешние ключи.
У меня есть урочек про нормализацию:
- https://github.com/codedokode/pasta/blob/master/db/normalization.md
- и еще по теме https://github.com/codedokode/pasta/blob/master/db/trees.md
- и еще https://github.com/codedokode/pasta/blob/master/db/databases.md#Теория-по-проектированию-БД
>>68518
Лучше освоить консольный клиент (клиент для командной строки) и руками писать запросы первое время.
Также можно писать запросы в текстовом файле и выполнять командой вроде
mysql -uuser -ppassword database < file.sql
>>68516
Почитай про umask. Наверно у процесса Апача/PHP стоит umask который снимает часть прав.
>>68260
> $this->rate = 2;
Эта строчка сохраняет новое значение в поле rate и при втором вызове расчета он зарплату покажет в 2 раза выше. Попробуй несколько раз вызвать getTotalPayment() и сравни результаты.
> if($hour > 40) {
> $overdraft = $hour - 40;
Этот if заменяется на функции max/min.
> substr(
Не работает с кирилицей, используй mb_substr.
> '/([a-zA-Z]) /';
Нет флага u для поддержки кирилицы.
Строку "Всего" проще всего посчитать руками, то есть завести переменные, и в цикле добавлять в них данные по каждому работнику. После цикла вывести.
Еще можно заморочиться с array_sum/array_map. Сделать с помощью array_map массив зарплат и просуммировать с помощью array_sum.
Имена функций начинаются с глагола. В остальном верно.
У тебя там идут ошибки, внизу страницы:
> PHP Notice: Undefined variable: allRates in /home/FAy6n4/prog.php on line 88
надо бы исправить.
Так, те же замечания, что по предыдущей версии.
>>68040
Дело в том, что PHP не на 100% ООП, и в нем, кроме исключений есть еще ошибки (то есть notice, warning, error, fatal error). Это другой, старый, механизм:
- http://anton.shevchuk.name/php/php-for-beginners-error-handling/
- http://php.net/manual/ru/book.errorfunc.php
- http://php.net/manual/ru/function.error-reporting.php
- http://php.net/manual/ru/function.set-error-handler.php
Попробуй разобраться.
Что особенно доставляет, так это то, что половина ошибок не останавливает выполнение скрипта. Например, обращение к несуществующей переменной или отсустствующему элементу массива.
К счастью, у нас есть простой способ превратить их в привычные исключения. Для этого мы ставим обработчик ошибок и в нем выкидываем исключение. Он описан тут:
- http://php.net/manual/ru/class.errorexception.php
Это конечно дичь, особенно трюк с register_shutdown_handler, чтобы поймать фатальную ошибку. Хорошо в Яве, Яваскрипте, Питоне, там есть только исключения и никаких других ошибок нету.
Но ловить их я бы не советовал. Если ты делишь на ноль - надо код исправлять, а не ловить исключение. Ловить лучше исключения, для которых сделан отдельный класс.
У тебя там идут ошибки, внизу страницы:
> PHP Notice: Undefined variable: allRates in /home/FAy6n4/prog.php on line 88
надо бы исправить.
Так, те же замечания, что по предыдущей версии.
>>68040
Дело в том, что PHP не на 100% ООП, и в нем, кроме исключений есть еще ошибки (то есть notice, warning, error, fatal error). Это другой, старый, механизм:
- http://anton.shevchuk.name/php/php-for-beginners-error-handling/
- http://php.net/manual/ru/book.errorfunc.php
- http://php.net/manual/ru/function.error-reporting.php
- http://php.net/manual/ru/function.set-error-handler.php
Попробуй разобраться.
Что особенно доставляет, так это то, что половина ошибок не останавливает выполнение скрипта. Например, обращение к несуществующей переменной или отсустствующему элементу массива.
К счастью, у нас есть простой способ превратить их в привычные исключения. Для этого мы ставим обработчик ошибок и в нем выкидываем исключение. Он описан тут:
- http://php.net/manual/ru/class.errorexception.php
Это конечно дичь, особенно трюк с register_shutdown_handler, чтобы поймать фатальную ошибку. Хорошо в Яве, Яваскрипте, Питоне, там есть только исключения и никаких других ошибок нету.
Но ловить их я бы не советовал. Если ты делишь на ноль - надо код исправлять, а не ловить исключение. Ловить лучше исключения, для которых сделан отдельный класс.
В задаче даны примеры номеров, надо бы их все проверить, как твой код их распознает.
Так, регулярка выглядит верно.
Объединять 2 регулярки особо смысла нет. Можно вроде поместить их в массив и передать массив в preg-replace, подробности в мануале.
> В задачке все переменные, кроме регулярки я обозвал $number. Нужно ли было их называть по задаче которую они выполняют? прим. $check $cleaned $matches и т.д.
Это важно?
В данном случае нет, так как промежуточные варианты номера никому не нужны, и разные переменные будут только запутывать.
>>69521
JSON лучше тем, что его можно читать не только из PHP, а из любого языка. Сериализованная строка привязана к PHP, более того, формат не стандартизован и может меняться между версиями PHP. не надо его никуда сохранять надолго.
Также, десериализация значения, которое дал пользователь, может привести к уязвимости. Гугли.
>>67573
Если БД поддерживает массив, то можно как массив. А можно как JSON.
>>71330
Может, ничто не мешает. Но может скрипт проверки капчи ставит какую-то переменную в сессии, без которой форма не принимается? Проверь-ка:
- код скрипта form.php, есть ли там проверки
- что шлется в form.php и можно ли это слать из браузера с чистыми куками (из режима инкогнито)? Посмотреть, что шлется, можно на вкладке network в инструментах разработчика (Ctrl + Shift + I).
- если капча проверяется и ставится какой-то параметр в сессии/в куках, нельзя ли решить ее один раз и после этого фигачить запросы в form.php?
В задаче даны примеры номеров, надо бы их все проверить, как твой код их распознает.
Так, регулярка выглядит верно.
Объединять 2 регулярки особо смысла нет. Можно вроде поместить их в массив и передать массив в preg-replace, подробности в мануале.
> В задачке все переменные, кроме регулярки я обозвал $number. Нужно ли было их называть по задаче которую они выполняют? прим. $check $cleaned $matches и т.д.
Это важно?
В данном случае нет, так как промежуточные варианты номера никому не нужны, и разные переменные будут только запутывать.
>>69521
JSON лучше тем, что его можно читать не только из PHP, а из любого языка. Сериализованная строка привязана к PHP, более того, формат не стандартизован и может меняться между версиями PHP. не надо его никуда сохранять надолго.
Также, десериализация значения, которое дал пользователь, может привести к уязвимости. Гугли.
>>67573
Если БД поддерживает массив, то можно как массив. А можно как JSON.
>>71330
Может, ничто не мешает. Но может скрипт проверки капчи ставит какую-то переменную в сессии, без которой форма не принимается? Проверь-ка:
- код скрипта form.php, есть ли там проверки
- что шлется в form.php и можно ли это слать из браузера с чистыми куками (из режима инкогнито)? Посмотреть, что шлется, можно на вкладке network в инструментах разработчика (Ctrl + Shift + I).
- если капча проверяется и ставится какой-то параметр в сессии/в куках, нельзя ли решить ее один раз и после этого фигачить запросы в form.php?
> Может, ничто не мешает. Но может скрипт проверки капчи ставит какую-то переменную в сессии, без которой форма не принимается? Проверь-ка:
> - код скрипта form.php, есть ли там проверки
> - что шлется в form.php и можно ли это слать из браузера с чистыми куками (из режима инкогнито)? Посмотреть, что шлется, можно на вкладке network в инструментах разработчика (Ctrl + Shift + I).
> - если капча проверяется и ставится какой-то параметр в сессии/в куках, нельзя ли решить ее один раз и после этого фигачить запросы в form.php?
Все хуже чем я думал, в скрипте формы идет проверка пустой ли массив пост(даже не проверка реквест метода), иначе показывает пикрелейтед. А проверка капчи просто отдает аяксу ошибки в джейсоне, и если их нет то он фигачит еще один запрос уже к форме. Уххххх...надеюсь те самые 80% веба на пхп не выглядят именно так. Короче у меня есть мысль сделать один нормальный аякс запрос, а не два вложенных, и проверять все в одном месте. Получается что капча есть, но она не против роботов, а против людей.
С простой или сложной версией? И что непонятно?
В простой версии используется "жадный" алгоритм. Мы берем купюры, начиная с самых крупных и берем по максимуму каждой купюры.
Например
Купюры: 5000, 1000, 500, 100
Сумма 8200
Берем сначала купюру 5000 и делим 8200 / 5000. Получаем 1 с копейками, значит берем 1 такую купюру и в остатке 3200
Затем берем купюру в 1000 и делим 3200 / 1000. Получаем 3 купюры и в остатке 200.
И так далее.
Для сложной версии набери в гугле "задача банкомат". Это разновидность так называемой "задачи о ранце".
Спасибо, няша :3
>с помощью min/max.
Спасибо за подсказки, но я не мог это использовать, так как о них не рассказал учебник же!
>>71364
>надо подробнее объяснить, что такое "тело цикла".
Надо объяснять подробнее момент когда цикл проходит первый раз и значения переменных внутри тела уже получаются другие.Не уверен, правильно ли я это понял
Оставляй немного ссылок по теме урока в конце, где более подробное объяснениепо возможности с комментарием на что обратить внимание, которое может помочь решению задачи.Было бы охуенно.
Реквестирую задачи по циклам и условиям
И еще такой вопрос: сколько у кого ушло времени на учебник ОПа?мне это нужно чтобы слишком не охуевать - много отвлекаюсь и ленюсь, мотивации нет
>И еще такой вопрос: сколько у кого ушло времени на учебник ОПа?
У меня по ощущениям ушло часов 20-30 на простые задачки и теорию. И ещё столько же на всякие ООП и доп задания. Точно не считал. Может и больше.
https://github.com/richBlueElephant/phpClub/issues/21#issuecomment-380116215
>Для того, чтобы отлавливать клики с фильтром по определенному селектору, есть $.on: http://api.jquery.com/on/
От такого способа пришлось отказаться, потому что нужно чтобы при клике снаружи привью оно убралось.
Кстати, проверка чтобы при клике на само привью оно не убиралось не сработала.
if (!$('.fullsize').is(e.tareget)) { //somehow it doesn't works
$(lightbox).hide();
$(lightbox).empty();
}
У вас есть мысли почему?
>Для проверки, что мы кликнули на элемент, лучше всего использовать $.on, или конструкцию $(target).closest('.file a').length - она делает поиск от элемента к корню дерева. Опять же, вместо сложного селектора тут лучше было бы вписать только один класс.
>
>Еще есть $(target).is('.file a') - но она проверяет на точное совпадение с селектором.
Не совсем понимаю о чем идет речь. У меня же и так идёт проверка !$(a).is(e.target).
И зачем нужно искать ближайщую ссылку от цели? Это же можно будет кликнуть в любом месте поста и откроется привьюшка.
>На все ключевые элементы поставить свой класс. Для выбора названий классов лучше всего (по моим ощущениям) использовать БЭМ, а в верстке макабы классы расставлены от балды без всякой логики.
Я переработал и HTML разметку, однако, на некоторых вложенных элементах не стоят классы. Согласно именованию в БЭМ, в каждом элементе должно быть и имя блока, в котором он содержится. В идеале нужно переработать и это?
Ключевым элементом имеется ввиду, элемент, с которым мы работаем или будем работать?
>default:
>window.open(src, '_blank');
>
>Это вообще наверно писать не надо, лучше просто выйти из обработчика, не отменяя действие по умолчанию.
Если убрать отмену действия по умолчанию, то каждый раз, даже при открытии привью, картинка будет открываться в новой вкладке. Есть какой-то другой способ избежать этого?
>$(content).ready
>
>Вообще, центрирование идеальнее всего сделать средствами CSS (через position: absolute, table-cell либо flexbox, последний умеет ужимать картинку до размера контейнера), либо, если невозможно, то надо ловить события load/error на картинке, а не ready.
>Кстати, при изменении размера окна надо перецентрировать картинку заново. Потому лучше было бы поискать способы центрировать ее через CSS.
У меня не получилось отцентрировать по вертикали абсолютно позиционированный элемент https://jsfiddle.net/5zgteu99/
>preventDefault лучше делать только, если мы успешно обработали клик, а не всегда.
А как выполняющая preventDefault функция выполниться, если обработка не прошла успешно?
>Для закрытия картинки лучше бы предусмотреть кнопку-крестик
А разве клика за пределами привьею не достаточно?
>а также можно положить под картинку снизу прозрачную или полупрозрачную подкладку и ловить клики на ней.
Ха, так сделать было слишком просто, но с этим есть проблема - под подкладкой нельзя выделять текст, пока она не исчезнет.
https://github.com/richBlueElephant/phpClub/issues/21#issuecomment-380116215
>Для того, чтобы отлавливать клики с фильтром по определенному селектору, есть $.on: http://api.jquery.com/on/
От такого способа пришлось отказаться, потому что нужно чтобы при клике снаружи привью оно убралось.
Кстати, проверка чтобы при клике на само привью оно не убиралось не сработала.
if (!$('.fullsize').is(e.tareget)) { //somehow it doesn't works
$(lightbox).hide();
$(lightbox).empty();
}
У вас есть мысли почему?
>Для проверки, что мы кликнули на элемент, лучше всего использовать $.on, или конструкцию $(target).closest('.file a').length - она делает поиск от элемента к корню дерева. Опять же, вместо сложного селектора тут лучше было бы вписать только один класс.
>
>Еще есть $(target).is('.file a') - но она проверяет на точное совпадение с селектором.
Не совсем понимаю о чем идет речь. У меня же и так идёт проверка !$(a).is(e.target).
И зачем нужно искать ближайщую ссылку от цели? Это же можно будет кликнуть в любом месте поста и откроется привьюшка.
>На все ключевые элементы поставить свой класс. Для выбора названий классов лучше всего (по моим ощущениям) использовать БЭМ, а в верстке макабы классы расставлены от балды без всякой логики.
Я переработал и HTML разметку, однако, на некоторых вложенных элементах не стоят классы. Согласно именованию в БЭМ, в каждом элементе должно быть и имя блока, в котором он содержится. В идеале нужно переработать и это?
Ключевым элементом имеется ввиду, элемент, с которым мы работаем или будем работать?
>default:
>window.open(src, '_blank');
>
>Это вообще наверно писать не надо, лучше просто выйти из обработчика, не отменяя действие по умолчанию.
Если убрать отмену действия по умолчанию, то каждый раз, даже при открытии привью, картинка будет открываться в новой вкладке. Есть какой-то другой способ избежать этого?
>$(content).ready
>
>Вообще, центрирование идеальнее всего сделать средствами CSS (через position: absolute, table-cell либо flexbox, последний умеет ужимать картинку до размера контейнера), либо, если невозможно, то надо ловить события load/error на картинке, а не ready.
>Кстати, при изменении размера окна надо перецентрировать картинку заново. Потому лучше было бы поискать способы центрировать ее через CSS.
У меня не получилось отцентрировать по вертикали абсолютно позиционированный элемент https://jsfiddle.net/5zgteu99/
>preventDefault лучше делать только, если мы успешно обработали клик, а не всегда.
А как выполняющая preventDefault функция выполниться, если обработка не прошла успешно?
>Для закрытия картинки лучше бы предусмотреть кнопку-крестик
А разве клика за пределами привьею не достаточно?
>а также можно положить под картинку снизу прозрачную или полупрозрачную подкладку и ловить клики на ней.
Ха, так сделать было слишком просто, но с этим есть проблема - под подкладкой нельзя выделять текст, пока она не исчезнет.
Я над каждой задачей начиная с цикла сижу не один день без малейшего понятия что делать. Просто туплю смотря на код. Когда начинаю читать http://php.net/manual как пособие - понимаю 25%. Похоже, пора бы уже сделать это.
Почему если я ставлю в 18 строке else вмусто elseif получается:
>PHP Parse error: syntax error, unexpected ';' in /home/84WF9r/prog.php on line 19
условие идет после if (if/elseif) а не после else.
Пояснил тебе за щеку.
Это тред посвященный языку программированию PHP. Тут обсуждают вещи так или иначе связанные с ним.
А что именно непонятно? Слово ::class или что-то еще?
::class - это встроенная константа, которая возвращает полное имя класса с неймспейсами. http://php.net/manual/ru/language.oop5.constants.php
Например,
use \X\Y;
echo Y\Z::class;
выведет X\Y\Z.
Если тебе непонятно, что такое неймспейсы, то урок https://github.com/codedokode/pasta/blob/master/php/autoload.md
Если еще что-то непонятно, напиши, что именно, а я дам совет, что почитать.
>>71794
Вопрос был про PHP.
Нужен риалтайм, сокеты и тп.
Это подобие SPA игра
И нода там нужна для чатов и подобного
Но в прочие моменты, думал юзать php7,
вроде же он быстрее и инфраструктура вокруг него побольше.
>>61188
Если ты используешь PHP7, то добавляй в код тайп-хинты: http://php.net/manual/ru/functions.arguments.php#functions.arguments.type-declaration
Они делают код понятнее, а также защищают от ошибок.
> if($this->correctOption == $answer) return 1;
По PSR требуется использовать фигурные скобки в таких случаях. Без них может появляться неоднозначность и неудобно править код.
> public function checkAnswer($answer){
У фукнций фигурная скобка по PSR пишется на новой строке.
> $this->correctOption = $stringCorrect;
> $this->deviation = $numberDeviation;
Одинаковые вещи лучше всего называть одинаково, а не придумывать им разные названия.
В остальном, верно.
https://github.com/sergnik1995/OOPtasks/blob/master/OOO_Vector.php
Тут, на мой взгляд, неудачная идея засовывать вывод таблицы в класс Company. Лучше в класс Company помещать код, который можно повторно использовать для решения других задач. А вывод этой таблицы никак нельзя повторно где-то еще использовать. Лучше сделать для этого отдельную функцию.
То есть сделать зоной ответственности Company только хранение и получение данных о компании, а не их вывод. Потому что этот метод вывода, он очень специфичный, тебе понадобится таблица чуть другого вида, и ты добавишь еще один метод? Так класс быстро превратится в свалку разного кода.
> public function getAverageWorkers(){
Этот метод (как и остальные методы average) можно написать гораздо короче, как return $this->getTotalWorkers() / $this->countDepartments(); Не надо копипастить один и тот же код 2 раза.
Округление делать не надо. Завтра тебе понадобится сделать вывод данных с 3 знаками после запятой, и ты напишешь второй метод? Или добавишь параметр для выбора способа округления? Лучше возвращать результат, как есть, а округлять его там, где он выводится. Ты здесь вместо универсального метода сделал метод, который годится только для вывода одной конкретной таблицы.
Тут важно понимать это разделение ответственности:
- ответственность Company - это возвращать данные о компании. Не думая, где они будут использоваться.
- ответственность какого-то другого кода их округлять и выводить в виде таблицы
Вместо передачи департаментов в конструктор наверно удобнее сделать метод для их добавления. То же касается класса Департамент - лучше сделать метод для найма и для увольнения работника.
> public function __construct(array $a)
Плохое название переменной. Как понять, что в ней должно быть? Я не понимаю.
> public function __construct(string $a, array $b){
То же самое.
Так как ты используешь PHP7, не забывай ставить тайп-хинты на результат функции, например:
public function getTotalLists():int { ... }
> $count = 0;
> foreach($this->workers as $worker){
> $count++;
Есть функция count($this->workers).
> if($this->prof == "me") {
> if($this->prof == "ma") {
В такой ситуации (выбор одного из нескольких вариантов) надо использовать константы в классе, например
const JOB_MANAGER = 'ma';
Константы во-первых, защищают от опечаток (будет выдана ошибка, а у тебя опечатка останется незамеченной), во-вторых, позволяют увидеть все возможные варианты профессий, в-третьих, в IDE позволяют использовать автодополнение.
Но этот подход имеет недостаток, что при добавлении новой профессии надо обходить весь код и добавлять новые блоки elseif. Это плохо, так как реальные программы имеют огромный размер и это требует много времени. Тут лучше было бы представить профессии в виде классов, в которых задается базовая зарплата, кофе и тд. Чтобы для добавления новой профессии достаточно было дописать один класс и не трогать остальной код.
> function padRight($string, $length){
Функцию можно сделать более универсальной, если она не будет выводить строку, а возвращать. А так, у тебя ее нельзя использовать для чего-то кроме вывода данных.
Ну и хотелось бы увидеть вариант с антикризисными мерами.
>>61188
Если ты используешь PHP7, то добавляй в код тайп-хинты: http://php.net/manual/ru/functions.arguments.php#functions.arguments.type-declaration
Они делают код понятнее, а также защищают от ошибок.
> if($this->correctOption == $answer) return 1;
По PSR требуется использовать фигурные скобки в таких случаях. Без них может появляться неоднозначность и неудобно править код.
> public function checkAnswer($answer){
У фукнций фигурная скобка по PSR пишется на новой строке.
> $this->correctOption = $stringCorrect;
> $this->deviation = $numberDeviation;
Одинаковые вещи лучше всего называть одинаково, а не придумывать им разные названия.
В остальном, верно.
https://github.com/sergnik1995/OOPtasks/blob/master/OOO_Vector.php
Тут, на мой взгляд, неудачная идея засовывать вывод таблицы в класс Company. Лучше в класс Company помещать код, который можно повторно использовать для решения других задач. А вывод этой таблицы никак нельзя повторно где-то еще использовать. Лучше сделать для этого отдельную функцию.
То есть сделать зоной ответственности Company только хранение и получение данных о компании, а не их вывод. Потому что этот метод вывода, он очень специфичный, тебе понадобится таблица чуть другого вида, и ты добавишь еще один метод? Так класс быстро превратится в свалку разного кода.
> public function getAverageWorkers(){
Этот метод (как и остальные методы average) можно написать гораздо короче, как return $this->getTotalWorkers() / $this->countDepartments(); Не надо копипастить один и тот же код 2 раза.
Округление делать не надо. Завтра тебе понадобится сделать вывод данных с 3 знаками после запятой, и ты напишешь второй метод? Или добавишь параметр для выбора способа округления? Лучше возвращать результат, как есть, а округлять его там, где он выводится. Ты здесь вместо универсального метода сделал метод, который годится только для вывода одной конкретной таблицы.
Тут важно понимать это разделение ответственности:
- ответственность Company - это возвращать данные о компании. Не думая, где они будут использоваться.
- ответственность какого-то другого кода их округлять и выводить в виде таблицы
Вместо передачи департаментов в конструктор наверно удобнее сделать метод для их добавления. То же касается класса Департамент - лучше сделать метод для найма и для увольнения работника.
> public function __construct(array $a)
Плохое название переменной. Как понять, что в ней должно быть? Я не понимаю.
> public function __construct(string $a, array $b){
То же самое.
Так как ты используешь PHP7, не забывай ставить тайп-хинты на результат функции, например:
public function getTotalLists():int { ... }
> $count = 0;
> foreach($this->workers as $worker){
> $count++;
Есть функция count($this->workers).
> if($this->prof == "me") {
> if($this->prof == "ma") {
В такой ситуации (выбор одного из нескольких вариантов) надо использовать константы в классе, например
const JOB_MANAGER = 'ma';
Константы во-первых, защищают от опечаток (будет выдана ошибка, а у тебя опечатка останется незамеченной), во-вторых, позволяют увидеть все возможные варианты профессий, в-третьих, в IDE позволяют использовать автодополнение.
Но этот подход имеет недостаток, что при добавлении новой профессии надо обходить весь код и добавлять новые блоки elseif. Это плохо, так как реальные программы имеют огромный размер и это требует много времени. Тут лучше было бы представить профессии в виде классов, в которых задается базовая зарплата, кофе и тд. Чтобы для добавления новой профессии достаточно было дописать один класс и не трогать остальной код.
> function padRight($string, $length){
Функцию можно сделать более универсальной, если она не будет выводить строку, а возвращать. А так, у тебя ее нельзя использовать для чего-то кроме вывода данных.
Ну и хотелось бы увидеть вариант с антикризисными мерами.
>>61188
> class CatDecisions extends Decisions
> function goUp($animals) {
> function goDown($animals) {
Это никуда не годится. Ты скопипастил стену кода, и теперь читатель кода должен эти 8 функций вычитывать и искать, где там различия. Это требует слишком много времени, никто не будет расшифровывать твой код. Нельзя его копипастить. Нужно сделать единый универсальный метод.
Да и код тяжело читать. Ну как это понимать:
> if(($animal->posY == ($this->posY-1)) && ($animal->posX == $this->posX) && ($animal->checkMouseAlone($animals) == 1)){
Это выражение даже в строчку не умещается. Код должен быть понятным и логичным, и не требовать расшифровки. А с таким кодом трудно даже сказать, правильный ли он, так как надо сидеть и на листочек выписывать все варианты координат, и проверять, все ли верно.
И в коде нет никаких пояснений или комментариев.
> if($animal->name == "mouse") {
Лучше использовать проверку вроде $animal instanceof Mouse.
Также, я не вижу, где в коде заданы и проверяются дальность зрения животных.
Непонятно, зачем дублировать 2 раза координаты, делая поля posX/posY и в животном, и в классе принятия решения. Координаты лучше хранить в одном месте.
Принятие решения можно было бы сделать в классе животного (или Decisions), а не во внешней функции. Непонятно, зачем функция вынесена отдельно.
Тут стоило бы сделать объект "карта" или "мир", который отвечает за хранение списка животных и поиск животных в определенном радиусе. У тебя же это просто хранится к каких-то отдельных массивах.
> if($decision == 'stay')
Тут наверно стоило завести константы для обозначения ходов. Или же, что лучше, сделать объект "ход" с полями x и y. Или хотя бы массив.
Цикл вывода поля с животными на экран сделан не эффективно. Там 3 вложенных цикла, и всего получается width x height x count(animals) шагов. Можно сделать проще: создать массив с пустыми клеточками, а затем обойти в цикле животных и для каждого в массив поместить букву. Это потребует меньше шагов.
> else if($animal->turnsToWakeUp > 0){
> $animal->turnsToWakeUp--;
> }
> else {
> $animal->sleep = 0;
У тебя тут непонимание принципа единственной ответственности. В ООП мы рзабиваем код на классы, у каждого из которых есть какая-то зона ответсвенности.
Код, отвечающий за сон, должен находиться в классе кошки, так как это часть ее поведения. У тебя же поведение кошки не собрано в одном классе, а размазано по всему коду (CatDecision, makeDecision(), chooseDecision(), и код в конце программы). То есть кошка не знает, когда ей спать, и внешний код должен ей об этом сообщать. Получается какая-то неполноценная кошка, которая сама по себе ничего делать не может и к которой надо снаружи приделать еще дополнительный код, чтобы она ходила.
Но идея ООП как раз в том, что у каждого класса есть своя зона ответственности, и все, что к ней относится, собрано в этом классе.
То есть, например, класс мышки знает все о мышке, а класс кошки - все о кошке. Класс карты знает список животных, которые на ней находятся.
Из-за этого в твоем коде очень сложно добавить новый вид животного. Если бы у тебя был правильный ООП-код, то достаточно было бы добавить еще один класс, а так надо просматривать весь код, и в каждый if добавлять else для нового вида животного.
Вот еще пример нарушения этого принципа: в функции
> function chooseDecision(Animal $animal, array $animals)
Делается проверка, какое у нас животное, и из этого решается, надо ли проверять диагональные ходы. Но это должно знать само животное, куда оно может ходить.
В общем, тут надо все радикально переделывать.
Перед тем как писать код, стоит спроектировать классы. Решить, какие у нас есть сущности, за что каждая отвечает, какие у них есть свойства (поля), что с ними можно делать (какие есть методы).
Если есть какие-то вопросы, задавай.
>>61188
> class CatDecisions extends Decisions
> function goUp($animals) {
> function goDown($animals) {
Это никуда не годится. Ты скопипастил стену кода, и теперь читатель кода должен эти 8 функций вычитывать и искать, где там различия. Это требует слишком много времени, никто не будет расшифровывать твой код. Нельзя его копипастить. Нужно сделать единый универсальный метод.
Да и код тяжело читать. Ну как это понимать:
> if(($animal->posY == ($this->posY-1)) && ($animal->posX == $this->posX) && ($animal->checkMouseAlone($animals) == 1)){
Это выражение даже в строчку не умещается. Код должен быть понятным и логичным, и не требовать расшифровки. А с таким кодом трудно даже сказать, правильный ли он, так как надо сидеть и на листочек выписывать все варианты координат, и проверять, все ли верно.
И в коде нет никаких пояснений или комментариев.
> if($animal->name == "mouse") {
Лучше использовать проверку вроде $animal instanceof Mouse.
Также, я не вижу, где в коде заданы и проверяются дальность зрения животных.
Непонятно, зачем дублировать 2 раза координаты, делая поля posX/posY и в животном, и в классе принятия решения. Координаты лучше хранить в одном месте.
Принятие решения можно было бы сделать в классе животного (или Decisions), а не во внешней функции. Непонятно, зачем функция вынесена отдельно.
Тут стоило бы сделать объект "карта" или "мир", который отвечает за хранение списка животных и поиск животных в определенном радиусе. У тебя же это просто хранится к каких-то отдельных массивах.
> if($decision == 'stay')
Тут наверно стоило завести константы для обозначения ходов. Или же, что лучше, сделать объект "ход" с полями x и y. Или хотя бы массив.
Цикл вывода поля с животными на экран сделан не эффективно. Там 3 вложенных цикла, и всего получается width x height x count(animals) шагов. Можно сделать проще: создать массив с пустыми клеточками, а затем обойти в цикле животных и для каждого в массив поместить букву. Это потребует меньше шагов.
> else if($animal->turnsToWakeUp > 0){
> $animal->turnsToWakeUp--;
> }
> else {
> $animal->sleep = 0;
У тебя тут непонимание принципа единственной ответственности. В ООП мы рзабиваем код на классы, у каждого из которых есть какая-то зона ответсвенности.
Код, отвечающий за сон, должен находиться в классе кошки, так как это часть ее поведения. У тебя же поведение кошки не собрано в одном классе, а размазано по всему коду (CatDecision, makeDecision(), chooseDecision(), и код в конце программы). То есть кошка не знает, когда ей спать, и внешний код должен ей об этом сообщать. Получается какая-то неполноценная кошка, которая сама по себе ничего делать не может и к которой надо снаружи приделать еще дополнительный код, чтобы она ходила.
Но идея ООП как раз в том, что у каждого класса есть своя зона ответственности, и все, что к ней относится, собрано в этом классе.
То есть, например, класс мышки знает все о мышке, а класс кошки - все о кошке. Класс карты знает список животных, которые на ней находятся.
Из-за этого в твоем коде очень сложно добавить новый вид животного. Если бы у тебя был правильный ООП-код, то достаточно было бы добавить еще один класс, а так надо просматривать весь код, и в каждый if добавлять else для нового вида животного.
Вот еще пример нарушения этого принципа: в функции
> function chooseDecision(Animal $animal, array $animals)
Делается проверка, какое у нас животное, и из этого решается, надо ли проверять диагональные ходы. Но это должно знать само животное, куда оно может ходить.
В общем, тут надо все радикально переделывать.
Перед тем как писать код, стоит спроектировать классы. Решить, какие у нас есть сущности, за что каждая отвечает, какие у них есть свойства (поля), что с ними можно делать (какие есть методы).
Если есть какие-то вопросы, задавай.
Ну запостил бы код и спросил, что именно непонятно. Может, в учебнике объяснено не очень хорошо и надо подробнее разъяснить.
>И зачем нужно искать ближайщую ссылку от цели? Это же можно будет кликнуть в любом месте поста и откроется привьюшка.
Вот в этом вопросе ошибся, потому что файлы лежат в отдельном контейнере, но всё равно не понимаю, как можно применить .closest(a) чтобы проверить, что мы кликнули на элемент.
> if (!$('.fullsize').is(e.tareget)) { //somehow it doesn't works
Там написано e.tareget.
Но вообще, ты неправильно делаешь сравнение, надо либо $(target).is(..) либо $(target).closest(), а ты делаешь поиск по всему дереву DOM ради одного сравнения.
И не надо писать $() вокруг переменной lighbox, если это и так объект jQuery.
> От такого способа пришлось отказаться, потому что нужно чтобы при клике снаружи привью оно убралось.
Это проще всего реализовать, подложив под превью прозрачный див. Ну хотя можно и проверять через is()/closest().
Также, не надо делать поиск элементов в DOM каждый раз. Проще в начале скрипта их найти и потом обращаться к этой переменной. Например, элемент #lightbox нет смысла каждый раз искать заново.
>>Еще есть $(target).is('.file a') - но она проверяет на точное совпадение с селектором.
> Не совсем понимаю о чем идет речь. У меня же и так идёт проверка !$(a).is(e.target).
Потому, что у тебя сделано неэффективно. Вот как у тебя сделано:
// запускаем обход всего огромного дерева DOM и получаем массив из сотни-двух ссылок
var a = $('a', '.file');
// Проверяем, есть ли target в этом списке, после чего отбрасываем список.
if ($(a).has(e.target).length == 0 && !$(a).is(e.target)) {
То есть ты ради проверки делаешь поиск по всему дереву DOM, и почти сразу же отбрасываешь результат. При каждом клике по странице. Это неэффективно.
Я предлагаю не делать поиск по всему дереву DOM, а просто сделать $(target).is(...). Что очевидно эффективнее. Если в селекторе указан просто класс is('.something'), то эта проверка сводится к проверке класса у текущего элемента.
closest() нужен в том случае, если мы хотим отслеживать клик по элементу, у которого есть дети. Так как клик может попасть на кого-то из детей, а не на родительский элемент. Ну например:
<div class="x">
<div class="y"></div>
<div class="z"></div>
</div>
Допустим, мы хотим проверить, был ли клик по элементу .x (или его детям). Мы можем написать так:
var isClicked = $(target).closest('.x').length > 0;
Такой код вернет true, если мы кликнули в .x, в .y или в .z.
> Я переработал и HTML разметку, однако, на некоторых вложенных элементах не стоят классы. Согласно именованию в БЭМ, в каждом элементе должно быть и имя блока, в котором он содержится. В идеале нужно переработать и это?
Нет, не совсем так. В БЭМ мы выделяем "независимые" блоки, которые могут быть в том числе вложены друг в друга. Например: пост, превьюшка, шапка, подвал, меню итд. Для них назначаем какие-то имена. А для их неотъемлемых частей (элементов) делаем имена с использованием имени блока. Ну например, у поста есть элемент "дата", который не является независимым, а является неотъемлемой частью поста. Для него мы сделаем имя вроде post__date. Из которого и видно, что это часть блока post.
"Независимый" - значит, что блок можно поместить в любое место любой страницы и он будет корректно отображаться и работать (при наличии достаточного места). Независимый блок не зависит от наличия каких-то родительских элементов или классов на них.
> Ключевым элементом имеется ввиду, элемент, с которым мы работаем или будем работать?
Ну я имел в виду, такие части страницы, как пост, тред, и тд. То есть то, что приходит в голову, когда пытаешься разбить страницу на блоки.
> Если убрать отмену действия по умолчанию, то каждый раз, даже при открытии привью, картинка будет открываться в новой вкладке.
Отменять действие, только если мы приняли решение показать картинку на странице. А не в любом случае вообще.
> А как выполняющая preventDefault функция выполниться, если обработка не прошла успешно?
надо убрать эту отдельную функцию и поместить preventDefault в основную функцию.
>>Для закрытия картинки лучше бы предусмотреть кнопку-крестик
> А разве клика за пределами привьею не достаточно?
А как догадаться, что можно кликнуть за пределами?
>>а также можно положить под картинку снизу прозрачную или полупрозрачную подкладку и ловить клики на ней.
> Ха, так сделать было слишком просто, но с этим есть проблема - под подкладкой нельзя выделять текст, пока она не исчезнет.
А зачем выделять текст во время просмотра картинки? Я об этом конечно не думал.
> if (!$('.fullsize').is(e.tareget)) { //somehow it doesn't works
Там написано e.tareget.
Но вообще, ты неправильно делаешь сравнение, надо либо $(target).is(..) либо $(target).closest(), а ты делаешь поиск по всему дереву DOM ради одного сравнения.
И не надо писать $() вокруг переменной lighbox, если это и так объект jQuery.
> От такого способа пришлось отказаться, потому что нужно чтобы при клике снаружи привью оно убралось.
Это проще всего реализовать, подложив под превью прозрачный див. Ну хотя можно и проверять через is()/closest().
Также, не надо делать поиск элементов в DOM каждый раз. Проще в начале скрипта их найти и потом обращаться к этой переменной. Например, элемент #lightbox нет смысла каждый раз искать заново.
>>Еще есть $(target).is('.file a') - но она проверяет на точное совпадение с селектором.
> Не совсем понимаю о чем идет речь. У меня же и так идёт проверка !$(a).is(e.target).
Потому, что у тебя сделано неэффективно. Вот как у тебя сделано:
// запускаем обход всего огромного дерева DOM и получаем массив из сотни-двух ссылок
var a = $('a', '.file');
// Проверяем, есть ли target в этом списке, после чего отбрасываем список.
if ($(a).has(e.target).length == 0 && !$(a).is(e.target)) {
То есть ты ради проверки делаешь поиск по всему дереву DOM, и почти сразу же отбрасываешь результат. При каждом клике по странице. Это неэффективно.
Я предлагаю не делать поиск по всему дереву DOM, а просто сделать $(target).is(...). Что очевидно эффективнее. Если в селекторе указан просто класс is('.something'), то эта проверка сводится к проверке класса у текущего элемента.
closest() нужен в том случае, если мы хотим отслеживать клик по элементу, у которого есть дети. Так как клик может попасть на кого-то из детей, а не на родительский элемент. Ну например:
<div class="x">
<div class="y"></div>
<div class="z"></div>
</div>
Допустим, мы хотим проверить, был ли клик по элементу .x (или его детям). Мы можем написать так:
var isClicked = $(target).closest('.x').length > 0;
Такой код вернет true, если мы кликнули в .x, в .y или в .z.
> Я переработал и HTML разметку, однако, на некоторых вложенных элементах не стоят классы. Согласно именованию в БЭМ, в каждом элементе должно быть и имя блока, в котором он содержится. В идеале нужно переработать и это?
Нет, не совсем так. В БЭМ мы выделяем "независимые" блоки, которые могут быть в том числе вложены друг в друга. Например: пост, превьюшка, шапка, подвал, меню итд. Для них назначаем какие-то имена. А для их неотъемлемых частей (элементов) делаем имена с использованием имени блока. Ну например, у поста есть элемент "дата", который не является независимым, а является неотъемлемой частью поста. Для него мы сделаем имя вроде post__date. Из которого и видно, что это часть блока post.
"Независимый" - значит, что блок можно поместить в любое место любой страницы и он будет корректно отображаться и работать (при наличии достаточного места). Независимый блок не зависит от наличия каких-то родительских элементов или классов на них.
> Ключевым элементом имеется ввиду, элемент, с которым мы работаем или будем работать?
Ну я имел в виду, такие части страницы, как пост, тред, и тд. То есть то, что приходит в голову, когда пытаешься разбить страницу на блоки.
> Если убрать отмену действия по умолчанию, то каждый раз, даже при открытии привью, картинка будет открываться в новой вкладке.
Отменять действие, только если мы приняли решение показать картинку на странице. А не в любом случае вообще.
> А как выполняющая preventDefault функция выполниться, если обработка не прошла успешно?
надо убрать эту отдельную функцию и поместить preventDefault в основную функцию.
>>Для закрытия картинки лучше бы предусмотреть кнопку-крестик
> А разве клика за пределами привьею не достаточно?
А как догадаться, что можно кликнуть за пределами?
>>а также можно положить под картинку снизу прозрачную или полупрозрачную подкладку и ловить клики на ней.
> Ха, так сделать было слишком просто, но с этим есть проблема - под подкладкой нельзя выделять текст, пока она не исчезнет.
А зачем выделять текст во время просмотра картинки? Я об этом конечно не думал.
> У меня не получилось отцентрировать по вертикали абсолютно позиционированный элемент
> position: absolute;
> display: table-cell;
Эти стили вообще не совместимы. Нельзя ячейку таблицы спозиционировать абсолютно. Ее положение определяется таблицей, ячейку нельзя вырвать из нее. Также, кстати, нельзя позиционироваться относительно ячейки или другой части таблицы.
Ок, поделюсь способами центрирования, которые у меня под рукой. Контент - это то, что центрируем, контейнер - это внутри чего центрируем. Отдельная задача - как ужать слишком большую картинку до размеров контейнера.
Вообще, способы решения делятся в зависимости от ситуации. Я сделал несколько примеров кода тут https://codepen.io/anon/pen/LdvNdW для тех методов, где код не очевиден.
задан размер контента (WxH), неизвестен размер контейнера
1) Можно сделать у контейнера pos:rel, у контента pos:abs, left/top/right/left: 0, margin: auto; height: H; width: W; - здесь margin будет вычислен из top, bottom, height. Объяснение на англ: https://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-height
2) Можно сделать у контейнера pos:rel, у контента pos:abs, top: 50%, margin-top: -(H/2)px; height: H; . Это работает с CSS2.1, если хочется ограничить себя новыми CSS3 браузерами, можно писать top: calc(50% - H/2px);
задан размер контейнера (WxH), неизвестен размер контента
1) Можно сделать в контейнере height: H; lihe-height: H;, в контенте: display: inline-block; line-height: 16px; (восстанавливаем назад) . Теория https://www.w3.org/TR/CSS2/visuren.html#inline-formatting
неизвестны ни размер контейнера, ни контента
1) Поместить картинку на фон (в background-image) и центрировать за счет background-position: 50% 50%; Ограничить ее размер можно с помощью background-size.
+ Поддерживается с давних времен: https://caniuse.com/#search=background-size (даже в IE8 за счет AlphaImageLoader)
+ Поддержка bg-size: IE 2011+, FF 2010+, Chrome 2010+, Opera 2009+, Android 2009
+ Если background-size не поддерживается, отобразится центр картинки в масштабе 1:1
+ Не вырезается почтовыми сервисами вроде gmail (почтовые сервисы фильтруют и HTML, и CSS в письмах)
- Маленькие картинки увеличиваются и размываются
- Нет поддержки srcset
2) Центрирование за счет translate
Это разновидность описанного выше трюка с абс. поз, но тут вместо ручного задания margin-top мы используем translate, который позволяет считать проценты от размера контента. Мы позиционируем содержимое с помощью top: 50%; left: 50%; (проценты относительно размера контейнера), а затем сдвигаем его в центр за счет translate(-50%, -50%) - тут проценты уже от размера содержимого.
Поддержка: https://caniuse.com/#search=translate
+ Поддержка с префиксами IE9 (2011), FF 2009, Chrome 2010, Opera 2011, Android 2009
+ Маленькие картинки центрируются и не увеличиваются
- Если transform не поддерживается, будет видна 1/4 картинки
- Почтовые сервисы не пропускают transform
Теория https://www.w3.org/TR/css-transforms-1/#terminology
3) Двойное translate
Здесь мы усложняем схему, чтобы в браузерах, не поддерживающих translate, показывалась бы не 1/4, а верхняя часть картинки. (хорошо бы конечно его протестировать получше, так как я не уверен что он 100% рабочий).
Поддержка: https://caniuse.com/#search=translate
+ Поддержка с префиксами IE9 (2011), FF 2009, Chrome 2010, Opera 2011, Android 2009
+ Маленькие картинки центрируются и не увеличиваются
+ Если transform не поддерживается, будет видна верхняя часть картинки вместо середины
+ Картинка влияет на высоту блока, которая может ограничиваться через min/max-width либо задаваться фиксированной через width
+ Можно добавить img { max-height: Npx; } , чтобы высокие картинки тоже помещались в блок
- Наибольший объем кода
- Не работает (картинка не центрируется) в mail.ru, yandex.ru, gmail.com из-за того, что почтовые сервисы не пропускают свойство transform
4) table
Контейнеру ставим display: table, в нем делаем див с display: table-cell; vertical-align: middle; text-align: center; и в него кладем картинку.
Теория https://www.w3.org/TR/CSS2/tables.html#height-layout
Минус: не уверен, что будет работать ограничение по высоте, так как содержимое таблицы может ее растягивать.
5) flexbox
Лень разбираться в спецификации, но он мощнее предыдущих методов. Однако, требует поддержки flexbox в браузере. В теории можно попробовать написать код с флексбокс и сделать фоллбек на какой-то другой метод для более старых браузеров.
> У меня не получилось отцентрировать по вертикали абсолютно позиционированный элемент
> position: absolute;
> display: table-cell;
Эти стили вообще не совместимы. Нельзя ячейку таблицы спозиционировать абсолютно. Ее положение определяется таблицей, ячейку нельзя вырвать из нее. Также, кстати, нельзя позиционироваться относительно ячейки или другой части таблицы.
Ок, поделюсь способами центрирования, которые у меня под рукой. Контент - это то, что центрируем, контейнер - это внутри чего центрируем. Отдельная задача - как ужать слишком большую картинку до размеров контейнера.
Вообще, способы решения делятся в зависимости от ситуации. Я сделал несколько примеров кода тут https://codepen.io/anon/pen/LdvNdW для тех методов, где код не очевиден.
задан размер контента (WxH), неизвестен размер контейнера
1) Можно сделать у контейнера pos:rel, у контента pos:abs, left/top/right/left: 0, margin: auto; height: H; width: W; - здесь margin будет вычислен из top, bottom, height. Объяснение на англ: https://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-height
2) Можно сделать у контейнера pos:rel, у контента pos:abs, top: 50%, margin-top: -(H/2)px; height: H; . Это работает с CSS2.1, если хочется ограничить себя новыми CSS3 браузерами, можно писать top: calc(50% - H/2px);
задан размер контейнера (WxH), неизвестен размер контента
1) Можно сделать в контейнере height: H; lihe-height: H;, в контенте: display: inline-block; line-height: 16px; (восстанавливаем назад) . Теория https://www.w3.org/TR/CSS2/visuren.html#inline-formatting
неизвестны ни размер контейнера, ни контента
1) Поместить картинку на фон (в background-image) и центрировать за счет background-position: 50% 50%; Ограничить ее размер можно с помощью background-size.
+ Поддерживается с давних времен: https://caniuse.com/#search=background-size (даже в IE8 за счет AlphaImageLoader)
+ Поддержка bg-size: IE 2011+, FF 2010+, Chrome 2010+, Opera 2009+, Android 2009
+ Если background-size не поддерживается, отобразится центр картинки в масштабе 1:1
+ Не вырезается почтовыми сервисами вроде gmail (почтовые сервисы фильтруют и HTML, и CSS в письмах)
- Маленькие картинки увеличиваются и размываются
- Нет поддержки srcset
2) Центрирование за счет translate
Это разновидность описанного выше трюка с абс. поз, но тут вместо ручного задания margin-top мы используем translate, который позволяет считать проценты от размера контента. Мы позиционируем содержимое с помощью top: 50%; left: 50%; (проценты относительно размера контейнера), а затем сдвигаем его в центр за счет translate(-50%, -50%) - тут проценты уже от размера содержимого.
Поддержка: https://caniuse.com/#search=translate
+ Поддержка с префиксами IE9 (2011), FF 2009, Chrome 2010, Opera 2011, Android 2009
+ Маленькие картинки центрируются и не увеличиваются
- Если transform не поддерживается, будет видна 1/4 картинки
- Почтовые сервисы не пропускают transform
Теория https://www.w3.org/TR/css-transforms-1/#terminology
3) Двойное translate
Здесь мы усложняем схему, чтобы в браузерах, не поддерживающих translate, показывалась бы не 1/4, а верхняя часть картинки. (хорошо бы конечно его протестировать получше, так как я не уверен что он 100% рабочий).
Поддержка: https://caniuse.com/#search=translate
+ Поддержка с префиксами IE9 (2011), FF 2009, Chrome 2010, Opera 2011, Android 2009
+ Маленькие картинки центрируются и не увеличиваются
+ Если transform не поддерживается, будет видна верхняя часть картинки вместо середины
+ Картинка влияет на высоту блока, которая может ограничиваться через min/max-width либо задаваться фиксированной через width
+ Можно добавить img { max-height: Npx; } , чтобы высокие картинки тоже помещались в блок
- Наибольший объем кода
- Не работает (картинка не центрируется) в mail.ru, yandex.ru, gmail.com из-за того, что почтовые сервисы не пропускают свойство transform
4) table
Контейнеру ставим display: table, в нем делаем див с display: table-cell; vertical-align: middle; text-align: center; и в него кладем картинку.
Теория https://www.w3.org/TR/CSS2/tables.html#height-layout
Минус: не уверен, что будет работать ограничение по высоте, так как содержимое таблицы может ее растягивать.
5) flexbox
Лень разбираться в спецификации, но он мощнее предыдущих методов. Однако, требует поддержки flexbox в браузере. В теории можно попробовать написать код с флексбокс и сделать фоллбек на какой-то другой метод для более старых браузеров.
> W5.2 Некто кладет в банк 10000 р. Банк начисляет 10% годовых (то есть, каждый год на счету становится на 10% больше, чем в прошлом году). Напиши программу, считающую, через сколько лет в банке будет миллион? Сколько лет будет этому некто? Доживет ли некто до этого дня, если сегодня ему 16 лет?
Написал что-то такое, но не работает, как нужно.
<?php
error_reporting(-1);
$balance=10000;
$percent=0.1;
$old=16;
for ($year=1; $year<1000; $year++) {
$balanceAll=($balance*$percent)+$balance;
echo" $year лет спустя депозит составит $balance\n";
if ($balanceAll>1000000){
break;
}
}
Это не так. В Яве можно возвращать null вместо объекта. null как раз и обозначает отсутствие объекта.
Насчет PHP - там исторически действительно было много бардака с функциями, возвращающими или принимающими значения разных типов. На мой взгляд, это плохо, так как создает путаницу, повышает вероятность ошибки.
В PHP7 можно (и нужно) указывать типы возврата у функций. И есть синтаксис, чтобы дать функции возможность возвращать null, например:
function x(): ?int {}
Кидать исключения надо в случае исключительных, неожиданных ситуаций и невозможности функции выполнить свою работу. Например: файл должен быть на диске, а его не оказалось. Или запись 100% должна быть в базе, а ее нет. Или функции переданы некорректные аргументы. Или SQL запрос не удалось выполнить из-за ошибки в синтаксисе.
Но если например, функция ищет что-то, и это что-то может не найтись, и мы ожидаем такую ситуацию, то вполне допустимо использовать null для обозначения этого:
function findPost($id): ?Post {}
При этом не надо бояться исключений и использовать null там, где лучше будет выбросить исключение.
Урок про исключения https://github.com/codedokode/pasta/blob/master/php/exceptions.md
>>71358
>Наверно лучше было сделать несколько регулярок, по одной на каждое правило, и массив с пояснением типа ошибки:
Я проиллюстрировал решение, в правильном ли я направлении думаю? +заготовка https://ideone.com/3utZYd
Застрял на этой задаче, похоже придется перечитывать главу про массивы.
Можно сделать так:
$regexps = [
'название ошибки' => '/.../',
'название ошибки 2' => '/.../'
];
foreach ($regexps as $comment => $regexp) {
...
}
бля, отправил случайно
как сделать первую букву большой, использовал preg_split чтобы разбить по предложениям и хз как их в массиве редактировать
<?php
$text = 'доброго времени суток. столкнулся с задачей сделать первую букву в каждом слове заглавной.доброго времени суток.';
echo preg_replace_callback('~(?:^|\.\s*)\w~u', function($m) {
return mb_strtoupper($m[0]);
}, $text);
говно какое-то, извиняй анон
1. Разбей текст на массив строк для начала. трок резделителями предложений служат .!? Стало быть если у тебя 1 из этих символов то предложение закончилось.
2. В каждой новой строке взять первый символ и заменить его на большой.
3. Склеить строки в новый текст.
Что тебе не понятно?
Этот способ перебора массива какой-то изолированный. Как мне сопоставить эти данные с найденными ошибками в $text, или найти их сразу там и вывести кусочек текста и название ошибки?
Простите, я дегенерат
Спасибо за ответы опчик, завтра-послезавтра скину переделанное.
>>72321
>>72371
Создал грамматического фашиста, буду признателен если ОП или кто-то проверит https://ideone.com/GqB1GK
Там конечно нужно $creditBalance = 0;
Условие работает так: если оставшийся долг меньше чем ежемесячный платеж, то платим только его, иначе платим $monthlyPayment
Как сделать так, чтобы действие сперва сохранялось в $op прошлая операция, а потом выполнялась над $result и $number?
я иcпользовал 2 числа и результат. в 1 число всякий раз сохранял результат, на новом шаге извлекал 2 число и считал результат. как-то так.
писать код легче чем объяснять это
Есть правило Лисков (это фамилия такая). Если говорить по-простому, то класс-наследник должен быть совместим с предком и объект наследника можно передать вместо предка, и все должно работать. Этот принцип проявляется во многих местах. Ну, например, если у нас есть функция
x(SomeClass $s)
То мы можем вместо объекта SomeClass передать и объект-наследник - он пройдет проверку в тайп-хинте. Этот принцип придуман, чтобы мы могли бы расширять классы, дополнять их и использовать в существующем коде.
Когда ты в базовом классе делаешь функцию без тайп-хинтов, а в наследнике ставишь тайп-хинт, то ты ограничиваешь набор допустимых значений. И этим ломаешь совместимость, так как значения, которые принимал базовый класс, не пройдут проверку в наследнике.
Следовательно, надо более грамотно расставить тайп-хинты.
https://ideone.com/2Yu37H
Вангую много проблем с инкапсуляцией и тайп хинтами, я не знаю что еще запротектить, а тайп хинты я просто проставил в функции, которые возвращают значения.
И говон какие-то антикризисные меры у меня похоже.
https://ideone.com/Y9Guf0
Спасибо!
>>>Для закрытия картинки лучше бы предусмотреть кнопку-крестик
>> А разве клика за пределами привьею не достаточно?
>
>А как догадаться, что можно кликнуть за пределами?
Добавил крестик и закртыие по ескпейпу. Только крестик на тёмном фоне плохо видно (посмотреть можно уже на сайте). Как это исправить?
>>>а также можно положить под картинку снизу прозрачную или полупрозрачную подкладку и ловить клики на ней.
>> Ха, так сделать было слишком просто, но с этим есть проблема - под подкладкой нельзя выделять текст, пока она не исчезнет.
>А зачем выделять текст во время просмотра картинки? Я об этом конечно не думал.
Конечно на практике я такое не делал, но мне показалось, что не хорошо получается, когда сама картинка занимает всего лишь какую-то часть страницы, а не деле всю. Это не более чем "косметическое" исправление.
>>72048
Спасибо за предоставленные способы - я возьму их себе на заметку.
Если #lightbox лежит в body, то body будет контейнером. Не слишком ли опасно проводить на теле такие операции?
Я правильно понимаю, что все эти способы подразумевают, что контейнер это подкладка, или, быть может, контейнер лучше будет поместить в подкладку? Я только не понимаю, мы центрируем элемент относительно окна, это значит, что размер заданный в процентах или flexbox/table на body, не позволит воспользоваться большинством способов. В нашем случае, наилучшим способом будет двойной translate.
Я, если честно, плохо понимаю вёрстку. К примеру, у меня почему-то картинка выходит за пределы контейнера, и я не знаю как это исправить https://jsfiddle.net/kd5bqr4j/1/
Так же, я не понимаю как в макабе сделан отступ конетнта от единичной картинки. Я прошелся вверх по дереву DOM от самой картинки и контенту, и отключал CSS свойства, и это не как сломало этот отступ. У меня только получилось чтобы текст только обтекал картинку https://jsfiddle.net/ntq1mqfL/ .
И с такими проблемами я сталкиваюсь всё время.
Наверно, мне лучше прочитать и выучить спецификации.
Если у вас будут какие-то ещё замечания - буду рад их услышать.
Спасибо
>>>Для закрытия картинки лучше бы предусмотреть кнопку-крестик
>> А разве клика за пределами привьею не достаточно?
>
>А как догадаться, что можно кликнуть за пределами?
Добавил крестик и закртыие по ескпейпу. Только крестик на тёмном фоне плохо видно (посмотреть можно уже на сайте). Как это исправить?
>>>а также можно положить под картинку снизу прозрачную или полупрозрачную подкладку и ловить клики на ней.
>> Ха, так сделать было слишком просто, но с этим есть проблема - под подкладкой нельзя выделять текст, пока она не исчезнет.
>А зачем выделять текст во время просмотра картинки? Я об этом конечно не думал.
Конечно на практике я такое не делал, но мне показалось, что не хорошо получается, когда сама картинка занимает всего лишь какую-то часть страницы, а не деле всю. Это не более чем "косметическое" исправление.
>>72048
Спасибо за предоставленные способы - я возьму их себе на заметку.
Если #lightbox лежит в body, то body будет контейнером. Не слишком ли опасно проводить на теле такие операции?
Я правильно понимаю, что все эти способы подразумевают, что контейнер это подкладка, или, быть может, контейнер лучше будет поместить в подкладку? Я только не понимаю, мы центрируем элемент относительно окна, это значит, что размер заданный в процентах или flexbox/table на body, не позволит воспользоваться большинством способов. В нашем случае, наилучшим способом будет двойной translate.
Я, если честно, плохо понимаю вёрстку. К примеру, у меня почему-то картинка выходит за пределы контейнера, и я не знаю как это исправить https://jsfiddle.net/kd5bqr4j/1/
Так же, я не понимаю как в макабе сделан отступ конетнта от единичной картинки. Я прошелся вверх по дереву DOM от самой картинки и контенту, и отключал CSS свойства, и это не как сломало этот отступ. У меня только получилось чтобы текст только обтекал картинку https://jsfiddle.net/ntq1mqfL/ .
И с такими проблемами я сталкиваюсь всё время.
Наверно, мне лучше прочитать и выучить спецификации.
Если у вас будут какие-то ещё замечания - буду рад их услышать.
Спасибо
>отступ конетнта от единичной картинки
overflow: auto; к классу "text" добавь в https://jsfiddle.net/ntq1mqfL/
> все курсы которые гугл выдает оказываются тратой времени и денег, если гуглить отзывы о них.
Так и есть. Твою профпригодность определяют реальные навыки, гитхаб, портфолио, а лёгких путей для вкатывания нет. Ты где-то видел, чтобы юристов готовили на курсах? У тебя для обучения есть бесплатные книги в огромном количестве и обучающие платформы интерактивные, но нет, хочу платить за курсы, вот я заплачу, а меня научат. Так не работает.
Да я же сказал, что сам обучаюсь. Я хочу курс именно для бумажки которой при устройстве можно похвастать, вот и все. Я не собираюсь идти на курсы за знаниями.
Создай что-нибудь годное и залей на гитхаб, гораздо полезнее чем тратить деньги на говнокурсы. Если стыдно указывать в резюме неоконченное высшее, напиши что еще учишься на заочке, кто это будет проверять?
Ну то есть ни одного курса который бы дал хоть сколько-то ценную бумажку или что-то достойное в портфолио, нет?
Еще раз повторю, что прекрасно понимаю что знания я получу сам и к ним исключительно иду за тем чтобы было какой бумажкой посветить при устройстве.
И иногда в базу прилетают какие-то данные в non utf-8 кодировке. Из-за этого получается следующее.
Делаю селект в psql, получаю такую ошибку.
>[22021] ERROR: invalid byte sequence for encoding "UTF8": 0xf0 0xe5 0xec 0xee
При выгрузке дампа и попытке его импортировать та же самая ошибка.
Посему несколько вопросов:
1) Как мне правильно перекодировать в php скрипте эти данные в utf-8? Я так понимаю сначала мне нужно задетектить исходную кодировку? Такое вообще возможно?
Наверняка многие из вас сталкивались с такой проблемой - когда текст в разной кодировке нужно привести к одной и сохранить в файле/бд. Как вы решали это? Или может есть где на гитхабе посмотреть решения умных людей?
2) Как это можно исправить на текущей бд?
3) Как это можно воспроизвести? Как сформировать non-utf8 байты чтобы потом передать их php скрипту для вставки базу? Я нихуя не понимаю. Это нужно будет чтобы протестировать исправление.
Nginx попробуй. Потом докеры-хуёкеры
Во-первых, тебе надо убедиться, что все правильно настроено. Что твоя БД имеет правильную серверную кодировку (utf-8), а также, что в твоем PHP коде задается клиентская кодировка (в которой ты отправляешь данные из скрипта) тоже utf-8. Мануал:
- https://postgrespro.ru/docs/postgresql/9.6/multibyte
На стороне PHP, я не нашел в документации по PDO опций для кодировки, так что видимо надо использовать команды из документации Postgres.
После того, как ты проверил, что все настроено, очевидно, что мы можем слать в Postrgres только валидные utf-8 строки, а не что попало. По крайней мере в текстовые поля.
Вот еще на всякий случай информация про кодировки, что это такое и как связано с символами и байтами, советую изучить: https://github.com/codedokode/pasta/blob/master/cs/strings.md
Я вижу тут такие решения:
- сделать в таблице бинарное поле, которое хранит не последовательность символов, а байты, как есть. Для него есть нестандартный тип колонки в Postgres и специальный синтаксис для передачи этих байтов в шестнадцатеричном виде: https://postgrespro.ru/docs/postgrespro/10/datatype-binary
- сделать в таблице текстовое поле, и помещать в него бинарные данные, предварительно закодированные в виде символов с помощью функций вроде base64 или uuencode. Или с помощью функции bin2hex. При выборке из БД данные придется раскодировать обратно из текста в байты. Минус - небольшое увеличение объема текста в сравнении с бинарными данными (наименее эффективна bin2hex, увеличивающая объем в 2 раза). Кодировать/раскодировать можно на стороне PHP, см. функции convert_uuencode(), base64_encode(), bin2hex().
- если по идее там не должно быть невалидных utf-8 кодов, то можно на стороне PHP делать очистку и удалять некорретные последовательности байт, которые не соответствуют символам в utf-8
> 1) Как мне правильно перекодировать в php скрипте эти данные в utf-8? Я так понимаю сначала мне нужно задетектить исходную кодировку? Такое вообще возможно?
Невозможно. Но если ты пишешь код, ты должен знать, какие данные в какой кодировке.
> Наверняка многие из вас сталкивались с такой проблемой - когда текст в разной кодировке нужно привести к одной и сохранить в файле/бд.
Я знаю, в какой кодировке текст и если надо, могу сконвертировать с помощью iconv(). Потому что я не пишу код наугад, а понимаю каждую строчку в нем.
> 2) Как это можно исправить на текущей бд?
Не знаю, зависит от выбранного варианта решения.
> 3) Как это можно воспроизвести? Как сформировать non-utf8 байты чтобы потом передать их php скрипту для вставки базу?
Прочитай мой урок про кодировки, изучи кодировку utf-8, пойми, какие последовательности байт в ней невалидные. После чего ты можешь создать строку с такой последовательностью байт либо так:
$str = chr(100) . chr(200) . chr (64); // в десятичном виде, мануал http://php.net/manual/ru/function.chr.php
Либо так:
$str = "\xe0\xff\xf0"; // в 16-ном виде, мануал http://php.net/manual/ru/language.types.string.php#language.types.string.syntax.double
Либо так:
$str = hex2bin("e0fff0"); // http://php.net/manual/ru/function.hex2bin.php
Во-первых, тебе надо убедиться, что все правильно настроено. Что твоя БД имеет правильную серверную кодировку (utf-8), а также, что в твоем PHP коде задается клиентская кодировка (в которой ты отправляешь данные из скрипта) тоже utf-8. Мануал:
- https://postgrespro.ru/docs/postgresql/9.6/multibyte
На стороне PHP, я не нашел в документации по PDO опций для кодировки, так что видимо надо использовать команды из документации Postgres.
После того, как ты проверил, что все настроено, очевидно, что мы можем слать в Postrgres только валидные utf-8 строки, а не что попало. По крайней мере в текстовые поля.
Вот еще на всякий случай информация про кодировки, что это такое и как связано с символами и байтами, советую изучить: https://github.com/codedokode/pasta/blob/master/cs/strings.md
Я вижу тут такие решения:
- сделать в таблице бинарное поле, которое хранит не последовательность символов, а байты, как есть. Для него есть нестандартный тип колонки в Postgres и специальный синтаксис для передачи этих байтов в шестнадцатеричном виде: https://postgrespro.ru/docs/postgrespro/10/datatype-binary
- сделать в таблице текстовое поле, и помещать в него бинарные данные, предварительно закодированные в виде символов с помощью функций вроде base64 или uuencode. Или с помощью функции bin2hex. При выборке из БД данные придется раскодировать обратно из текста в байты. Минус - небольшое увеличение объема текста в сравнении с бинарными данными (наименее эффективна bin2hex, увеличивающая объем в 2 раза). Кодировать/раскодировать можно на стороне PHP, см. функции convert_uuencode(), base64_encode(), bin2hex().
- если по идее там не должно быть невалидных utf-8 кодов, то можно на стороне PHP делать очистку и удалять некорретные последовательности байт, которые не соответствуют символам в utf-8
> 1) Как мне правильно перекодировать в php скрипте эти данные в utf-8? Я так понимаю сначала мне нужно задетектить исходную кодировку? Такое вообще возможно?
Невозможно. Но если ты пишешь код, ты должен знать, какие данные в какой кодировке.
> Наверняка многие из вас сталкивались с такой проблемой - когда текст в разной кодировке нужно привести к одной и сохранить в файле/бд.
Я знаю, в какой кодировке текст и если надо, могу сконвертировать с помощью iconv(). Потому что я не пишу код наугад, а понимаю каждую строчку в нем.
> 2) Как это можно исправить на текущей бд?
Не знаю, зависит от выбранного варианта решения.
> 3) Как это можно воспроизвести? Как сформировать non-utf8 байты чтобы потом передать их php скрипту для вставки базу?
Прочитай мой урок про кодировки, изучи кодировку utf-8, пойми, какие последовательности байт в ней невалидные. После чего ты можешь создать строку с такой последовательностью байт либо так:
$str = chr(100) . chr(200) . chr (64); // в десятичном виде, мануал http://php.net/manual/ru/function.chr.php
Либо так:
$str = "\xe0\xff\xf0"; // в 16-ном виде, мануал http://php.net/manual/ru/language.types.string.php#language.types.string.syntax.double
Либо так:
$str = hex2bin("e0fff0"); // http://php.net/manual/ru/function.hex2bin.php
Если тебе нужна бумажка, получи диплом в вузе. А так я не уверен, что какие-то краткосрочные курсы произведут впечатление. Хотя конечно зависит от HR.
То, что ты придумал, глупо. На курсы идти нужно именно за знаниями, иначе это просто трата денег.
>>72863
Я бы еще советовал глянуть существующие плагины для просмотра картинок (конечно, куча кнопок и функций не нужна, но можно посмотреть, как они сделаны). Они часто называются вроде lightbox:
- http://ignitersworld.com/lab/imageViewer.html
- http://lokeshdhakar.com/projects/lightbox2/
- http://fancyapps.com/fancybox/3/
- https://fengyuanchen.github.io/viewerjs/
- https://noelboss.github.io/featherlight/
- http://dimsemenov.com/plugins/magnific-popup/
- https://sorgalla.com/lity/
Этих скриптов так много, что я даже не знаю, какой лучше или хуже.
> Посмотреть можно на сайте
Ну пока какие-то косяки, например: https://i.imgur.com/JCuEhn9.jpg
Очевидно, тут проблема в том, что скрипт пытается определить размер картинки до ее полной загрузки, определяет неверно и все раскособочило.
> Только крестик на тёмном фоне плохо видно
Я его вообще не вижу. Но чтобы его было видно, можно использовать один из вариантов:
- подложить под белый крестик темный полупрозрачный прямоугольник
- добавить белому крестику черную обводку
> и закртыие по ескпейпу
А он кстати перехватывает эскейп только когда открыта картинка и не перехватывает в других случаях?
> Если #lightbox лежит в body, то body будет контейнером. Не слишком ли опасно проводить на теле такие операции?
Не опасно, но естественно, добавление стилей на body повлияет на верстку. Да и лучше наверно сделать контейнером div c pos: fixed, left/right/top/bottom: 0; Или нет?
> Я правильно понимаю, что все эти способы подразумевают, что контейнер это подкладка, или, быть может, контейнер лучше будет поместить в подкладку?
В моем посте контейнер - это блок, внутри которого находится контент (картинка), которую мы центрируем. Ну например, у тебя контейнером может быть div c pos: fixed, top/bottom/left/right: 0; и внутри него мы центрируем картинку.
> Я, если честно, плохо понимаю вёрстку.
Ну ты задавай вопросы, я подскажу.
> К примеру, у меня почему-то картинка выходит за пределы контейнера, и я не знаю как это исправить
Если открыть отладчик в браузере, то мы увидим:
> #lightbox {
> max-height: 66%;
Соответственно лайтбокс из-за этого оказывается меньше, чем картинка. На картинке, конечно, стоит height: 100%;, но это свойство тут не работает, так как высота лайтбокса не задана явно в CSS. Если мы откроем спец-ю по height, то там написано:
> https://www.w3.org/TR/2011/REC-CSS2-20110607/visudet.html#the-height-property
> <percentage>
> If the height of the containing block is not specified explicitly (i.e., it depends on content height), and this element is not absolutely positioned, the value computes to 'auto'.
Высота в процентах работает только если высота родителя явно задана, например в пикселях, или в процентах от прародителя, у которого в свою очередь тоже задана высота. Исключение - абс. поз. элементы, для них можно задавать высоту в процентах в любом случае (так как абс. поз. эл. никак не влияет на родителя и его высота вычисляется после того, как высота родителя посчитана).
Это, к сожалению, не очень известная особенность CSS.
> Так же, я не понимаю как в макабе сделан отступ конетнта от единичной картинки.
Есть один трюк. Если ты помещаешь перед текстом картинку с float, то текст (и любые inline/inline-block элементы) ее обтекает справа и снизу. Но если ты засовываешь текст в блок с overflow: auto, то этот блок сдвигается вправо как одно целое, плюс его ширина магическим образом вычисляется так, чтобы занять все свободное место: https://codepen.io/anon/pen/Brgyza
При этом, если например, вместо overflow: auto влепить просто display: inline-block или float: left, то ничего не работает - текст проваливается под флоаты (так как блок слишком большой, чтобы уместиться сбоку).
И что интересно, хотя для .text по идее должна по умолчанию вычисляться ширина в 100% (так как он display: block, не float, не абс. поз.), здесь за счет какой-то магии ширина уменьшается.
Я решил поискать это в спец-и: https://www.w3.org/TR/2011/REC-CSS2-20110607/visuren.html#floats
> The border box of a table, a block-level replaced element, or an element in the normal flow that establishes a new block formatting context (such as an element with 'overflow' other than 'visible') must not overlap the margin box of any floats in the same block formatting context as the element itself. If necessary, implementations should clear the said element by placing it below any preceding floats, but may place it adjacent to such floats if there is sufficient space. They may even make the border box of said element narrower than defined by section 10.3.3. CSS2 does not define when a UA may put said element next to the float or by how much said element may become narrower.
Если что, replaced elements - это картинки, элементы форм, то есть элементы, у которых есть внутренний размер.
Здесь указано, что float не должен пересекаться с:
1) таблицами
2) block-level replaced element (например: картинка с display: block)
3) element in the normal flow that establishes a new formatting context
В такой ситуации разрешается 2 варианта:
a) сдвинуть элемент под флоат
b) поместить элемент сбоку от флоата, ужав его ширину
А далее начинаются странности. Если мы посмотрим на пункт 3, и поищем, что может создавать "new formatting context", то увидим: https://www.w3.org/TR/2011/REC-CSS2-20110607/visuren.html#block-formatting
> Floats, absolutely positioned elements, block containers (such as inline-blocks, table-cells, and table-captions) that are not block boxes, and block boxes with 'overflow' other than 'visible' (except when that value has been propagated to the viewport) establish new block formatting contexts for their contents.
Поскольку "float, absolutely positioned elements" не попадает под условие "in normal flow" в пункте 3, мы их отбросим. Остается:
x) block containers (such as inline-blocks, table-cells, and table-captions) that are not block boxes
y) block boxes with 'overflow' other than 'visible'
По логике, и x) и y) должны себя вести одинаково. Но по факту элементы из пункта x) проваливаются под флоат по варианту a), а вот элементы из пункта y) ужимаются по ширине по варианту b).
Объяснить это, думаю, можно историческими причинами, какой-то браузер ужимал блоки с overflow по ширине, сайты были сверстаны с учетом этого, и в спецификации решили зафиксировать такую возможность, но не указывать, как именно должен себя вести браузер.
Это показывает интересную особенность: если ты напишешь новый браузер строго по спецификации, многие сайты в нем развалятся. Так как люди верстают не по спецификации, а на глаз, опираясь на поведение существующих браузеров и на такие неявные особенности. А сама спецификация не описывает все на 100%.
Я еще глянул спецификацию CSS2.0 и там в разделе floats такое не описано. Скорее всего, где-то между CSS2.0 и 2.1 браузеры это реализовали, и пришлось зафиксировать это в спецификации по факту.
И еще, я нашел тред в рассылке w3c: https://lists.w3.org/Archives/Public/www-style/2008May/0225.html
- там упомянуто, что сайты полагаются на эту особенность (по-видимому, добавленную в старом IE).
Надеюсь, загадка раскрыта. Я давно знал про эту особенность, но не знал, описана ли она где-то и откуда взялась.
> Наверно, мне лучше прочитать и выучить спецификации.
Я обычно туда смотрю только в спорных случаях. Вот те случаи, что ты упомянул, как раз без спецификации не разобрать, они довольно хитрые.
По коду:
Не забывай кроме событий img.load/video.canplay обрабатывать ошибки - ошибка загрузки, отсутствие поддержки формата браузером
Вместо $(content)[0].oncanplay наверно можно писать $(content).on('canplay') - нет?
var a = $('.file-link'); - это, как мне кажется, не нужно.
var fullsize = $('.fullsize'); - вместо поиска каждый раз заново в дереве DOM было бы удобнее просто хранить ссылку на элемент в переменной.
hideLightbox не надо вызывать, если он уже закрыт.
Вместо $(e.target).closest(a) наверно надо было написать closest('a'). Там указывают селектор обычно.
Вместо $(target).is мне кажется, лучше использовать closest(), так как клик может придтись как на элемент <a>, так и на <img> внутри него.
Если тебе нужна бумажка, получи диплом в вузе. А так я не уверен, что какие-то краткосрочные курсы произведут впечатление. Хотя конечно зависит от HR.
То, что ты придумал, глупо. На курсы идти нужно именно за знаниями, иначе это просто трата денег.
>>72863
Я бы еще советовал глянуть существующие плагины для просмотра картинок (конечно, куча кнопок и функций не нужна, но можно посмотреть, как они сделаны). Они часто называются вроде lightbox:
- http://ignitersworld.com/lab/imageViewer.html
- http://lokeshdhakar.com/projects/lightbox2/
- http://fancyapps.com/fancybox/3/
- https://fengyuanchen.github.io/viewerjs/
- https://noelboss.github.io/featherlight/
- http://dimsemenov.com/plugins/magnific-popup/
- https://sorgalla.com/lity/
Этих скриптов так много, что я даже не знаю, какой лучше или хуже.
> Посмотреть можно на сайте
Ну пока какие-то косяки, например: https://i.imgur.com/JCuEhn9.jpg
Очевидно, тут проблема в том, что скрипт пытается определить размер картинки до ее полной загрузки, определяет неверно и все раскособочило.
> Только крестик на тёмном фоне плохо видно
Я его вообще не вижу. Но чтобы его было видно, можно использовать один из вариантов:
- подложить под белый крестик темный полупрозрачный прямоугольник
- добавить белому крестику черную обводку
> и закртыие по ескпейпу
А он кстати перехватывает эскейп только когда открыта картинка и не перехватывает в других случаях?
> Если #lightbox лежит в body, то body будет контейнером. Не слишком ли опасно проводить на теле такие операции?
Не опасно, но естественно, добавление стилей на body повлияет на верстку. Да и лучше наверно сделать контейнером div c pos: fixed, left/right/top/bottom: 0; Или нет?
> Я правильно понимаю, что все эти способы подразумевают, что контейнер это подкладка, или, быть может, контейнер лучше будет поместить в подкладку?
В моем посте контейнер - это блок, внутри которого находится контент (картинка), которую мы центрируем. Ну например, у тебя контейнером может быть div c pos: fixed, top/bottom/left/right: 0; и внутри него мы центрируем картинку.
> Я, если честно, плохо понимаю вёрстку.
Ну ты задавай вопросы, я подскажу.
> К примеру, у меня почему-то картинка выходит за пределы контейнера, и я не знаю как это исправить
Если открыть отладчик в браузере, то мы увидим:
> #lightbox {
> max-height: 66%;
Соответственно лайтбокс из-за этого оказывается меньше, чем картинка. На картинке, конечно, стоит height: 100%;, но это свойство тут не работает, так как высота лайтбокса не задана явно в CSS. Если мы откроем спец-ю по height, то там написано:
> https://www.w3.org/TR/2011/REC-CSS2-20110607/visudet.html#the-height-property
> <percentage>
> If the height of the containing block is not specified explicitly (i.e., it depends on content height), and this element is not absolutely positioned, the value computes to 'auto'.
Высота в процентах работает только если высота родителя явно задана, например в пикселях, или в процентах от прародителя, у которого в свою очередь тоже задана высота. Исключение - абс. поз. элементы, для них можно задавать высоту в процентах в любом случае (так как абс. поз. эл. никак не влияет на родителя и его высота вычисляется после того, как высота родителя посчитана).
Это, к сожалению, не очень известная особенность CSS.
> Так же, я не понимаю как в макабе сделан отступ конетнта от единичной картинки.
Есть один трюк. Если ты помещаешь перед текстом картинку с float, то текст (и любые inline/inline-block элементы) ее обтекает справа и снизу. Но если ты засовываешь текст в блок с overflow: auto, то этот блок сдвигается вправо как одно целое, плюс его ширина магическим образом вычисляется так, чтобы занять все свободное место: https://codepen.io/anon/pen/Brgyza
При этом, если например, вместо overflow: auto влепить просто display: inline-block или float: left, то ничего не работает - текст проваливается под флоаты (так как блок слишком большой, чтобы уместиться сбоку).
И что интересно, хотя для .text по идее должна по умолчанию вычисляться ширина в 100% (так как он display: block, не float, не абс. поз.), здесь за счет какой-то магии ширина уменьшается.
Я решил поискать это в спец-и: https://www.w3.org/TR/2011/REC-CSS2-20110607/visuren.html#floats
> The border box of a table, a block-level replaced element, or an element in the normal flow that establishes a new block formatting context (such as an element with 'overflow' other than 'visible') must not overlap the margin box of any floats in the same block formatting context as the element itself. If necessary, implementations should clear the said element by placing it below any preceding floats, but may place it adjacent to such floats if there is sufficient space. They may even make the border box of said element narrower than defined by section 10.3.3. CSS2 does not define when a UA may put said element next to the float or by how much said element may become narrower.
Если что, replaced elements - это картинки, элементы форм, то есть элементы, у которых есть внутренний размер.
Здесь указано, что float не должен пересекаться с:
1) таблицами
2) block-level replaced element (например: картинка с display: block)
3) element in the normal flow that establishes a new formatting context
В такой ситуации разрешается 2 варианта:
a) сдвинуть элемент под флоат
b) поместить элемент сбоку от флоата, ужав его ширину
А далее начинаются странности. Если мы посмотрим на пункт 3, и поищем, что может создавать "new formatting context", то увидим: https://www.w3.org/TR/2011/REC-CSS2-20110607/visuren.html#block-formatting
> Floats, absolutely positioned elements, block containers (such as inline-blocks, table-cells, and table-captions) that are not block boxes, and block boxes with 'overflow' other than 'visible' (except when that value has been propagated to the viewport) establish new block formatting contexts for their contents.
Поскольку "float, absolutely positioned elements" не попадает под условие "in normal flow" в пункте 3, мы их отбросим. Остается:
x) block containers (such as inline-blocks, table-cells, and table-captions) that are not block boxes
y) block boxes with 'overflow' other than 'visible'
По логике, и x) и y) должны себя вести одинаково. Но по факту элементы из пункта x) проваливаются под флоат по варианту a), а вот элементы из пункта y) ужимаются по ширине по варианту b).
Объяснить это, думаю, можно историческими причинами, какой-то браузер ужимал блоки с overflow по ширине, сайты были сверстаны с учетом этого, и в спецификации решили зафиксировать такую возможность, но не указывать, как именно должен себя вести браузер.
Это показывает интересную особенность: если ты напишешь новый браузер строго по спецификации, многие сайты в нем развалятся. Так как люди верстают не по спецификации, а на глаз, опираясь на поведение существующих браузеров и на такие неявные особенности. А сама спецификация не описывает все на 100%.
Я еще глянул спецификацию CSS2.0 и там в разделе floats такое не описано. Скорее всего, где-то между CSS2.0 и 2.1 браузеры это реализовали, и пришлось зафиксировать это в спецификации по факту.
И еще, я нашел тред в рассылке w3c: https://lists.w3.org/Archives/Public/www-style/2008May/0225.html
- там упомянуто, что сайты полагаются на эту особенность (по-видимому, добавленную в старом IE).
Надеюсь, загадка раскрыта. Я давно знал про эту особенность, но не знал, описана ли она где-то и откуда взялась.
> Наверно, мне лучше прочитать и выучить спецификации.
Я обычно туда смотрю только в спорных случаях. Вот те случаи, что ты упомянул, как раз без спецификации не разобрать, они довольно хитрые.
По коду:
Не забывай кроме событий img.load/video.canplay обрабатывать ошибки - ошибка загрузки, отсутствие поддержки формата браузером
Вместо $(content)[0].oncanplay наверно можно писать $(content).on('canplay') - нет?
var a = $('.file-link'); - это, как мне кажется, не нужно.
var fullsize = $('.fullsize'); - вместо поиска каждый раз заново в дереве DOM было бы удобнее просто хранить ссылку на элемент в переменной.
hideLightbox не надо вызывать, если он уже закрыт.
Вместо $(e.target).closest(a) наверно надо было написать closest('a'). Там указывают селектор обычно.
Вместо $(target).is мне кажется, лучше использовать closest(), так как клик может придтись как на элемент <a>, так и на <img> внутри него.
Все верно.
>>72806
>>72572
Он видит ошибку в фразе "Этот анон": https://ideone.com/o0aUDq
Он видит ошибку в фразе "разделанный на части".
В (жы|шы)\w+ наверно нужен не плюс, а звездочка.
В остальном верно.
>>72788
При инкапсуляции мы закрываем прямой доступ к полям, ставя на них модификаторы доступа protected или private. У тебя в компании поле departments публичное и это дает возможность делать с ним что угодно, например, записать туда по ошибке названия вместо объектов. Надо закрыть доступ.
> public function addDepartment($department)
Здесь нужен тайп-хинт на аргумент и на возвращаемое значение (void если нет).
С тайп-хинтами все очень просто: ставь их везде, где можно. То есть почти везде.
> $totalEmployees += $department->countEmployees($department->employees);
Здесь логическая ошибка: зачем ты в метод департамента передаешь список работников? Департамент и так знает, кто в нем работает, и передавать список ему не надо.
> class Department
> public function createEmployee($rank, $isBoss, $proffession)
Это не гибко. Ты не позволяешь создать работника и нанять его на работу, а требуешь чтобы работники создавались только в департаменте. То есть ограничиваешь возможности, и непонятно в чем тут выгода, зачем так делать. Если можно просто написать метод hire(Employee $e). Это проще, и дает больше гибкости.
Также, в твоем коде перечислен список профессий и нельзя добавить новую, не меняя код. А у меня в условии написано, что желательно сделать возможность добавления новой профессии, не трогая существующие классы.
> public function deleteEmployee($rank, $isBoss, $proffession)
Этот метод неудачно спроектирован. ПРочитай сам: "уволить всех работников данного ранга, профессии, с признаком босса". То есть он годится только для массовых увольнений и не позволяет уволить отдельного работника. Подсказка, как это сделать проще:
fire(Employee $e)
> abstract class Employee
> function __construct ($rank, $isBoss, $proffession)
Зачем передавать профессию в конструктор, если мы создаем объект определенного класса (Engineer) и тем самым уже указываем профессию. Зачем ее указывать второй раз?
> return $reports = 200;
Не надо тут писать переменную, которую ты потом нигде не используешь. Пиши просто return 200; Или у тебя по учебнику создалось впечатление, что вернуть можно только переменную? Нет, там может быть любое выражение.
Антикризисные меры пока никуда не годятся. Во-первых, они применяются к компании в целом, и я не вижу методов, которые бы применяли эти меры к компании. Во-вторых, надо их применить и распечатать таблицы с результатом.
Измененеи зарплаты надо делать не ручным комментированием строчек в коде, а кодом, который ее меняет.
Применять меры лучше всего так:
- найти работников нужного типа. Для этого можно сделать в департаменте универсальный метод поиска работников по любым условиям. Подсказка: удобно передавать условие отбора с помощью анонимной функции, либо надо предусмотреть какой-то другой вариант.
- отсортировать их по очереди на увольнение c помощью usort + анонимная функция
- взять нужную часть с помощью array_slice
- уволить
Анонимные функции: http://php.net/manual/ru/functions.anonymous.php
Чтобы применить несколько мер независимо, надо сделать несколько клонов компании и применять к каждому клону свою меру.
Замену босса лучше делать не сложными условиями, а просто сделать в департаменте метод для замены босса. А у тебя тут нарушение инкапсуляции: ты меняешь начальника департамента в обход департамента.
Все верно.
>>72806
>>72572
Он видит ошибку в фразе "Этот анон": https://ideone.com/o0aUDq
Он видит ошибку в фразе "разделанный на части".
В (жы|шы)\w+ наверно нужен не плюс, а звездочка.
В остальном верно.
>>72788
При инкапсуляции мы закрываем прямой доступ к полям, ставя на них модификаторы доступа protected или private. У тебя в компании поле departments публичное и это дает возможность делать с ним что угодно, например, записать туда по ошибке названия вместо объектов. Надо закрыть доступ.
> public function addDepartment($department)
Здесь нужен тайп-хинт на аргумент и на возвращаемое значение (void если нет).
С тайп-хинтами все очень просто: ставь их везде, где можно. То есть почти везде.
> $totalEmployees += $department->countEmployees($department->employees);
Здесь логическая ошибка: зачем ты в метод департамента передаешь список работников? Департамент и так знает, кто в нем работает, и передавать список ему не надо.
> class Department
> public function createEmployee($rank, $isBoss, $proffession)
Это не гибко. Ты не позволяешь создать работника и нанять его на работу, а требуешь чтобы работники создавались только в департаменте. То есть ограничиваешь возможности, и непонятно в чем тут выгода, зачем так делать. Если можно просто написать метод hire(Employee $e). Это проще, и дает больше гибкости.
Также, в твоем коде перечислен список профессий и нельзя добавить новую, не меняя код. А у меня в условии написано, что желательно сделать возможность добавления новой профессии, не трогая существующие классы.
> public function deleteEmployee($rank, $isBoss, $proffession)
Этот метод неудачно спроектирован. ПРочитай сам: "уволить всех работников данного ранга, профессии, с признаком босса". То есть он годится только для массовых увольнений и не позволяет уволить отдельного работника. Подсказка, как это сделать проще:
fire(Employee $e)
> abstract class Employee
> function __construct ($rank, $isBoss, $proffession)
Зачем передавать профессию в конструктор, если мы создаем объект определенного класса (Engineer) и тем самым уже указываем профессию. Зачем ее указывать второй раз?
> return $reports = 200;
Не надо тут писать переменную, которую ты потом нигде не используешь. Пиши просто return 200; Или у тебя по учебнику создалось впечатление, что вернуть можно только переменную? Нет, там может быть любое выражение.
Антикризисные меры пока никуда не годятся. Во-первых, они применяются к компании в целом, и я не вижу методов, которые бы применяли эти меры к компании. Во-вторых, надо их применить и распечатать таблицы с результатом.
Измененеи зарплаты надо делать не ручным комментированием строчек в коде, а кодом, который ее меняет.
Применять меры лучше всего так:
- найти работников нужного типа. Для этого можно сделать в департаменте универсальный метод поиска работников по любым условиям. Подсказка: удобно передавать условие отбора с помощью анонимной функции, либо надо предусмотреть какой-то другой вариант.
- отсортировать их по очереди на увольнение c помощью usort + анонимная функция
- взять нужную часть с помощью array_slice
- уволить
Анонимные функции: http://php.net/manual/ru/functions.anonymous.php
Чтобы применить несколько мер независимо, надо сделать несколько клонов компании и применять к каждому клону свою меру.
Замену босса лучше делать не сложными условиями, а просто сделать в департаменте метод для замены босса. А у тебя тут нарушение инкапсуляции: ты меняешь начальника департамента в обход департамента.
Когда ты натыкаешься на знак операции, ты достаешь предыдущий знак из $op и копируешь в временную переменную, а новый знак кладешь в $op на будущее. Затем выполняешь операцию во времененой переменной.
>>72608
Нужно делать отступы внутри if/for/функций, иначе читать код невозможно. Во втором посте треда описано, как это автоматизировать.
> foreach ($separation as $value) {
надо лучше выбирать имена, например: foreach ($sentences as $sentence)
value ничего не говорит.
Замену первой буквы на заглавную стоило вынести в отдельную функцию с понятным именем, чтобы код было проще читать.
$name1 плохое название, так как непонятно, при чем тут единица, да и name тоже ничего не говорит.
Если ты обрабатываешь значение, то может быть лучше не заводить на каждый шаг новую переменную, а класть его назад в ту же. А то много названий: $value, $clearSpace, $name1
>>72350
Так тоже можно.
>>73367
Потерпи еще денек. Там с ~300 до ~650 поста не проверены. И анон с HTML версткой сайта.
>>73362
Уже можно кодить. Изучить надо файловые системы, символические ссылки, права на файлы, команды типа ls, rm, find, grep, sort, uniq, cut, less, ps, top, kill. Они в любом учебнике по линукс перечислены. Остальное по ходу дела изучишь.
Когда ты натыкаешься на знак операции, ты достаешь предыдущий знак из $op и копируешь в временную переменную, а новый знак кладешь в $op на будущее. Затем выполняешь операцию во времененой переменной.
>>72608
Нужно делать отступы внутри if/for/функций, иначе читать код невозможно. Во втором посте треда описано, как это автоматизировать.
> foreach ($separation as $value) {
надо лучше выбирать имена, например: foreach ($sentences as $sentence)
value ничего не говорит.
Замену первой буквы на заглавную стоило вынести в отдельную функцию с понятным именем, чтобы код было проще читать.
$name1 плохое название, так как непонятно, при чем тут единица, да и name тоже ничего не говорит.
Если ты обрабатываешь значение, то может быть лучше не заводить на каждый шаг новую переменную, а класть его назад в ту же. А то много названий: $value, $clearSpace, $name1
>>72350
Так тоже можно.
>>73367
Потерпи еще денек. Там с ~300 до ~650 поста не проверены. И анон с HTML версткой сайта.
>>73362
Уже можно кодить. Изучить надо файловые системы, символические ссылки, права на файлы, команды типа ls, rm, find, grep, sort, uniq, cut, less, ps, top, kill. Они в любом учебнике по линукс перечислены. Остальное по ходу дела изучишь.
Написать код вроде:
- вывести 1-ю страницу
- вывести многоточие
- вывести N страниц рядом с текущей
- вывести последнюю страницу
Плюс условия на тот случай, если первая или последняя страница попадают в блок "рядом с текущей".
>>59802
Это плохая идея. Глупо загружать 500 ссылок, чтобы удалить 495 из них. Плюс, яваскрипт срабатывает не сразу и пользователь сначала увидит 500 ссылок, а потом скачком часть из них удалится.
>>59816
Если проще без них, то делай без фреймворков. Если же чувствуешь, что начал писать клон реакта, то наверно надо взять готовый.
>>59901
Добавь скрытое поле action.
>>59914
Только через конструктор. В качестве значений полей по умолчанию можно указывать только постоянные значения (константы).
> Попробовал через конструктор складывать - тоже самое:
Ты опечатался в слове construct, будь внимательнее
Написать код вроде:
- вывести 1-ю страницу
- вывести многоточие
- вывести N страниц рядом с текущей
- вывести последнюю страницу
Плюс условия на тот случай, если первая или последняя страница попадают в блок "рядом с текущей".
>>59802
Это плохая идея. Глупо загружать 500 ссылок, чтобы удалить 495 из них. Плюс, яваскрипт срабатывает не сразу и пользователь сначала увидит 500 ссылок, а потом скачком часть из них удалится.
>>59816
Если проще без них, то делай без фреймворков. Если же чувствуешь, что начал писать клон реакта, то наверно надо взять готовый.
>>59901
Добавь скрытое поле action.
>>59914
Только через конструктор. В качестве значений полей по умолчанию можно указывать только постоянные значения (константы).
> Попробовал через конструктор складывать - тоже самое:
Ты опечатался в слове construct, будь внимательнее
> if ($humanDice1 + $humanDice2 > $compDice1 + $compDice2) {
if ($humanAll > $compAll)
Не проверяется ничья при даблах у обоих.
А так, верно.
>>59951
На 100% актуально, кроме абзацев про древние браузеры вроде Netscape или IE6. Там уроки по стандарту CSS2.1 и этот стандарт никто не отменял (CSS3 его лишь дополняет).
Я сам CSS учил по этому учебнику когда-то.
>>60517
Я табличную верстку видел много раз, и отнюдь не в 2000 году. Ведь было много старых учебников и статей, описывающих ее. Я помню, много статей было с критикой, чтобы это искоренить.
Кстати, забавный факт: HTML-письма в рассылках до сих пор верстаются таблицами, так как почтовые сервисы фильтруют HTML/CSS, и таблицы дают наибольшую гарантию корректного отображения. Не веришь - отправь сам HTML/CSS-письмо и посмотри что отобразится.
>>59965
Если ты знаешь Java, тебе проще офиц мануал пролистать и запомнить отличия.
>>60021
MVC ничего такого не запрещает.
> if ($humanDice1 + $humanDice2 > $compDice1 + $compDice2) {
if ($humanAll > $compAll)
Не проверяется ничья при даблах у обоих.
А так, верно.
>>59951
На 100% актуально, кроме абзацев про древние браузеры вроде Netscape или IE6. Там уроки по стандарту CSS2.1 и этот стандарт никто не отменял (CSS3 его лишь дополняет).
Я сам CSS учил по этому учебнику когда-то.
>>60517
Я табличную верстку видел много раз, и отнюдь не в 2000 году. Ведь было много старых учебников и статей, описывающих ее. Я помню, много статей было с критикой, чтобы это искоренить.
Кстати, забавный факт: HTML-письма в рассылках до сих пор верстаются таблицами, так как почтовые сервисы фильтруют HTML/CSS, и таблицы дают наибольшую гарантию корректного отображения. Не веришь - отправь сам HTML/CSS-письмо и посмотри что отобразится.
>>59965
Если ты знаешь Java, тебе проще офиц мануал пролистать и запомнить отличия.
>>60021
MVC ничего такого не запрещает.
Приоритеты операторов указаны тут: http://php.net/manual/ru/language.operators.precedence.php
В любых сомнительных случаях ставь скобки.
>>60327
Дискретная математика тут не при чем, надо смотреть только на приоритеты операторов.
>>60072
Верно. Можно было еще объединить 2 группы ифов в одну.
>>60078
Если за ним что-то идет, например, HTML-код
>>60087
на хабре есть стори про Нигерию: https://habrahabr.ru/post/346514/
>>60107
Шаблонизатор - это штука, которая берет шаблон и подставляет в него данные. Пример:
Шаблон: Hello, {name}
Данные: name="world"
Результат: Hello, world
Это часть приложения, а не все приложение. Так как те же данные надо сначала получить.
MVC - это паттерн архитектуры приложения, основанный на разделении его на M, V и C.
То есть это просто разные вещи. При этом MVC конечно может использовать шаблонизатор в View.
Приоритеты операторов указаны тут: http://php.net/manual/ru/language.operators.precedence.php
В любых сомнительных случаях ставь скобки.
>>60327
Дискретная математика тут не при чем, надо смотреть только на приоритеты операторов.
>>60072
Верно. Можно было еще объединить 2 группы ифов в одну.
>>60078
Если за ним что-то идет, например, HTML-код
>>60087
на хабре есть стори про Нигерию: https://habrahabr.ru/post/346514/
>>60107
Шаблонизатор - это штука, которая берет шаблон и подставляет в него данные. Пример:
Шаблон: Hello, {name}
Данные: name="world"
Результат: Hello, world
Это часть приложения, а не все приложение. Так как те же данные надо сначала получить.
MVC - это паттерн архитектуры приложения, основанный на разделении его на M, V и C.
То есть это просто разные вещи. При этом MVC конечно может использовать шаблонизатор в View.
Посмотри мануал PHP. Если кратко, в PHP в классах гораздо больше возможностей.
>>60311
Это типичный пример оверинжиниринга. Блог, если подумать - это просто HTML страница, может быть с комментариями под ней. Где ты там видишь потребность в SPA? Просто получится громоздкая тормозная штука, которая сначала грузит мегабайт яваскрипта, делает аякс-запрос, хотя могла бы сразу показать текст поста.
Если ты хочешь поиграться с SPA приложениями, пожалуйста, вот идея:
- читалка новостей (постов, смешных картинок, чего угодно)
- позволяет читать постраничную или бесконечную ленту постов. Пост состоит из превьюшки и названия, заходишь в него и видишь полный текст
- посты помечены тегами/категориями, можно читать посты только на определенную тему
- можно лайкать посты
- при желании, можно добавить комменты
Конечно, тут пока нужды в SPA нет. Потому давай ее добавим: приложение должно частично работать в офлайне. Ну например, ставишь лайк, а он выгружается, когда появится связь. А пока связи нет, можно читать посты, которые успели подгрузиться. То есть, чтобы это было похоже на мобильное приложение, а не на просто сайт. И работало без перезагрузки страниц.
- не забудь задействовать HTML5 history, чтобы можно было делиться ссылками
- постов в ленте так много, что все их загрузить на клиент (в стор редукса) нереально
- надо подгружать часть постов заранее, чтобы когда ты окажешься без связи, ты мог бы их читать в офлайне
>>60369
С виду все так. Можешь дать пример, что не работает?
>>60528
Да, это будет полезно и пригодится.
Посмотри мануал PHP. Если кратко, в PHP в классах гораздо больше возможностей.
>>60311
Это типичный пример оверинжиниринга. Блог, если подумать - это просто HTML страница, может быть с комментариями под ней. Где ты там видишь потребность в SPA? Просто получится громоздкая тормозная штука, которая сначала грузит мегабайт яваскрипта, делает аякс-запрос, хотя могла бы сразу показать текст поста.
Если ты хочешь поиграться с SPA приложениями, пожалуйста, вот идея:
- читалка новостей (постов, смешных картинок, чего угодно)
- позволяет читать постраничную или бесконечную ленту постов. Пост состоит из превьюшки и названия, заходишь в него и видишь полный текст
- посты помечены тегами/категориями, можно читать посты только на определенную тему
- можно лайкать посты
- при желании, можно добавить комменты
Конечно, тут пока нужды в SPA нет. Потому давай ее добавим: приложение должно частично работать в офлайне. Ну например, ставишь лайк, а он выгружается, когда появится связь. А пока связи нет, можно читать посты, которые успели подгрузиться. То есть, чтобы это было похоже на мобильное приложение, а не на просто сайт. И работало без перезагрузки страниц.
- не забудь задействовать HTML5 history, чтобы можно было делиться ссылками
- постов в ленте так много, что все их загрузить на клиент (в стор редукса) нереально
- надо подгружать часть постов заранее, чтобы когда ты окажешься без связи, ты мог бы их читать в офлайне
>>60369
С виду все так. Можешь дать пример, что не работает?
>>60528
Да, это будет полезно и пригодится.
Ты бы хоть ссылку дал. Я не понял, какую "schema" ты имеешь в виду.
>>60551
В Гугле и вообще на западе Питон довольно популярен. В Гугле используют Питон, Ява, C++, Го.
Ну и ява в андроиде используется.
>>60744
Это удобно, когда справа сложные выражения.
>>60865
Да.
>>60943
>>60892
Высота в процентах у блока работает только в случаях:
или 1) блок имеет абс. поз.
или 2) у родителя высота задана явно в пикс.
или 3) у родителя и выше высота в процентах, а у кого-то из прародителей в пикс.
или 4) у родителя и всех праводителей вплоть до HTML указана высота в процентах
То есть тогда, когда высота родителя вычисляется и не зависит от самого блока с высотой в процентах.
Ссылка https://www.w3.org/TR/2011/REC-CSS2-20110607/visudet.html#the-height-property
Ты бы хоть ссылку дал. Я не понял, какую "schema" ты имеешь в виду.
>>60551
В Гугле и вообще на западе Питон довольно популярен. В Гугле используют Питон, Ява, C++, Го.
Ну и ява в андроиде используется.
>>60744
Это удобно, когда справа сложные выражения.
>>60865
Да.
>>60943
>>60892
Высота в процентах у блока работает только в случаях:
или 1) блок имеет абс. поз.
или 2) у родителя высота задана явно в пикс.
или 3) у родителя и выше высота в процентах, а у кого-то из прародителей в пикс.
или 4) у родителя и всех праводителей вплоть до HTML указана высота в процентах
То есть тогда, когда высота родителя вычисляется и не зависит от самого блока с высотой в процентах.
Ссылка https://www.w3.org/TR/2011/REC-CSS2-20110607/visudet.html#the-height-property
Тебе что важно - задачу решить или получить авторитет в /pr/?
>>61631
Первое лучше тем, что с ним код очевиднее и труднее сделать ошибку. Но потребует чуть больше памяти, если массив большой.
Недостаток ссылок в том, что не очевидно, что функция меняет значение:
doSomething($x); // <-- что здесь происходит с $x? непонятно
А тут все понятно:
$y = doSomething($x);
>>62003
Это SQL инъекция, читай урок https://github.com/codedokode/pasta/blob/master/security/sql-injection.md
Надо проверять поле по списку разрешенных значений.А не вставлять не глядя.
>Я бы еще советовал глянуть существующие плагины для просмотра картинок (конечно, куча кнопок и функций не нужна, но можно посмотреть, как они сделаны). Они часто называются вроде lightbox:
Я до этого только догадывался как работает popup. Поэтому, я нашел один из перечисленных плагинов, посмотрел принцип его работы, а так же посмтрел как это работает в популярных соц.сетях, и написал свой под свои нужды.
>Этих скриптов так много, что я даже не знаю, какой лучше или хуже.
Который ты написал сам https://i.imgur.com/4QwBnwK.gif
>> Посмотреть можно на сайте
>Ну пока какие-то косяки, например: https://i.imgur.com/JCuEhn9.jpg
>Очевидно, тут проблема в том, что скрипт пытается определить размер картинки до ее полной загрузки, определяет неверно и все раскособочило.
Почему вы решили что проблема в этом? Проблема в том что картинка выходит за пределы контейнера#lightbox.
>> Только крестик на тёмном фоне плохо видно
>Я его вообще не вижу.
Нужно навести на картинку.
Я не подумал, что пользователь может не пользоваться мышью, например на ноутбуке. Я вообще не очень люблю когда элементы интерфейса бросаются в глаза, они отвлекают от самой картинки т.е. от контентной части. Я обратил внимание, что во все перечисленных lightbox плагинах, этот крестик присутствует, но пойти на такой шаг мне даётся кривя душой. Разве не достаточно будет выхода по ескейпу в таком случае?
Аргументируйте, пожалуйста, почему крестик нужно сделать видимым всегда, и, может быть, мне будет легче это сделать.
>> и закртыие по ескпейпу
>А он кстати перехватывает эскейп только когда открыта картинка и не перехватывает в других случаях?
Я сделал проверку if (lightbox.css('display') == 'block') { , но сейчас загуглил и понял что лучше сделать проверку .is(':visible'). Это хороший способ?
https://github.com/richBlueElephant/phpClub/blob/master/public/media/js/script.js#L97
>> К примеру, у меня почему-то картинка выходит за пределы контейнера, и я не знаю как это исправить
>Высота в процентах работает только если высота родителя явно задана, например в пикселях, или в процентах от прародителя, у которого в свою очередь тоже задана высота. Исключение - абс. поз. элементы, для них можно задавать высоту в процентах в любом случае (так как абс. поз. эл. никак не влияет на родителя и его высота вычисляется после того, как высота родителя посчитана).
Так как быть? Я не могу явно указать ширину или высоту контейнера, т.к. он растянется шире картинки, а нужно чтобы контейнер был не больше 66% страницы и картинка вписывалась в него, либо чтобы сама картинка была не больше 66% а размер контейнера высчитался из содержимого. Я не понимаю что тут можно сделать.
>По коду:
>var a = $('.file-link'); - это, как мне кажется, не нужно.
Почему не нужно? Мы в пару местах делаем проверку на этот элемент. Нужно каждый раз их искать?
https://github.com/richBlueElephant/phpClub/blob/master/public/media/js/script.js#L37
https://github.com/richBlueElephant/phpClub/blob/master/public/media/js/script.js#L44
>var fullsize = $('.fullsize'); - вместо поиска каждый раз заново в дереве DOM было бы удобнее просто хранить ссылку на элемент в переменной.
Этот элемент нужно искать именно каждый раз когда мы делаем клик, потому что, при каждом открытии, он, каждый раз, создаётся новый.
https://github.com/richBlueElephant/phpClub/blob/master/public/media/js/script.js#L49
https://github.com/richBlueElephant/phpClub/blob/master/public/media/js/script.js#L58
>Вместо $(e.target).closest(a) наверно надо было написать closest('a'). Там указывают селектор обычно.
Можно и объект jQuery указать, и элемент DOM...
https://api.jquery.com/closest/#closest-selection
>Я бы еще советовал глянуть существующие плагины для просмотра картинок (конечно, куча кнопок и функций не нужна, но можно посмотреть, как они сделаны). Они часто называются вроде lightbox:
Я до этого только догадывался как работает popup. Поэтому, я нашел один из перечисленных плагинов, посмотрел принцип его работы, а так же посмтрел как это работает в популярных соц.сетях, и написал свой под свои нужды.
>Этих скриптов так много, что я даже не знаю, какой лучше или хуже.
Который ты написал сам https://i.imgur.com/4QwBnwK.gif
>> Посмотреть можно на сайте
>Ну пока какие-то косяки, например: https://i.imgur.com/JCuEhn9.jpg
>Очевидно, тут проблема в том, что скрипт пытается определить размер картинки до ее полной загрузки, определяет неверно и все раскособочило.
Почему вы решили что проблема в этом? Проблема в том что картинка выходит за пределы контейнера#lightbox.
>> Только крестик на тёмном фоне плохо видно
>Я его вообще не вижу.
Нужно навести на картинку.
Я не подумал, что пользователь может не пользоваться мышью, например на ноутбуке. Я вообще не очень люблю когда элементы интерфейса бросаются в глаза, они отвлекают от самой картинки т.е. от контентной части. Я обратил внимание, что во все перечисленных lightbox плагинах, этот крестик присутствует, но пойти на такой шаг мне даётся кривя душой. Разве не достаточно будет выхода по ескейпу в таком случае?
Аргументируйте, пожалуйста, почему крестик нужно сделать видимым всегда, и, может быть, мне будет легче это сделать.
>> и закртыие по ескпейпу
>А он кстати перехватывает эскейп только когда открыта картинка и не перехватывает в других случаях?
Я сделал проверку if (lightbox.css('display') == 'block') { , но сейчас загуглил и понял что лучше сделать проверку .is(':visible'). Это хороший способ?
https://github.com/richBlueElephant/phpClub/blob/master/public/media/js/script.js#L97
>> К примеру, у меня почему-то картинка выходит за пределы контейнера, и я не знаю как это исправить
>Высота в процентах работает только если высота родителя явно задана, например в пикселях, или в процентах от прародителя, у которого в свою очередь тоже задана высота. Исключение - абс. поз. элементы, для них можно задавать высоту в процентах в любом случае (так как абс. поз. эл. никак не влияет на родителя и его высота вычисляется после того, как высота родителя посчитана).
Так как быть? Я не могу явно указать ширину или высоту контейнера, т.к. он растянется шире картинки, а нужно чтобы контейнер был не больше 66% страницы и картинка вписывалась в него, либо чтобы сама картинка была не больше 66% а размер контейнера высчитался из содержимого. Я не понимаю что тут можно сделать.
>По коду:
>var a = $('.file-link'); - это, как мне кажется, не нужно.
Почему не нужно? Мы в пару местах делаем проверку на этот элемент. Нужно каждый раз их искать?
https://github.com/richBlueElephant/phpClub/blob/master/public/media/js/script.js#L37
https://github.com/richBlueElephant/phpClub/blob/master/public/media/js/script.js#L44
>var fullsize = $('.fullsize'); - вместо поиска каждый раз заново в дереве DOM было бы удобнее просто хранить ссылку на элемент в переменной.
Этот элемент нужно искать именно каждый раз когда мы делаем клик, потому что, при каждом открытии, он, каждый раз, создаётся новый.
https://github.com/richBlueElephant/phpClub/blob/master/public/media/js/script.js#L49
https://github.com/richBlueElephant/phpClub/blob/master/public/media/js/script.js#L58
>Вместо $(e.target).closest(a) наверно надо было написать closest('a'). Там указывают селектор обычно.
Можно и объект jQuery указать, и элемент DOM...
https://api.jquery.com/closest/#closest-selection
>Я не могу явно указать ширину или высоту контейнера, т.к. он растянется шире картинки
Забыл указать код https://jsfiddle.net/kd5bqr4j/5/
PHP + ООП, Знакомство с фреймворком на уровне создание небольшого бложика, Понимание MVC, Базовый JS, HTML 5, CSS3 + Bootstrap, Git, Умение настроить LAMP + базовые команды линукса.
вычисляй пропорции картинки, и делай 66% большую сторону, тогда вторая всегда будет меньше 66 и все впишется и не вылезет за твои сферические 66%. А то безголовое аниме.
Cпасибо за подробное пояснение. Буду разбираться в чём именно проблема.
В общем пришел на пересдачу. Сори что очень долго писал правки.
И так, код: https://github.com/mlmn/vector.loc
Теперь по пунктам с вопросами и комментариями:
1.
>Ой-ой, смесь PHP и HTML...
Не проблема, это просто тянулось еще с тех пор, когда код постился на ideone и нужно было что бы программа была по сути совместимой с консолью, но со временем я запилил себе более удобный вариант для отладки в браузере, который при этом не требовал бы никаких инклудов, что бы быть по прежнему совместимым с ideone, ща консольный вариант выпилил, выпилил шаблоны в отдельыне файлы и перелопатил их.
2.
>> static public function pageHeader() {
>А не надо тут статический метод использовать, зачем?
Вынес header страницы в конструктор Reporter'a, а footer соответственно в деструктор, что бы при создании 1 Reporter'a всегда были все необходимые теги. Как минимум экономится код, жду комментария по этому поводу, предвижу слабое место в том, что кто-то может создавать еще Reporter'ов, но мне решение кажется довольно элегантным, жду оценку.
3.
>При попытке дважды добавить департамент наверно лучше выкидывать исключение. Чтобы сообщить об ошибке.
>То же самое, надо сообщать об ошибке, а не тихо ее игнорировать.
Ок, глянул про исключения, засунул их в места добавления сотрудников и департаментов. А так же отлавливаю в OrganisationBuilder'e. Что бы не копипастить везде
echo 'Выброшено исключение: ', $e->getMessage();
завел статическую функцию для оповещения в Dbg->exceptionEcho($exception).
Только вот у меня вопрос возникает, а для кого пишутся эти исключения? Для самого разработчика, что бы на этапе тестирования увидеть ошибки? Или для пользователя? Останавливать программу после срабатывания такого вот исключения или нет? Если например пытаешься добавить 2 одинаковых департамента, то второй просто не добавляется, но без остановки всё как бы и хорошо работает. Обошли дублирование и всё ок, выполнению программы это не мешает.
4.
>Лучше использовать instanceof
Где мог заменил, в PeopleFactory заменил на is_subclass_of(), так как там проверка не по существующему объекту, а просто по имени класса.
5.
>> $info = new stdClass();
>Не надо использовать stdClass. Это как массив (так как нигде не описаны его поля), только плохой, так как с ним не работают функции работы с массивами. Тут лучше либо сделать отдельные методы вроде getTotalSalary(), либо специальный объект CompanyStat где описаны все поля.
Первый серьезный ступор был тут, и он по сути никуда не делся. Я просто написал класс OrgInfo, но оставил все поля в нем public, так как просто бомбануло при попытке написать в этот класс 24 геттера/сеттера и в том месте где я их заполняю - Organisation->getOrgInfo() тоже просто удлинять код.
Из:
$orgInfo->totalPeople += $dep->countDepEmployees();
делать:
$orgInfo->setTotalPeople() = $orgInfo->getTotalPeople() + $dep->countDepEmployees();
В общем оставил пока такой вот простой объект, и жду комментария что с ним делать, удобный метод getOrgInfo() в котором элегантно всё в одном месте считается через цикл тоже не хочется бить на копипастные методы вида getOrgTotalPeople(), getOrgTotalSalary()...
6.
>> public function __construct($name) {
>Если ты используешь PHP7, то можно добавить тайп-хинты вроде string, а также тайп-хинты на возвращаемые функцией значения: public function getName(): string
До этого писал на 5.х, перекатился на 7.2, вроде расставил везде где нашел тайпхинты как на вход так и на выход. Ну опять же кроме геттеров/сеттеров пустышек. На них тоже нужно выставлять тайпхинт по паравилу хорошего тона, даже если ты просто возвращаешь что-то без изменения/вычисления? Еще не понятно как быть в случае как с моей функцией getTopAnalyst() - либо она возвращает объект Analyst, либо null (по логике отсутствие объекта это как раз оно), и сюда ничего нельзя поставить на выходной тип, будут ошибки.
7.
>> if (in_array($employee->getName(), $fireList)) {
>Мне кажется, лучше удалять не по имени, а по объекту. Так как объект обладает идентичностью и отличается от всех других объектов. И придумывать дополнительные идентификаторы не надо.
>> public function makeLeaderByName($name) {
>То же самое, не надо придумывать идентификатор, передавай сам объект.
Избавился от идентификаторов.
8.
>> public function getTopAnalyst() {
>Это очень узкоспециальная функция, нужная только антикризисному комитету. Надо ее перенести в антикризисный комитет, а в департаменте сделать универсальный метод поиска по любым критериям.
Перенес getTopAnalyst() в класс AntiCrisis. В департаменте завел функцию поиска getAllCertainSpecialists(), в которую нужно было передавать много разных параметров в виде массивов для поиска, поэтому вместо того что бы городить кучу проверок о правильности переданных аргументов просто завел еще 1 класс специально для этой функции - EmployeeSelector. Жду комментарий по поводу этого моего решения.
9.
>> public function demoteLeader() {
>нужен ли этот метод? Лучше наверно сделать метод замены босса. А то у тебя можно департамент без босса оставить.
>> public function makeLeaderByName($name) {
>> public function promoteLeaderByName($name) {
>Одинаковые методы же?
Разобрался, сделал метод замены босса. Но не стал склеивать методы demoteLeader() и promoteLeader() в один большой метод замены, просто заприватил их и оставил для лучшей читабельности. завел публичный swapLeader(), который просто вызывает их в нужной последовательности, логика в этом есть имхо.
10.
> class Names {
ok
11.
>Насчет наследовния. У тебя есть негласное правило, что при наследовании профессии от работника надо задать базовые параметры. Но это никак не документировано и никак не проверяется. Легко забыть это сделать. Чтобы этого избежать, можно использовать абстрактные методы - то есть методы, которые не дописаны в базовом классе и которые обязаны реализовать потомки. Попробуй добавить абстрактные методы вроде getDefaultBaseSalary() и тогда их нельзя будет забыть определить.
Вот тут у меня если честно ступор возник и я вижу дыру теперь, что действительно, если создать новый класс сотрудника, и не прописать в нем типовой конструктор для моего класса, то будет пустой сотрудник без зарплаты, кофе и бумаг. Но как мне поможет абстрактный метод getDefaultBaseSalary(), в классе Employee??
В общем тут у меня проблема и не понимание как из этого слабого места выкрутиться. Не добавлять же абстрактный метод в родителя, который бы вызывался в родительском конструкторе, что бы при наследовании переопределить этот абстрактный метод и типа при переопределении уже в этом методе заполнять стандартные поля значениями (без переопределия как раз ошибка, а при переопределении вроде как и не забудут переписать). В общем я сейчас сяду после этого отчета с этим делом эксперементировать, в гитхаб пока в любом случае не буду коммитить промежуточные варианты.
12.
>> class AntiCrisis {
>> private $departments;
>Мне кажется это поле не нужно, если у тебя есть компания, ты из нее всегда можешь получить департаменты. Получается дублирование данных.
Ок, убрал, но появилось это поле вот так:
Я когда писал этот класс, то заметил что у меня везде в коде копипаста вида:
foreach($this->organisation->getDepartments() as $dep) {
И просто вынес это в отдельное поле да еще и выставляющееся в конструкторе. Не понял если честно что в этом плохого.
13.
>Отбирать работников для увольнения проще так:
>- получаем список кандидатов на увольнение
>- сортируем его по приоритету (кто в прервую очередь) с помощью usort + анонимная функция
>- с помощью array_slice отрезаем нужное число кандидатов
>- увольняем
>Это будет читаться лучше, чем твой код с вложенными циклами и брейками.
Заменил циклы и брейки на usort+анонимные функции. Не имею такого опыта общения с usort, что бы быть уверенным в правильной сортировке сразу по двум параметрам за 1 вызов этой конструкции. Поэтому сначала сортирую пор рангу, потом уже по лидерству.
Функция для инспекции теперь AntiCrisis->prepareEngineersForFire()
14.
>Также, надо чтобы программа применила все 3 метода и вывела таблицы для сравнения. Для этого надо научиться делать копии (клоны) организации, чтобы работать с ними, не трогая исходную компанию.
Ок, 658 и далее строчки теперь посвящены этому, но мне кажется что это не сильно элегантное решение. Может быть стоит антикризис сделать вообще статическим классом? Что бы не создавать под каждую клонированную организацию новый антикризисный объект? А просто передавать ему объект, а он его будет возвращать в измененном виде аки обычная процедурная функция?
Еле еле уместился в 15кб в ответе, пришлось подрезать где можно.
В общем пришел на пересдачу. Сори что очень долго писал правки.
И так, код: https://github.com/mlmn/vector.loc
Теперь по пунктам с вопросами и комментариями:
1.
>Ой-ой, смесь PHP и HTML...
Не проблема, это просто тянулось еще с тех пор, когда код постился на ideone и нужно было что бы программа была по сути совместимой с консолью, но со временем я запилил себе более удобный вариант для отладки в браузере, который при этом не требовал бы никаких инклудов, что бы быть по прежнему совместимым с ideone, ща консольный вариант выпилил, выпилил шаблоны в отдельыне файлы и перелопатил их.
2.
>> static public function pageHeader() {
>А не надо тут статический метод использовать, зачем?
Вынес header страницы в конструктор Reporter'a, а footer соответственно в деструктор, что бы при создании 1 Reporter'a всегда были все необходимые теги. Как минимум экономится код, жду комментария по этому поводу, предвижу слабое место в том, что кто-то может создавать еще Reporter'ов, но мне решение кажется довольно элегантным, жду оценку.
3.
>При попытке дважды добавить департамент наверно лучше выкидывать исключение. Чтобы сообщить об ошибке.
>То же самое, надо сообщать об ошибке, а не тихо ее игнорировать.
Ок, глянул про исключения, засунул их в места добавления сотрудников и департаментов. А так же отлавливаю в OrganisationBuilder'e. Что бы не копипастить везде
echo 'Выброшено исключение: ', $e->getMessage();
завел статическую функцию для оповещения в Dbg->exceptionEcho($exception).
Только вот у меня вопрос возникает, а для кого пишутся эти исключения? Для самого разработчика, что бы на этапе тестирования увидеть ошибки? Или для пользователя? Останавливать программу после срабатывания такого вот исключения или нет? Если например пытаешься добавить 2 одинаковых департамента, то второй просто не добавляется, но без остановки всё как бы и хорошо работает. Обошли дублирование и всё ок, выполнению программы это не мешает.
4.
>Лучше использовать instanceof
Где мог заменил, в PeopleFactory заменил на is_subclass_of(), так как там проверка не по существующему объекту, а просто по имени класса.
5.
>> $info = new stdClass();
>Не надо использовать stdClass. Это как массив (так как нигде не описаны его поля), только плохой, так как с ним не работают функции работы с массивами. Тут лучше либо сделать отдельные методы вроде getTotalSalary(), либо специальный объект CompanyStat где описаны все поля.
Первый серьезный ступор был тут, и он по сути никуда не делся. Я просто написал класс OrgInfo, но оставил все поля в нем public, так как просто бомбануло при попытке написать в этот класс 24 геттера/сеттера и в том месте где я их заполняю - Organisation->getOrgInfo() тоже просто удлинять код.
Из:
$orgInfo->totalPeople += $dep->countDepEmployees();
делать:
$orgInfo->setTotalPeople() = $orgInfo->getTotalPeople() + $dep->countDepEmployees();
В общем оставил пока такой вот простой объект, и жду комментария что с ним делать, удобный метод getOrgInfo() в котором элегантно всё в одном месте считается через цикл тоже не хочется бить на копипастные методы вида getOrgTotalPeople(), getOrgTotalSalary()...
6.
>> public function __construct($name) {
>Если ты используешь PHP7, то можно добавить тайп-хинты вроде string, а также тайп-хинты на возвращаемые функцией значения: public function getName(): string
До этого писал на 5.х, перекатился на 7.2, вроде расставил везде где нашел тайпхинты как на вход так и на выход. Ну опять же кроме геттеров/сеттеров пустышек. На них тоже нужно выставлять тайпхинт по паравилу хорошего тона, даже если ты просто возвращаешь что-то без изменения/вычисления? Еще не понятно как быть в случае как с моей функцией getTopAnalyst() - либо она возвращает объект Analyst, либо null (по логике отсутствие объекта это как раз оно), и сюда ничего нельзя поставить на выходной тип, будут ошибки.
7.
>> if (in_array($employee->getName(), $fireList)) {
>Мне кажется, лучше удалять не по имени, а по объекту. Так как объект обладает идентичностью и отличается от всех других объектов. И придумывать дополнительные идентификаторы не надо.
>> public function makeLeaderByName($name) {
>То же самое, не надо придумывать идентификатор, передавай сам объект.
Избавился от идентификаторов.
8.
>> public function getTopAnalyst() {
>Это очень узкоспециальная функция, нужная только антикризисному комитету. Надо ее перенести в антикризисный комитет, а в департаменте сделать универсальный метод поиска по любым критериям.
Перенес getTopAnalyst() в класс AntiCrisis. В департаменте завел функцию поиска getAllCertainSpecialists(), в которую нужно было передавать много разных параметров в виде массивов для поиска, поэтому вместо того что бы городить кучу проверок о правильности переданных аргументов просто завел еще 1 класс специально для этой функции - EmployeeSelector. Жду комментарий по поводу этого моего решения.
9.
>> public function demoteLeader() {
>нужен ли этот метод? Лучше наверно сделать метод замены босса. А то у тебя можно департамент без босса оставить.
>> public function makeLeaderByName($name) {
>> public function promoteLeaderByName($name) {
>Одинаковые методы же?
Разобрался, сделал метод замены босса. Но не стал склеивать методы demoteLeader() и promoteLeader() в один большой метод замены, просто заприватил их и оставил для лучшей читабельности. завел публичный swapLeader(), который просто вызывает их в нужной последовательности, логика в этом есть имхо.
10.
> class Names {
ok
11.
>Насчет наследовния. У тебя есть негласное правило, что при наследовании профессии от работника надо задать базовые параметры. Но это никак не документировано и никак не проверяется. Легко забыть это сделать. Чтобы этого избежать, можно использовать абстрактные методы - то есть методы, которые не дописаны в базовом классе и которые обязаны реализовать потомки. Попробуй добавить абстрактные методы вроде getDefaultBaseSalary() и тогда их нельзя будет забыть определить.
Вот тут у меня если честно ступор возник и я вижу дыру теперь, что действительно, если создать новый класс сотрудника, и не прописать в нем типовой конструктор для моего класса, то будет пустой сотрудник без зарплаты, кофе и бумаг. Но как мне поможет абстрактный метод getDefaultBaseSalary(), в классе Employee??
В общем тут у меня проблема и не понимание как из этого слабого места выкрутиться. Не добавлять же абстрактный метод в родителя, который бы вызывался в родительском конструкторе, что бы при наследовании переопределить этот абстрактный метод и типа при переопределении уже в этом методе заполнять стандартные поля значениями (без переопределия как раз ошибка, а при переопределении вроде как и не забудут переписать). В общем я сейчас сяду после этого отчета с этим делом эксперементировать, в гитхаб пока в любом случае не буду коммитить промежуточные варианты.
12.
>> class AntiCrisis {
>> private $departments;
>Мне кажется это поле не нужно, если у тебя есть компания, ты из нее всегда можешь получить департаменты. Получается дублирование данных.
Ок, убрал, но появилось это поле вот так:
Я когда писал этот класс, то заметил что у меня везде в коде копипаста вида:
foreach($this->organisation->getDepartments() as $dep) {
И просто вынес это в отдельное поле да еще и выставляющееся в конструкторе. Не понял если честно что в этом плохого.
13.
>Отбирать работников для увольнения проще так:
>- получаем список кандидатов на увольнение
>- сортируем его по приоритету (кто в прервую очередь) с помощью usort + анонимная функция
>- с помощью array_slice отрезаем нужное число кандидатов
>- увольняем
>Это будет читаться лучше, чем твой код с вложенными циклами и брейками.
Заменил циклы и брейки на usort+анонимные функции. Не имею такого опыта общения с usort, что бы быть уверенным в правильной сортировке сразу по двум параметрам за 1 вызов этой конструкции. Поэтому сначала сортирую пор рангу, потом уже по лидерству.
Функция для инспекции теперь AntiCrisis->prepareEngineersForFire()
14.
>Также, надо чтобы программа применила все 3 метода и вывела таблицы для сравнения. Для этого надо научиться делать копии (клоны) организации, чтобы работать с ними, не трогая исходную компанию.
Ок, 658 и далее строчки теперь посвящены этому, но мне кажется что это не сильно элегантное решение. Может быть стоит антикризис сделать вообще статическим классом? Что бы не создавать под каждую клонированную организацию новый антикризисный объект? А просто передавать ему объект, а он его будет возвращать в измененном виде аки обычная процедурная функция?
Еле еле уместился в 15кб в ответе, пришлось подрезать где можно.
Нууу как тебе сказать... Там почти всё неправильно.
Тут будут только ответы на старые посты. Если вас пропустили или вам не ответили, напишите в новый тред.
почему первой-то. первой в офисе пыхтел
> function inclineWord($number, $word) {
Тут сплошная копипаста, один и тот же код скопирован 3 раза. Так не годится, надо убрать копипасту. Вместо того, чтобы передавать одно слово, лучше передавать 3 формы этого слова и пусть функция из них выберет одну.
> function smallNumberToText($number, $isFemale) {
> $array [] = "$hundreds";
Плохо, что это скопировано в обе ветки. Нужно вынести эту строку выше, чтобы она не повторялась.
> foreach($array as $a) {
> array_push($array1,$spelling[$a]);
По моему, проще сразу в первый массив класть $spelling[...], а не цифру. Также, у тебя очень плохие названия переменных - array, a, array1 - что они значат? Нужно выбирать более понятные названия, например: $words.
> if ($isFemale == 1) {
> $array1 = preg_replace('/один/u', 'одна', $array1);
Это костыли. Надо с самого начала класть в массив правильный элемент.
> function numberToText($number) {
> $thirst = $number % 1000;
Не надо эту строчку копировать 3 раза.
> $second = floor($number % 1000000 - $thirst) / 1000;
И эту тоже не надо копировать.
> $result = preg_replace('/\\s\\s/u', ' ', $result);
Это плохо, это костыль, код становится труднее понять (так как надо сначала найти, как формируется исходная строка, а потом понять, как она преобразуется), лучше так сделать программу, чтобы был массив слов и в него не добавлялись пустые значения с самого начала.
В общем, главное замечание - много копипасты, надо от нее избавиться.
>>62106
Проще всего погуглить "название библиотеки add color".
>>62132
Ты не написал, гле каракули. При открытии страницы, которую генерирует файл, в браузере? Надо добавить метатег meta charset.
> function inclineWord($number, $word) {
Тут сплошная копипаста, один и тот же код скопирован 3 раза. Так не годится, надо убрать копипасту. Вместо того, чтобы передавать одно слово, лучше передавать 3 формы этого слова и пусть функция из них выберет одну.
> function smallNumberToText($number, $isFemale) {
> $array [] = "$hundreds";
Плохо, что это скопировано в обе ветки. Нужно вынести эту строку выше, чтобы она не повторялась.
> foreach($array as $a) {
> array_push($array1,$spelling[$a]);
По моему, проще сразу в первый массив класть $spelling[...], а не цифру. Также, у тебя очень плохие названия переменных - array, a, array1 - что они значат? Нужно выбирать более понятные названия, например: $words.
> if ($isFemale == 1) {
> $array1 = preg_replace('/один/u', 'одна', $array1);
Это костыли. Надо с самого начала класть в массив правильный элемент.
> function numberToText($number) {
> $thirst = $number % 1000;
Не надо эту строчку копировать 3 раза.
> $second = floor($number % 1000000 - $thirst) / 1000;
И эту тоже не надо копировать.
> $result = preg_replace('/\\s\\s/u', ' ', $result);
Это плохо, это костыль, код становится труднее понять (так как надо сначала найти, как формируется исходная строка, а потом понять, как она преобразуется), лучше так сделать программу, чтобы был массив слов и в него не добавлялись пустые значения с самого начала.
В общем, главное замечание - много копипасты, надо от нее избавиться.
>>62106
Проще всего погуглить "название библиотеки add color".
>>62132
Ты не написал, гле каракули. При открытии страницы, которую генерирует файл, в браузере? Надо добавить метатег meta charset.
Я не вижу, в чем проблема. Анонимные функции всегда будут при вар дампе выдавать такую гору кода, не надо просто на нее обращать внимания.
Код выглядит нормально, единственное, непонятно, зачем там зависимость от ContainerHelper.
>>62280
> Почему колонка 2 стоит неравномерно относительно 1й, приходится подстраивать top: 8.9%; и прочее, чтобы стояли ровно.
А почему они должны быть на одной высоте, если у них разные правила позиционирования? У column1 стоит margin-top: 10%;, а у column2 - стоит top: 10%; (а не margin-top). Естественно, они будут на разной высоте.
У первой колонки не задан top, и за основу берется текущее положение в потоке, к которому прибавляется отступ в 10%. У второй задан top, он и используется.
> Второе - как сделать фиксированное положение 2й колонны, при этом чтобы можно было скроллить страницу.
В твоей верстке - никак. Ну или как вариант, поставить на блок overflow: auto, чтобы в нем появлялись линейки прокрутки. Чтобы можно было скроллить всю страницу целиком, содержимое не должно быть засунуто в блок с position: absolute или fixed.
Ты вроде хорошо оцениваешь свою верстку, но на мой взгляд, она плохая. Одна из идей CSS - это то, что мы стараемся не задавать жестко положение элементов, а опираемся на их автоматическое расположение на странице. У нас есть воображаемый лист бумаги, мы кладем на него блоки и браузер расставляет их друг за другом, чтобы они не накладывались.
У тебя же этого нет, ты пытаешься указать вручную положение для каждого блока, да еще и в процентах. То есть на большом экране там будут огромные пустые не используемые пространства.
Попробуй уменьшить размер окна. Твои колонки на телефоне ужимаются до узких полосок.
Плюс, ты используешь fixed позиционирование, которое предусматривает, что весь контент помещается в окно браузера и не выходит за его границы. Это неудобно, так как в том же вконтакте контент может быть очень длинным и прокручивается. А твоя верстка этого не позволяет.
Потому бросай эту дурь, изучи блочное позиционирование (урок https://github.com/codedokode/pasta/blob/master/html/positioning.md ) и используй его для контента. Не злоупотребляй абсолютным, а тем более, фиксированным позиционированием. Фиксированное позиционирование - это очень плохо, так как оно закрепляет элемент в окне и он постоянно отнимает место, даже при прокрутке страницы.
Абсолютное позиционирование используют, чтобы крестик в углу блока поместить. Сложную верстку на нем не сделать.
Также, давай нормальные названия классам, column2_5 никуда не годится.
Далее, по коду. Ощущение, что ты CSS толком не изучал и просто пишешь правила на глаз.
> .container {
> margin: auto;
> position: absolute;
> top: 0; left: 0; bottom: 0; right: 0;
Уже тут проблемы, так как это растягивает контейнер на всю страницу (а не на все окно). И непонятно, в чем смысл этого.
> .header {
> position: fixed;
> top: 0;
> margin-bottom: 20px;
зачем тут margin-bottom, если он ни на что не влияет? Блок, который спозиционирован absolute или fixed, не влияет ни на соседние, ни на родительский блок.
При этом у тебя даже не указан left. Такое ощущение, что ты не понимаешь, что какое свойство делает. Если ты используешь абс. или фикс. позиционирование, ты должен указать положение по 2 осям - left или right и top или bottom. Очевидная же вещь.
> .column1 {
> position: fixed;
> float: left;
float не совместим с fixed. И опять, не указаны ни left, ни top.
> .column2_5 {
> left: 0;
> right: 0;
left/right применяется только в сочетании с position.
> position: bottom;
Ошибка.
Я не вижу, в чем проблема. Анонимные функции всегда будут при вар дампе выдавать такую гору кода, не надо просто на нее обращать внимания.
Код выглядит нормально, единственное, непонятно, зачем там зависимость от ContainerHelper.
>>62280
> Почему колонка 2 стоит неравномерно относительно 1й, приходится подстраивать top: 8.9%; и прочее, чтобы стояли ровно.
А почему они должны быть на одной высоте, если у них разные правила позиционирования? У column1 стоит margin-top: 10%;, а у column2 - стоит top: 10%; (а не margin-top). Естественно, они будут на разной высоте.
У первой колонки не задан top, и за основу берется текущее положение в потоке, к которому прибавляется отступ в 10%. У второй задан top, он и используется.
> Второе - как сделать фиксированное положение 2й колонны, при этом чтобы можно было скроллить страницу.
В твоей верстке - никак. Ну или как вариант, поставить на блок overflow: auto, чтобы в нем появлялись линейки прокрутки. Чтобы можно было скроллить всю страницу целиком, содержимое не должно быть засунуто в блок с position: absolute или fixed.
Ты вроде хорошо оцениваешь свою верстку, но на мой взгляд, она плохая. Одна из идей CSS - это то, что мы стараемся не задавать жестко положение элементов, а опираемся на их автоматическое расположение на странице. У нас есть воображаемый лист бумаги, мы кладем на него блоки и браузер расставляет их друг за другом, чтобы они не накладывались.
У тебя же этого нет, ты пытаешься указать вручную положение для каждого блока, да еще и в процентах. То есть на большом экране там будут огромные пустые не используемые пространства.
Попробуй уменьшить размер окна. Твои колонки на телефоне ужимаются до узких полосок.
Плюс, ты используешь fixed позиционирование, которое предусматривает, что весь контент помещается в окно браузера и не выходит за его границы. Это неудобно, так как в том же вконтакте контент может быть очень длинным и прокручивается. А твоя верстка этого не позволяет.
Потому бросай эту дурь, изучи блочное позиционирование (урок https://github.com/codedokode/pasta/blob/master/html/positioning.md ) и используй его для контента. Не злоупотребляй абсолютным, а тем более, фиксированным позиционированием. Фиксированное позиционирование - это очень плохо, так как оно закрепляет элемент в окне и он постоянно отнимает место, даже при прокрутке страницы.
Абсолютное позиционирование используют, чтобы крестик в углу блока поместить. Сложную верстку на нем не сделать.
Также, давай нормальные названия классам, column2_5 никуда не годится.
Далее, по коду. Ощущение, что ты CSS толком не изучал и просто пишешь правила на глаз.
> .container {
> margin: auto;
> position: absolute;
> top: 0; left: 0; bottom: 0; right: 0;
Уже тут проблемы, так как это растягивает контейнер на всю страницу (а не на все окно). И непонятно, в чем смысл этого.
> .header {
> position: fixed;
> top: 0;
> margin-bottom: 20px;
зачем тут margin-bottom, если он ни на что не влияет? Блок, который спозиционирован absolute или fixed, не влияет ни на соседние, ни на родительский блок.
При этом у тебя даже не указан left. Такое ощущение, что ты не понимаешь, что какое свойство делает. Если ты используешь абс. или фикс. позиционирование, ты должен указать положение по 2 осям - left или right и top или bottom. Очевидная же вещь.
> .column1 {
> position: fixed;
> float: left;
float не совместим с fixed. И опять, не указаны ни left, ни top.
> .column2_5 {
> left: 0;
> right: 0;
left/right применяется только в сочетании с position.
> position: bottom;
Ошибка.
Дай пример кода и что пишет валидатор.
>>62829
В твоем коде уязвимость - SQL инъекция: https://github.com/codedokode/pasta/blob/master/security/sql-injection.md
Она из-за того, что ты переменную вставляешь напрямую в SQL-запрос.
Также, mysql-функции устарели уже как лет 5. Почитай про myqsli или PDO.
По коду - он тебе пишет, что там в переменной что-то не то. Сдампь переменную через var_dump() и посмотри.
>>62830
наверно, трудно так сказать.
>>63026
По опыту - для species/breed наверно удобнее создать таблицы и ставить ссылку на них.
Связь "рецепт" - "прием", по моему, должна быть много-к-(одному или нулю), на одном приеме можно выдать много рецептов. И может быть, понадобится выдавать рецепты вне приема. Если такое возможно, лучше не делать связь обязательной.
Пароль хранить не надо, надо хранить соленый хеш от него.
>>63159
Отправляешь аякс-запрос на сервер, код там обрабатывает его и генерирует HTML с данными, получаешь ответ и вставляешь HTML в нужное место страницы.
Дай пример кода и что пишет валидатор.
>>62829
В твоем коде уязвимость - SQL инъекция: https://github.com/codedokode/pasta/blob/master/security/sql-injection.md
Она из-за того, что ты переменную вставляешь напрямую в SQL-запрос.
Также, mysql-функции устарели уже как лет 5. Почитай про myqsli или PDO.
По коду - он тебе пишет, что там в переменной что-то не то. Сдампь переменную через var_dump() и посмотри.
>>62830
наверно, трудно так сказать.
>>63026
По опыту - для species/breed наверно удобнее создать таблицы и ставить ссылку на них.
Связь "рецепт" - "прием", по моему, должна быть много-к-(одному или нулю), на одном приеме можно выдать много рецептов. И может быть, понадобится выдавать рецепты вне приема. Если такое возможно, лучше не делать связь обязательной.
Пароль хранить не надо, надо хранить соленый хеш от него.
>>63159
Отправляешь аякс-запрос на сервер, код там обрабатывает его и генерирует HTML с данными, получаешь ответ и вставляешь HTML в нужное место страницы.
> Не понимаю что подразумевается под хранилищами, которые как будто просто раз и быстрее чем база - как, что это?
Например, написанные на Си (а также Си++, Ява, Го) хранилища, которые хранят какие-то данные в памяти или файлах, к которым можно подсоединяться и добавлять или искать данные.
> Это как если например ты закешируешь всех юзеров вконтакте, а многие из них очень даже и непопулярны, и на их странички никто не заходит, но при этом у них постоянно из друзей кто-то удаляется или меняет личные данные так, что страничку нашего непопулярного юзера будет проще каждый раз собирать заного, чем на каждый чих его друзей обновлять кэш?
Да.
> Печально, что за пару лет опыта я сижу на каких-то макако-задачах в среде таких же не шарящих ребят и не с кем даже банально на теоритическом уровне по обмениваться подобным опытом,
Придумай какой-нибудь проект, делай и выкладывай код, я пострааюсь прокомемнтировать. Но сначала тебе может придется освоить (если ты не освоил) композер, MVC, DI, все это.
>>63298
Можно, но сложно. Для старых браузеров может быть проще отдать страницу без CSS или сделать отдельный минимальный CSS с самыми простыми правилами. То есть без сайдбаров, сложных меню, итд, просто идущие подряд блоки.
Выгоднее сделать именно отдельные стили, так как иначе браузер половину стилей не поймет и страницу раскособочит.
>>63899
Посмотри, как сделано в АПИ яндекс-диска, гуглосервисов и тд.
>>63942
Никуда.
Если тебе нужен блог сегодня, то это хорошее решение.
>>64740
То, что сейчас есть, нужно доделывать, пока сделано процентов на 40.
У меня в браузере подвал слипся: https://i.imgur.com/l3rnlch.png . Хромиум 2-летней давности.
Кнопка see portfolio должна бы реагировать на наведение. Кнопки соцсетей - тоже. Эффекты при наведении на кнопку можешь найти где-нибудь в интернете по словам css effects.
Адаптивные версии сделаны очень слабо, такое ощущение, что им особо время не уделялось.
На узком экране (780px) портфолио у меня прижимается к левому краю и не центрируется.
На совсем маленьком экране (300px) меню занимает слишком много места, плюс там огромный заголовок. Ну представь, что ты это на телефоне открыл и у тебя "we are webpaint" растянулось на 2 экрана. Портфолио съехало вбок. Удобно ли пользоваться таким сайтом? Надо сделать версию для маленького экрана лучше. Адаптивность - это не просто перестановка блоков друг над другом, это именно доработка для разных экранов. Подвал тоже сделан плохо, номер телефона на нем в 2 строки, зато в подвале огромные пустые пространства. Подумай, как сделать, чтобы было аккуратно и удобно.
Картинки портфолио стоит сделать ссылками.
Вот как сайт выглядит в FF3.6: https://i.imgur.com/X9yxRP6.png - а ведь этот браузер поддерживает стандарт CSS2.1. Надо бы протестировать сайт в разных браузерах. Хотя бы чтобы он работал хотя бы во всех браузрах 5-летней давности + в IE9 + хорошо, если в IE8 не сильно раскособочит.
Протестировать можно тут:
- https://developer.microsoft.com/en-us/microsoft-edge/tools/screenshots/
- http://browsershots.org/
Выбери там современные версии каждого браузера, потом версии 5-летней давности и разные версии ИЕ и проверь.
Далее, надо проверить, как твои стили совместимы с текстом. Если мы добавим на сайт текстовую страницу, будет ли она корректно отображаться?
Для этого берем любой HTML с разными тегами, например, этот http://motherfuckingwebsite.com/ и добавляем в него ссылку на твой CSS. Твой код тест проваливает - весь текст выгдядит слипшимся, отступов нет. Это значит, что добавление текстовой страницы на сайт вызовет проблемы. Если ты решил сбросить стили браузера, то ты должен прописать вручную все сброшенные стили.
По коду:
> <link rel="stylesheet" type="text/css" href="home.css"></link>
У link нет закрывающего тега.
> <p class="nav-wrapper-logo">ebpaint</p>
Это плохо, так как поисковик проиндексирует именно это слово, а не название компании.
> <p class="banner-row1">We are <span class="letter-spacing-2">Webpaint</span></p>
Тут бы подошел strong для выделения названия. Имя класса - не говорящее.
> <span>digital & branding</span>
А тут em
> <div class="service-wrapper android-service">
> <div class="android-icon"></div>
Не надо тут добавлять лишний div, используй фоновую картинку или псевдоэлемент ::before.
> <h2 class="android-heading">Consectetur</h2>
> <h2 class="monitor-heading">Tristiquet</h2>
А зачем тут свои классына каждый заголовок? там ведь стили абсолютно одинаковые.
> <p class="monitor-text letter-spacing-none">
то же самое, зачем тут monitor-text?
> <h1 class="portfolio-heading">Our Featured Works</h1>
h1 - это заголовок всей страницы. Наверно, h1 логичнее поместить в шапку, где слоган.
> <button class="portfolio-nav-row-btn all-btn" type="button">All</button>
Надо, чтобы эти кнопки работали и скрывали часть картинок. В идеале, с анимацией и без яваскрипта, средствами CSS3
> <img class="portfolio-grid-item portfolio-grid-row1-column1"
Тут можно сделать проще, без таких классов и ручной нумерации картинок.
> <h1 class="footer-heading">Get in Touch</h1>
На странице не может быть 2 раза h1.
> <p class="footer-phone letter-spacing-none">
Телефон надо сделать ссылкой с префиксом tel. Адрес - ссылкой на сервис карт вроде openstreetmap или google/yandex.
Информацию о компании в подвале желательно разметить с помощью микроразметки vcard.
Картинки в портфолио очень тяжелые. В сумме весят под мегабайт. Надо рассмотреть варианты сжатия без визуальной потери качества.
> @font-face { font-family: ReklameScript; src: url('fonts/ReklameScript-Regular_DEMO.otf'); }
Тут надо посмотреть, что выгоднее - сделать логотип в формате SVG/PNG или грузить шрифт ради него? Или хотя бы грузить урезанный шрифт, в котором оставлены только нужные буквы.
> * {
> margin: 0;
> padding: 0;
Это по моему невыгодно. Вот ты сбросил все стили, а дальше будешь все их восстанавливать назад? Без этого у тебя будут слипаться абзацы в тексте, строки в списках итд. В браузере стоят по умолчанию разные полезные стили и не надо их уничтожать.
> p, h1, h2, span {
> letter-spacing: 1px;
Это точно нужно?
> nav {
> display: flex;
Ты изучал, какие браузеры это поддерживают? https://caniuse.com/#search=flexbox - при том там часть браузеров поддерживает только "старую" версию flexbox.
Если тебе надо отцентрировать что-то, не проще использовать table-cell?
Вообще, тут простой сайт, где все максимально квадратно, тут по моему это просто не нужно. Ну или надо предусмореть фоллбек, запасной вариант, чтобы страница не разваливалась в неподдерживающих браузерах.
В картинке спрайта надо оставлять хотя бы пикселей 3-5 между иконками. Иначе при изменении масштаба размер картинки получается нецелым и может показать часть соседней иконки.
Если тебе нужен блог сегодня, то это хорошее решение.
>>64740
То, что сейчас есть, нужно доделывать, пока сделано процентов на 40.
У меня в браузере подвал слипся: https://i.imgur.com/l3rnlch.png . Хромиум 2-летней давности.
Кнопка see portfolio должна бы реагировать на наведение. Кнопки соцсетей - тоже. Эффекты при наведении на кнопку можешь найти где-нибудь в интернете по словам css effects.
Адаптивные версии сделаны очень слабо, такое ощущение, что им особо время не уделялось.
На узком экране (780px) портфолио у меня прижимается к левому краю и не центрируется.
На совсем маленьком экране (300px) меню занимает слишком много места, плюс там огромный заголовок. Ну представь, что ты это на телефоне открыл и у тебя "we are webpaint" растянулось на 2 экрана. Портфолио съехало вбок. Удобно ли пользоваться таким сайтом? Надо сделать версию для маленького экрана лучше. Адаптивность - это не просто перестановка блоков друг над другом, это именно доработка для разных экранов. Подвал тоже сделан плохо, номер телефона на нем в 2 строки, зато в подвале огромные пустые пространства. Подумай, как сделать, чтобы было аккуратно и удобно.
Картинки портфолио стоит сделать ссылками.
Вот как сайт выглядит в FF3.6: https://i.imgur.com/X9yxRP6.png - а ведь этот браузер поддерживает стандарт CSS2.1. Надо бы протестировать сайт в разных браузерах. Хотя бы чтобы он работал хотя бы во всех браузрах 5-летней давности + в IE9 + хорошо, если в IE8 не сильно раскособочит.
Протестировать можно тут:
- https://developer.microsoft.com/en-us/microsoft-edge/tools/screenshots/
- http://browsershots.org/
Выбери там современные версии каждого браузера, потом версии 5-летней давности и разные версии ИЕ и проверь.
Далее, надо проверить, как твои стили совместимы с текстом. Если мы добавим на сайт текстовую страницу, будет ли она корректно отображаться?
Для этого берем любой HTML с разными тегами, например, этот http://motherfuckingwebsite.com/ и добавляем в него ссылку на твой CSS. Твой код тест проваливает - весь текст выгдядит слипшимся, отступов нет. Это значит, что добавление текстовой страницы на сайт вызовет проблемы. Если ты решил сбросить стили браузера, то ты должен прописать вручную все сброшенные стили.
По коду:
> <link rel="stylesheet" type="text/css" href="home.css"></link>
У link нет закрывающего тега.
> <p class="nav-wrapper-logo">ebpaint</p>
Это плохо, так как поисковик проиндексирует именно это слово, а не название компании.
> <p class="banner-row1">We are <span class="letter-spacing-2">Webpaint</span></p>
Тут бы подошел strong для выделения названия. Имя класса - не говорящее.
> <span>digital & branding</span>
А тут em
> <div class="service-wrapper android-service">
> <div class="android-icon"></div>
Не надо тут добавлять лишний div, используй фоновую картинку или псевдоэлемент ::before.
> <h2 class="android-heading">Consectetur</h2>
> <h2 class="monitor-heading">Tristiquet</h2>
А зачем тут свои классына каждый заголовок? там ведь стили абсолютно одинаковые.
> <p class="monitor-text letter-spacing-none">
то же самое, зачем тут monitor-text?
> <h1 class="portfolio-heading">Our Featured Works</h1>
h1 - это заголовок всей страницы. Наверно, h1 логичнее поместить в шапку, где слоган.
> <button class="portfolio-nav-row-btn all-btn" type="button">All</button>
Надо, чтобы эти кнопки работали и скрывали часть картинок. В идеале, с анимацией и без яваскрипта, средствами CSS3
> <img class="portfolio-grid-item portfolio-grid-row1-column1"
Тут можно сделать проще, без таких классов и ручной нумерации картинок.
> <h1 class="footer-heading">Get in Touch</h1>
На странице не может быть 2 раза h1.
> <p class="footer-phone letter-spacing-none">
Телефон надо сделать ссылкой с префиксом tel. Адрес - ссылкой на сервис карт вроде openstreetmap или google/yandex.
Информацию о компании в подвале желательно разметить с помощью микроразметки vcard.
Картинки в портфолио очень тяжелые. В сумме весят под мегабайт. Надо рассмотреть варианты сжатия без визуальной потери качества.
> @font-face { font-family: ReklameScript; src: url('fonts/ReklameScript-Regular_DEMO.otf'); }
Тут надо посмотреть, что выгоднее - сделать логотип в формате SVG/PNG или грузить шрифт ради него? Или хотя бы грузить урезанный шрифт, в котором оставлены только нужные буквы.
> * {
> margin: 0;
> padding: 0;
Это по моему невыгодно. Вот ты сбросил все стили, а дальше будешь все их восстанавливать назад? Без этого у тебя будут слипаться абзацы в тексте, строки в списках итд. В браузере стоят по умолчанию разные полезные стили и не надо их уничтожать.
> p, h1, h2, span {
> letter-spacing: 1px;
Это точно нужно?
> nav {
> display: flex;
Ты изучал, какие браузеры это поддерживают? https://caniuse.com/#search=flexbox - при том там часть браузеров поддерживает только "старую" версию flexbox.
Если тебе надо отцентрировать что-то, не проще использовать table-cell?
Вообще, тут простой сайт, где все максимально квадратно, тут по моему это просто не нужно. Ну или надо предусмореть фоллбек, запасной вариант, чтобы страница не разваливалась в неподдерживающих браузерах.
В картинке спрайта надо оставлять хотя бы пикселей 3-5 между иконками. Иначе при изменении масштаба размер картинки получается нецелым и может показать часть соседней иконки.
Изучай mysqli или PDO
>>66377
> дублирование кода - плохой признак.
Да, можно было вынести повторяющиеся строчки из if, чтобы они шли после.
> $creditBalance -= $monthlyPayment;
> $paymentTotal += $monthlyPayment;
> echo "{$month} месяц спустя: долг = {$creditBalance} руб, выплачено всего {$paymentTotal} руб. \n";
А дополнительный if + break поставить после них.
А так, работает верно.
>>66412
Первый раз такое вижу. Может, он так невидимые теги подсвечивает?
>>66546
Вместо того, чтобы делать стену кода в CompanyBuilder, можно было там сделать массив с описанием работников. И пройтись по нему циклом. Но это не принципиально, так как суть задачи не в этом.
> //Босс у меня это такое количество. Ага, да.
Лучше было сделать так:
create($profession, $rank = 1, $count = 1, $isBoss = false)
Так мы бы могли не указывать часть аргументов и не пришлось бы лепить костыли.
> 'Manager'
Лучше писать Manager::class - это дает защиту от опечаток и автодополняется в IDE.
> public function addDepartment(Department $department)
Можно добавить тут тайп-хинт :void
> abstract public function __construct
Конструктор может быть абстрактным? Вообще, смысла особого это делать нет, так как абстрактные методы - это методы, которые не дописаны и которые должны реализовать потомки. Но потомок класса не может реализовать конструктор для базового класса, он может включать только конструктор для себя. Это просто нелогично как-то.
В Яве например абстрактные конструкторы запрещены: https://stackoverflow.com/questions/28825517/why-cant-we-have-abstract-constructor-in-java
Для чего ты решил сделать абстрактный конструктор?
Далее, у тебя в наследнике конструктор задает значения базовой зарплаты, и тд. Но нигде не написано, что потомок обязан это делать, и это никак не проверяется. Было бы лучше сделать абстрактные методы вроде getStartingSalary - тогда их нельзя было бы не реализовать. Или сделать базовую зарплату аргументом конструктора - тогда ее нельзя было бы не указать.
> Class Marketer Extends Employee
class/extends принято писать маленькими буквами. Это не имена классов.
Ну и ждем полную версию программы, с антикризисными мерами.
> Решение Антикризисной задачи видится тривиальным. Клонирование компании и изменение клона в соответствии условиям
Нет, там есть свои особенности. Лучше сделать.
Изучай mysqli или PDO
>>66377
> дублирование кода - плохой признак.
Да, можно было вынести повторяющиеся строчки из if, чтобы они шли после.
> $creditBalance -= $monthlyPayment;
> $paymentTotal += $monthlyPayment;
> echo "{$month} месяц спустя: долг = {$creditBalance} руб, выплачено всего {$paymentTotal} руб. \n";
А дополнительный if + break поставить после них.
А так, работает верно.
>>66412
Первый раз такое вижу. Может, он так невидимые теги подсвечивает?
>>66546
Вместо того, чтобы делать стену кода в CompanyBuilder, можно было там сделать массив с описанием работников. И пройтись по нему циклом. Но это не принципиально, так как суть задачи не в этом.
> //Босс у меня это такое количество. Ага, да.
Лучше было сделать так:
create($profession, $rank = 1, $count = 1, $isBoss = false)
Так мы бы могли не указывать часть аргументов и не пришлось бы лепить костыли.
> 'Manager'
Лучше писать Manager::class - это дает защиту от опечаток и автодополняется в IDE.
> public function addDepartment(Department $department)
Можно добавить тут тайп-хинт :void
> abstract public function __construct
Конструктор может быть абстрактным? Вообще, смысла особого это делать нет, так как абстрактные методы - это методы, которые не дописаны и которые должны реализовать потомки. Но потомок класса не может реализовать конструктор для базового класса, он может включать только конструктор для себя. Это просто нелогично как-то.
В Яве например абстрактные конструкторы запрещены: https://stackoverflow.com/questions/28825517/why-cant-we-have-abstract-constructor-in-java
Для чего ты решил сделать абстрактный конструктор?
Далее, у тебя в наследнике конструктор задает значения базовой зарплаты, и тд. Но нигде не написано, что потомок обязан это делать, и это никак не проверяется. Было бы лучше сделать абстрактные методы вроде getStartingSalary - тогда их нельзя было бы не реализовать. Или сделать базовую зарплату аргументом конструктора - тогда ее нельзя было бы не указать.
> Class Marketer Extends Employee
class/extends принято писать маленькими буквами. Это не имена классов.
Ну и ждем полную версию программы, с антикризисными мерами.
> Решение Антикризисной задачи видится тривиальным. Клонирование компании и изменение клона в соответствии условиям
Нет, там есть свои особенности. Лучше сделать.
Решено неверно, так как ты сравниваешь только первую и последнюю буквы и делаешь вывод, но надо сравнить все буквы, чтобы понять, что это палиндром.
Смотри, слово "крюк" твоя программа считает палиндромом: http://sandbox.onlinephpfunctions.com/code/79cb3ab0407627348a05d18c0a6e54959008eec8
>>66815
Решил не до конца, так как у тебя там 11 номеров, а правильных среди них нашлось только 8.
> ^(8|7|\+7)
Должны проходить только номера с +7 или 8, но не с 7 без плюса.
Надо переделать, и проверить все номера, которые указаны в задаче.
>>66859
> elseif ($balanceSoftBank || $balanceHomoCredit || $balanceStrawberryBank > $payment) {
Это так не работает. Ты наверно хотел написать "если A, B или C больше, чем D". Но компьютер поймет это так:
"если A не равно нулю, или B не равно нулю, или C больше чем D".
Оператор || не значит дословно "или". Он берет значения справа и слева, и, если хотя бы одно "не пусто", то возвращает значение true (истина), иначе, если оба "пусты", то возвращает false (ложь).
"Пустые" значения - это 0, "" (пустая строка), "0" (строка из символа 0), false, null, пустой массив. Они перечислены тут: http://php.net/manual/ru/language.types.boolean.php
То есть:
пустое || пустое => false
пустое || непустое => true
непустое || пустое => true
непустое || непустое => true
А почему же в учебнике пишут, что это "или"? Потому, что при объединении 2 условий он действительно так работает. Смотри:
($a > $b) || ($c > $d)
Здесь, если $a больше $b, и условие слева выполняется, то оператор > вернет "true", и оператор || тоже вернет true, не проверяя правое условие. И только если оба условия не выполняются, они вернут false (ложь), и оператор || тоже вернет false.
Соответственно, выражение $a || $b || $c > $d работает совсем не так, как ты хотел.
Решено неверно, так как ты сравниваешь только первую и последнюю буквы и делаешь вывод, но надо сравнить все буквы, чтобы понять, что это палиндром.
Смотри, слово "крюк" твоя программа считает палиндромом: http://sandbox.onlinephpfunctions.com/code/79cb3ab0407627348a05d18c0a6e54959008eec8
>>66815
Решил не до конца, так как у тебя там 11 номеров, а правильных среди них нашлось только 8.
> ^(8|7|\+7)
Должны проходить только номера с +7 или 8, но не с 7 без плюса.
Надо переделать, и проверить все номера, которые указаны в задаче.
>>66859
> elseif ($balanceSoftBank || $balanceHomoCredit || $balanceStrawberryBank > $payment) {
Это так не работает. Ты наверно хотел написать "если A, B или C больше, чем D". Но компьютер поймет это так:
"если A не равно нулю, или B не равно нулю, или C больше чем D".
Оператор || не значит дословно "или". Он берет значения справа и слева, и, если хотя бы одно "не пусто", то возвращает значение true (истина), иначе, если оба "пусты", то возвращает false (ложь).
"Пустые" значения - это 0, "" (пустая строка), "0" (строка из символа 0), false, null, пустой массив. Они перечислены тут: http://php.net/manual/ru/language.types.boolean.php
То есть:
пустое || пустое => false
пустое || непустое => true
непустое || пустое => true
непустое || непустое => true
А почему же в учебнике пишут, что это "или"? Потому, что при объединении 2 условий он действительно так работает. Смотри:
($a > $b) || ($c > $d)
Здесь, если $a больше $b, и условие слева выполняется, то оператор > вернет "true", и оператор || тоже вернет true, не проверяя правое условие. И только если оба условия не выполняются, они вернут false (ложь), и оператор || тоже вернет false.
Соответственно, выражение $a || $b || $c > $d работает совсем не так, как ты хотел.
Регулярка написана правильно. Поначалу это сложно, но если практиковаться побольше, то ты сможешь писать и читать регулярки легко.
>>67366
Так смысл passphrase (пароля), что он никуда не сохраняется и есть только в твоей голове. Если ты сохранишь его на диск, то тебе проще использовать ssh-ключи в открытом виде, без пароля.
Задача ssh-агента - сохранить пароль в памяти, пока компьютер включен (не на диске!), чтобы не вводить пароль много раз. Если тебе это надоело, используй ключи без паролей.
Если тебе лень писать команду запуска агента, найди какой-нибудь GUI, который будет его запускать при входе и показывать окно ввода пароля.
> Почему вы решили что проблема в этом? Проблема в том что картинка выходит за пределы контейнера#lightbox.
Да, я ошибся. Проблема там в том, что height 66% не работает.
> Аргументируйте, пожалуйста, почему крестик нужно сделать видимым всегда, и, может быть, мне будет легче это сделать.
Потому что ты не можешь нажать на кнопку, о которой не знаешь. Про эскейп многие пользователи тоже могут не знать, да и на сайтах он часто не работает, я его даже не пробую жать.
Ну и на мобильных устройствах нет "наведения мыши".
Кнопки должны быть видны, это однозначно. Крестик можно при желании поместить снаружи картинки.
> Я сделал проверку if (lightbox.css('display') == 'block') { , но сейчас загуглил и понял что лучше сделать проверку .is(':visible'). Это хороший способ?
Да, однозначно, так как есть много вариантов скрыть элемент, кроме display: none. Например: поставить display: none на родителе.
Также, еще мне нравится идея просто хранить состояние попапа в переменной, а не лезть за ним в DOM.
Что еще мне не нравится - то, что у тебя весь скрипт - гигантская анонимная функция, которая засунута в $().ready(). Вот как это читать? Читатель, по твоему, должен терпеливо прочесть все 160 строк сверху донизу (это пока их 160, а дальше будет больше)? Это неудобно. Гораздо лучше разделить отдельно функции и отдельно код инициализации.
Также, мне вообще не нравится идея "самозапускающихся скриптов". Мне нравится идея, когда JS скрипт - это модуль, просто набор определений (классов, функций) и в нем само собой ничего не запускается. Твой подход на больших сайтах приводит к тому, что все только дописывают код в ready() и мы имеем функции на тысячи строк, причем там большая часть кода не нужна на текущей странице, но все равно выполняется, и никто не может понять, какая часть кода еще используется, какая уже не нужна. И потому код только копится и растет со временем.
То есть это выглядит как:
$(...).click(.... 100 строк ...);
$(...).hover(.... 50 строк ...);
И так несколько десятков блоков подряд.
Также, такой подход приводит к тому, что глядя на HTML-код страницы, невозможно понять, какие к нему привязаны обработчики - они спрятаны где-то в тысячах строк кода в ready().
Какие ты видишь решения проблемы?
> $(window).scroll(function() {
Это не очень хорошая идея, надо бы хотя бы троттлить тут вызов функции, а то при плавном скроллинге твоя функция будет вызываться с большой частотой и нагружать браузер постоянным обновлением дома. Вообще, функции , которые вешаются на scroll - это зло для производительности (особенно на мобильных):
- https://developers.google.com/web/updates/2016/06/passive-event-listeners
- http://joji.me/en-us/blog/how-to-develop-high-performance-onscroll-event
- https://www.sitepoint.com/throttle-scroll-events/
- https://www.html5rocks.com/en/tutorials/speed/scrolling/
> if ($(a).has(e.target).length == 0 && !$(e.target).is('.file-link')) {
Еще раз спрошу, а почему не использовать тут closest() или is() вместо has() и поиска кучи узлов?
Плюс, в твоем коде есть недостаток, что var a = $('.file-link'); не содержит добавленные позже в DOM узлы. Например, картинки из постов, подгруженных через аякс.
> var fullsize = $('.fullsize');
Не лучше ли сохранять ссылку в переменной, а не искать каждый раз этот класс по всему дереву DOM?
Ну и не вижу обработку ошибок. Также, хорошо бы добавить прелоадер, хотя бы текст "загрузка...".
> Так как быть? Я не могу явно указать ширину или высоту контейнера, т.к. он растянется шире картинки, а нужно чтобы контейнер был не больше 66% страницы и картинка вписывалась в него, либо чтобы сама картинка была не больше 66% а размер контейнера высчитался из содержимого. Я не понимаю что тут можно сделать.
Ну давай искать варианты и тестировать. Я для затравки подкину пару идей, а ты их потестируй в разных условиях и браузерах:
1) https://codepen.io/anon/pen/yjyLyP
Тут главная идея в том, что мы позиционируем картинку внутри контейнера абсолютно и за счет этого получаем возможность использовать max-height, а также центрирование за счет margin-auto. Перечитай спец-ю про abs pos, если что-то непонятно:
- https://www.w3.org/TR/2011/REC-CSS2-20110607/visudet.html#abs-replaced-width
- https://www.w3.org/TR/2011/REC-CSS2-20110607/visudet.html#abs-replaced-height
Ограничение в 66% мы делаем за счет жесткого задания размера контейнера. Но я поймал себя на мысли, что можно было сделать контейнер на все окно, а ограничение сделать заданием max-height: 66% либо top/bottom: 17% на картинке.
Вообще, я надеюсь, что цифра 66% условная, так как при ней не используется значительная часть экрана.
2) зловещий flexbox https://codepen.io/anon/pen/GdgRjo?editors=1100
Подвохи с ним - он не везде поддерживается и там много тонкостей. Например, у меня в фаерфоксе раскособочило картинку 800x200 (ее ужало до 400x200 с нарушением пропорций), хотя в Хроме тот же код работал как надо и она уменьшается. То ли я неправильно что-то сделал, то ли баг, то ли еще что-то. Не хочешь помучаться и выяснить?
3) https://codepen.io/anon/pen/WJbNKM?editors=1100
Тут мы позиционируем картинку ниже середины (top: 50%) и сдвигаем ее вверх на середину за счет translate. Так как картинка позиционирована абсолютно, мы можем применять max-height в процентах.
Минус - я не придумал в этих методах, как тут завернуть картинку в обертку. А обертка нужна, если мы например, хотим поместить крестик в углу или подпись к картинке - нам нужна обертка, равная по размеру картинке. Но если мы добавим обертку, перестанет работать max-height на картинке. А если мы спозиц. картинку абсолютно внутри обертки, то картинка перестанет растягивать ее. Замкнутый круг.
Что-то мне кажется, для добавления обертки надо опять откатываться к яваскрипту. Либо добить решение с флексбоксом. Вот такой вот он, CSS. Предлагай свои идеи.
Даже если использовать яваскрипт, то лучше как-то придумать схему, чтобы не центрировать им картинку, а например, только задавать пропорции для контейнера. То есть:
- яваскриптом вычисляем размеры картинки
- ограничиваем их с учетом размеров окна
- ставим их на контейнер как width/height
- центрируем/ограничиваем размер за счет CSS
Мне кажется, это лучше будет работать при изменении размеров окна, например. Вот пример: https://codepen.io/anon/pen/MGYWLZ?editors=1100 - тут специально добавлена желтая обертка, чтобы показать, что контейнер пропорционален картинке.
> Почему не нужно? Мы в пару местах делаем проверку на этот элемент. Нужно каждый раз их искать?
Использовать вместо этого is()/closest() и ничего не искать.
> Этот элемент нужно искать именно каждый раз когда мы делаем клик, потому что, при каждом открытии, он, каждый раз, создаётся новый.
ну все равно, можно сохранять ссылку на него, а не искать в DOM.
> Почему вы решили что проблема в этом? Проблема в том что картинка выходит за пределы контейнера#lightbox.
Да, я ошибся. Проблема там в том, что height 66% не работает.
> Аргументируйте, пожалуйста, почему крестик нужно сделать видимым всегда, и, может быть, мне будет легче это сделать.
Потому что ты не можешь нажать на кнопку, о которой не знаешь. Про эскейп многие пользователи тоже могут не знать, да и на сайтах он часто не работает, я его даже не пробую жать.
Ну и на мобильных устройствах нет "наведения мыши".
Кнопки должны быть видны, это однозначно. Крестик можно при желании поместить снаружи картинки.
> Я сделал проверку if (lightbox.css('display') == 'block') { , но сейчас загуглил и понял что лучше сделать проверку .is(':visible'). Это хороший способ?
Да, однозначно, так как есть много вариантов скрыть элемент, кроме display: none. Например: поставить display: none на родителе.
Также, еще мне нравится идея просто хранить состояние попапа в переменной, а не лезть за ним в DOM.
Что еще мне не нравится - то, что у тебя весь скрипт - гигантская анонимная функция, которая засунута в $().ready(). Вот как это читать? Читатель, по твоему, должен терпеливо прочесть все 160 строк сверху донизу (это пока их 160, а дальше будет больше)? Это неудобно. Гораздо лучше разделить отдельно функции и отдельно код инициализации.
Также, мне вообще не нравится идея "самозапускающихся скриптов". Мне нравится идея, когда JS скрипт - это модуль, просто набор определений (классов, функций) и в нем само собой ничего не запускается. Твой подход на больших сайтах приводит к тому, что все только дописывают код в ready() и мы имеем функции на тысячи строк, причем там большая часть кода не нужна на текущей странице, но все равно выполняется, и никто не может понять, какая часть кода еще используется, какая уже не нужна. И потому код только копится и растет со временем.
То есть это выглядит как:
$(...).click(.... 100 строк ...);
$(...).hover(.... 50 строк ...);
И так несколько десятков блоков подряд.
Также, такой подход приводит к тому, что глядя на HTML-код страницы, невозможно понять, какие к нему привязаны обработчики - они спрятаны где-то в тысячах строк кода в ready().
Какие ты видишь решения проблемы?
> $(window).scroll(function() {
Это не очень хорошая идея, надо бы хотя бы троттлить тут вызов функции, а то при плавном скроллинге твоя функция будет вызываться с большой частотой и нагружать браузер постоянным обновлением дома. Вообще, функции , которые вешаются на scroll - это зло для производительности (особенно на мобильных):
- https://developers.google.com/web/updates/2016/06/passive-event-listeners
- http://joji.me/en-us/blog/how-to-develop-high-performance-onscroll-event
- https://www.sitepoint.com/throttle-scroll-events/
- https://www.html5rocks.com/en/tutorials/speed/scrolling/
> if ($(a).has(e.target).length == 0 && !$(e.target).is('.file-link')) {
Еще раз спрошу, а почему не использовать тут closest() или is() вместо has() и поиска кучи узлов?
Плюс, в твоем коде есть недостаток, что var a = $('.file-link'); не содержит добавленные позже в DOM узлы. Например, картинки из постов, подгруженных через аякс.
> var fullsize = $('.fullsize');
Не лучше ли сохранять ссылку в переменной, а не искать каждый раз этот класс по всему дереву DOM?
Ну и не вижу обработку ошибок. Также, хорошо бы добавить прелоадер, хотя бы текст "загрузка...".
> Так как быть? Я не могу явно указать ширину или высоту контейнера, т.к. он растянется шире картинки, а нужно чтобы контейнер был не больше 66% страницы и картинка вписывалась в него, либо чтобы сама картинка была не больше 66% а размер контейнера высчитался из содержимого. Я не понимаю что тут можно сделать.
Ну давай искать варианты и тестировать. Я для затравки подкину пару идей, а ты их потестируй в разных условиях и браузерах:
1) https://codepen.io/anon/pen/yjyLyP
Тут главная идея в том, что мы позиционируем картинку внутри контейнера абсолютно и за счет этого получаем возможность использовать max-height, а также центрирование за счет margin-auto. Перечитай спец-ю про abs pos, если что-то непонятно:
- https://www.w3.org/TR/2011/REC-CSS2-20110607/visudet.html#abs-replaced-width
- https://www.w3.org/TR/2011/REC-CSS2-20110607/visudet.html#abs-replaced-height
Ограничение в 66% мы делаем за счет жесткого задания размера контейнера. Но я поймал себя на мысли, что можно было сделать контейнер на все окно, а ограничение сделать заданием max-height: 66% либо top/bottom: 17% на картинке.
Вообще, я надеюсь, что цифра 66% условная, так как при ней не используется значительная часть экрана.
2) зловещий flexbox https://codepen.io/anon/pen/GdgRjo?editors=1100
Подвохи с ним - он не везде поддерживается и там много тонкостей. Например, у меня в фаерфоксе раскособочило картинку 800x200 (ее ужало до 400x200 с нарушением пропорций), хотя в Хроме тот же код работал как надо и она уменьшается. То ли я неправильно что-то сделал, то ли баг, то ли еще что-то. Не хочешь помучаться и выяснить?
3) https://codepen.io/anon/pen/WJbNKM?editors=1100
Тут мы позиционируем картинку ниже середины (top: 50%) и сдвигаем ее вверх на середину за счет translate. Так как картинка позиционирована абсолютно, мы можем применять max-height в процентах.
Минус - я не придумал в этих методах, как тут завернуть картинку в обертку. А обертка нужна, если мы например, хотим поместить крестик в углу или подпись к картинке - нам нужна обертка, равная по размеру картинке. Но если мы добавим обертку, перестанет работать max-height на картинке. А если мы спозиц. картинку абсолютно внутри обертки, то картинка перестанет растягивать ее. Замкнутый круг.
Что-то мне кажется, для добавления обертки надо опять откатываться к яваскрипту. Либо добить решение с флексбоксом. Вот такой вот он, CSS. Предлагай свои идеи.
Даже если использовать яваскрипт, то лучше как-то придумать схему, чтобы не центрировать им картинку, а например, только задавать пропорции для контейнера. То есть:
- яваскриптом вычисляем размеры картинки
- ограничиваем их с учетом размеров окна
- ставим их на контейнер как width/height
- центрируем/ограничиваем размер за счет CSS
Мне кажется, это лучше будет работать при изменении размеров окна, например. Вот пример: https://codepen.io/anon/pen/MGYWLZ?editors=1100 - тут специально добавлена желтая обертка, чтобы показать, что контейнер пропорционален картинке.
> Почему не нужно? Мы в пару местах делаем проверку на этот элемент. Нужно каждый раз их искать?
Использовать вместо этого is()/closest() и ничего не искать.
> Этот элемент нужно искать именно каждый раз когда мы делаем клик, потому что, при каждом открытии, он, каждый раз, создаётся новый.
ну все равно, можно сохранять ссылку на него, а не искать в DOM.
> public function __construct() {
> include 'views/header.php';
Это плохая идея. Конструктор для инициализации объекта, а не для вывода шаблонов.
> public function __destruct() {
Эта идея еще хуже. PHP - язык со сборкой мусора и ты не можешь предсказать, когда будет удален объект и вызван деструктор. Деструктор используется только для освобождения каких-то ресурсов, а лучше по возможности вообще не использовать.
> $orgInfo = $org->getOrgInfo();
> include 'views/reportBody.php';
А зачем нужно OrgInfo? Нельзя ли в организации сделать методы для вычислений этих чисел? Просто у меня ощущение, что этот класс заточен только под вывод таблицы, и тогда код getOrgInfo() желательно вынести из компании куда-нибудь, хотя бы в ту же OrgInfo. Или вообще ликвидировать этот метод.
Поля orgName и orgTitle точно не нужны, так как для них есть методы у компании.
> public function getClass() {
Тут нужен тайп-хинт на возвращаемое значение.
> $this->addEmployee($employee);
> } catch (Exception $e) {
> Dbg::exceptionEcho($e);
Это не нужно делать. try/catch не нужен. PHP сам выводит непойманные исключения, если поменять настройки в php.ini.
> public function promoteStuff(array $promotionList) {
Я не думаю, что это надо делать в департаменте. Тут от департамента ничего не требуется и работников можно повышать напрямую.
> $classMatch = (get_class($employee) == $employeeSelector->getClass());
> $rangMatch = (in_array($employee->getRang(), $employeeSelector->getRang()));
> $leaderMatch = (in_array($employee->isLeader(), $employeeSelector->getLeader()));
По моему было бы гораздо удачнее сделать так:
if ($employeeSelector->matches($employee)) ...
Это позволило бы поместить логику отбора в класс-фильтра, где ей и место. Ну и еще есть такой вариант с коллбеком:
function find...(callable $filter) {
...
if ($filter($employee)) {
$list[] = $employee;
}
...
> public function countDepPageCost(): float {
> return round($pageCost, 3);
Не надо делать тут round, так как это нужно только для вывода в таблицу и должно быть там, где делается вывод, а не тут. Тут должен быть метод, который возвращает точное значение.
> abstract protected function setDefaults();
Это не очень хорошо, так как непонятно, что эта функция должна делать. Это никак не описано и никак не проверяется. Мне непонятно, что в ней надо написать. По моему так лучше сделать функции getStartingSalary(), getStartingCoffee() и тд, с которыми все проще и понятнее.
> public function setLeader($leader) {
Нужны тайп-хинты.
> public function upRang() {
нет проверки на выход за пределы допустимых значений.
> $vectorSecondAC = clone $vectorVanilla;
В клонировании у теябя допущена ошибка. Этот метод не создает глубокую копию компании. он делает клон компании, но в него помещает ссылки на те же самые департаменты с теми же самыми работниками - они по умолчанию не клонируются, а просто копируются ссылки. Изучи магический метод __clone().
> $this->organisation->setTitle("после антикризисных мер #1");
Это неправильно, ради решения задачи про антикризисные меры добавлять в Компанию поле-комментарий. Это не нужно компании, это нужно только в антикризисных мерах, и это надо делать где-то в другом месте.
> new EmployeeSelector('Engineer', [1, 2, 3], [true, false]);
лучше сделать возможность указать "не важно" для ранга. null, например, передать.
Или так:
$selector = new Selector;
$selector->setClass(...);
Сортировку лучше делать в одной функции, так:
$aLeader = $a->isLeader() ? 1 : 0;
$bLeader = $b->isLeader() ? 1 : 0;
if ($aLeader != $bLeader) {
return ...;
}
// иначе, сравниваем ранг
Также, есть еще такой трюк, вычисляем "вес" и сравниваем его:
$aWeight = ( $a->isLeader() ? 100 : 0) + $a->getRank();
$bWeight = ...;
// сравниваем вес
> $managersOfSertainRangs
$managersByRank
> $thisRangToPromote = count($currentRangManagers);
> $neededToPromote = ceil(0.5 * ($thisRangToPromote));
Это лучше записать в одно выражение без промежуточной переменной.
По view: в идеале, надо использовать htmlspecialchars при вставке текста в HTML. Иначе может быть уязвимость XSS: https://github.com/codedokode/pasta/blob/master/security/xss.md
По вопросам:
-------
> Только вот у меня вопрос возникает, а для кого пишутся эти исключения?
Тут есть такой ответ:
Выброс исключения - это способ функции заявить о невозможности выполнения задачи. То есть это такой способ передачи информации out-of-band (не через return). Если исключение планируется ловить, то для этого используется кастомный класс.
То есть функция либо возвращает результат (если он есть), либо выбрасывает исключение. НЕ выбросила - значит, все ок.
> Для самого разработчика, что бы на этапе тестирования увидеть ошибки?
Да.
> Или для пользователя?
Только если чтобы сообщить о них разработчику. Пользователь ведь не разбирается в коде.
Но ты не забывай, что бывает разный пользователь. Есть пользователь программы, а есть пользователь функции - другой разработчик, который ее использует в своем коде.
> Останавливать программу после срабатывания такого вот исключения или нет?
Да. если она неправильная, то ее надо останавливать. Чем раньше ошибка найдена, тем дешевле ее исправить. Читай
- https://habrahabr.ru/post/218325/
- https://www.martinfowler.com/ieeeSoftware/failFast.pdf
> Если например пытаешься добавить 2 одинаковых департамента, то второй просто не добавляется, но без остановки всё как бы и хорошо работает. Обошли дублирование и всё ок, выполнению программы это не мешает.
В программе явно есть ошибка, ты ее скрываешь, в итоге она вылезет где-то на более позднем этапе, например, в виде неправильных чисел. И ее найти будет гораздо труднее. Особенно когда эта программа станет огромной и в ней будут спрятаны сотни разных ошибок, которые сделали предыдущие разработчики, а исправлять придется тебе.
> Первый серьезный ступор был тут, и он по сути никуда не делся. Я просто написал класс OrgInfo, но оставил все поля в нем public, так как просто бомбануло при попытке написать в этот класс 24 геттера/сеттера и в том месте где я их заполняю
Ок, но другой вариант был не делать этот класс, а сделать геттеры в Company. Это позволяет получать отдельные цифры, не вычисляя все.
Еще один вариант - сделать только геттеры, без сеттеров, такого вида:
$info = new OrgInfo($company);
echo $info->getAvgSalary();
зачем тебе там сеттеры?
> Ну опять же кроме геттеров/сеттеров пустышек. На них тоже нужно выставлять тайпхинт по паравилу хорошего тона, даже если ты просто возвращаешь что-то без изменения/вычисления?
Желательно. Для полей ведь ты не указал типы значений, как понять, что там хранится? Плюс, это защищает от ошибок, например, попытки записать некорректное значение. Ты бы мог еще больше проверок сделать, например, запретить ставить неправильный ранг.
> Еще не понятно как быть в случае как с моей функцией getTopAnalyst() - либо она возвращает объект Analyst, либо null (по логике отсутствие объекта это как раз оно), и сюда ничего нельзя поставить на выходной тип, будут ошибки.
Есть тип ?Analyst со знаком вопроса. Гугли. Например https://wiki.php.net/rfc/nullable_types
> Но не стал склеивать методы demoteLeader() и promoteLeader() в один большой метод замены, просто заприватил их и оставил для лучшей читабельности. завел публичный swapLeader(), который просто вызывает их в нужной последовательности, логика в этом есть имхо.
Ну ок, тогда, получается, ты за возможность "обезглавить" департамент. Такое тоже возможно, почему бы и нет. Просто если оставить только swapLeader, то можно запретить делать департамент без босса или с несколькими боссами. А с promote/demote это возможно.
> В общем тут у меня проблема и не понимание как из этого слабого места выкрутиться. [про абстрактные методы]
Сделать абс. методы вроде getStartingSalary():float { return 500; } для каждого значения.
> И просто вынес это в отдельное поле да еще и выставляющееся в конструкторе. Не понял если честно что в этом плохого.
Ненужное дублирование данных, по моему. Можно подумать, что это какой-то отдельный список, не совпадающий с тем, что в компании. Ничего страшного в том, чтобы сделать getDepartments(), нету.
> Может быть стоит антикризис сделать вообще статическим классом?
Не думаю. Тогда ты должен будешь хранить компанию в статическом поле и нельзя работать с несколькими компаниями.
> А просто передавать ему объект, а он его будет возвращать в измененном виде аки обычная процедурная функция?
Вообще, можно.Но лучше бы обычный метод, а не статический. Так как в теории у "антикризисного менеджера" могут быть настройки (сколько процентов увольнять), зависимости, а для них нужны поля и $this.
Кстати, у нас еще есть задача про Гостиницу. Не хочешь отточить навыки ООП?
> public function __construct() {
> include 'views/header.php';
Это плохая идея. Конструктор для инициализации объекта, а не для вывода шаблонов.
> public function __destruct() {
Эта идея еще хуже. PHP - язык со сборкой мусора и ты не можешь предсказать, когда будет удален объект и вызван деструктор. Деструктор используется только для освобождения каких-то ресурсов, а лучше по возможности вообще не использовать.
> $orgInfo = $org->getOrgInfo();
> include 'views/reportBody.php';
А зачем нужно OrgInfo? Нельзя ли в организации сделать методы для вычислений этих чисел? Просто у меня ощущение, что этот класс заточен только под вывод таблицы, и тогда код getOrgInfo() желательно вынести из компании куда-нибудь, хотя бы в ту же OrgInfo. Или вообще ликвидировать этот метод.
Поля orgName и orgTitle точно не нужны, так как для них есть методы у компании.
> public function getClass() {
Тут нужен тайп-хинт на возвращаемое значение.
> $this->addEmployee($employee);
> } catch (Exception $e) {
> Dbg::exceptionEcho($e);
Это не нужно делать. try/catch не нужен. PHP сам выводит непойманные исключения, если поменять настройки в php.ini.
> public function promoteStuff(array $promotionList) {
Я не думаю, что это надо делать в департаменте. Тут от департамента ничего не требуется и работников можно повышать напрямую.
> $classMatch = (get_class($employee) == $employeeSelector->getClass());
> $rangMatch = (in_array($employee->getRang(), $employeeSelector->getRang()));
> $leaderMatch = (in_array($employee->isLeader(), $employeeSelector->getLeader()));
По моему было бы гораздо удачнее сделать так:
if ($employeeSelector->matches($employee)) ...
Это позволило бы поместить логику отбора в класс-фильтра, где ей и место. Ну и еще есть такой вариант с коллбеком:
function find...(callable $filter) {
...
if ($filter($employee)) {
$list[] = $employee;
}
...
> public function countDepPageCost(): float {
> return round($pageCost, 3);
Не надо делать тут round, так как это нужно только для вывода в таблицу и должно быть там, где делается вывод, а не тут. Тут должен быть метод, который возвращает точное значение.
> abstract protected function setDefaults();
Это не очень хорошо, так как непонятно, что эта функция должна делать. Это никак не описано и никак не проверяется. Мне непонятно, что в ней надо написать. По моему так лучше сделать функции getStartingSalary(), getStartingCoffee() и тд, с которыми все проще и понятнее.
> public function setLeader($leader) {
Нужны тайп-хинты.
> public function upRang() {
нет проверки на выход за пределы допустимых значений.
> $vectorSecondAC = clone $vectorVanilla;
В клонировании у теябя допущена ошибка. Этот метод не создает глубокую копию компании. он делает клон компании, но в него помещает ссылки на те же самые департаменты с теми же самыми работниками - они по умолчанию не клонируются, а просто копируются ссылки. Изучи магический метод __clone().
> $this->organisation->setTitle("после антикризисных мер #1");
Это неправильно, ради решения задачи про антикризисные меры добавлять в Компанию поле-комментарий. Это не нужно компании, это нужно только в антикризисных мерах, и это надо делать где-то в другом месте.
> new EmployeeSelector('Engineer', [1, 2, 3], [true, false]);
лучше сделать возможность указать "не важно" для ранга. null, например, передать.
Или так:
$selector = new Selector;
$selector->setClass(...);
Сортировку лучше делать в одной функции, так:
$aLeader = $a->isLeader() ? 1 : 0;
$bLeader = $b->isLeader() ? 1 : 0;
if ($aLeader != $bLeader) {
return ...;
}
// иначе, сравниваем ранг
Также, есть еще такой трюк, вычисляем "вес" и сравниваем его:
$aWeight = ( $a->isLeader() ? 100 : 0) + $a->getRank();
$bWeight = ...;
// сравниваем вес
> $managersOfSertainRangs
$managersByRank
> $thisRangToPromote = count($currentRangManagers);
> $neededToPromote = ceil(0.5 * ($thisRangToPromote));
Это лучше записать в одно выражение без промежуточной переменной.
По view: в идеале, надо использовать htmlspecialchars при вставке текста в HTML. Иначе может быть уязвимость XSS: https://github.com/codedokode/pasta/blob/master/security/xss.md
По вопросам:
-------
> Только вот у меня вопрос возникает, а для кого пишутся эти исключения?
Тут есть такой ответ:
Выброс исключения - это способ функции заявить о невозможности выполнения задачи. То есть это такой способ передачи информации out-of-band (не через return). Если исключение планируется ловить, то для этого используется кастомный класс.
То есть функция либо возвращает результат (если он есть), либо выбрасывает исключение. НЕ выбросила - значит, все ок.
> Для самого разработчика, что бы на этапе тестирования увидеть ошибки?
Да.
> Или для пользователя?
Только если чтобы сообщить о них разработчику. Пользователь ведь не разбирается в коде.
Но ты не забывай, что бывает разный пользователь. Есть пользователь программы, а есть пользователь функции - другой разработчик, который ее использует в своем коде.
> Останавливать программу после срабатывания такого вот исключения или нет?
Да. если она неправильная, то ее надо останавливать. Чем раньше ошибка найдена, тем дешевле ее исправить. Читай
- https://habrahabr.ru/post/218325/
- https://www.martinfowler.com/ieeeSoftware/failFast.pdf
> Если например пытаешься добавить 2 одинаковых департамента, то второй просто не добавляется, но без остановки всё как бы и хорошо работает. Обошли дублирование и всё ок, выполнению программы это не мешает.
В программе явно есть ошибка, ты ее скрываешь, в итоге она вылезет где-то на более позднем этапе, например, в виде неправильных чисел. И ее найти будет гораздо труднее. Особенно когда эта программа станет огромной и в ней будут спрятаны сотни разных ошибок, которые сделали предыдущие разработчики, а исправлять придется тебе.
> Первый серьезный ступор был тут, и он по сути никуда не делся. Я просто написал класс OrgInfo, но оставил все поля в нем public, так как просто бомбануло при попытке написать в этот класс 24 геттера/сеттера и в том месте где я их заполняю
Ок, но другой вариант был не делать этот класс, а сделать геттеры в Company. Это позволяет получать отдельные цифры, не вычисляя все.
Еще один вариант - сделать только геттеры, без сеттеров, такого вида:
$info = new OrgInfo($company);
echo $info->getAvgSalary();
зачем тебе там сеттеры?
> Ну опять же кроме геттеров/сеттеров пустышек. На них тоже нужно выставлять тайпхинт по паравилу хорошего тона, даже если ты просто возвращаешь что-то без изменения/вычисления?
Желательно. Для полей ведь ты не указал типы значений, как понять, что там хранится? Плюс, это защищает от ошибок, например, попытки записать некорректное значение. Ты бы мог еще больше проверок сделать, например, запретить ставить неправильный ранг.
> Еще не понятно как быть в случае как с моей функцией getTopAnalyst() - либо она возвращает объект Analyst, либо null (по логике отсутствие объекта это как раз оно), и сюда ничего нельзя поставить на выходной тип, будут ошибки.
Есть тип ?Analyst со знаком вопроса. Гугли. Например https://wiki.php.net/rfc/nullable_types
> Но не стал склеивать методы demoteLeader() и promoteLeader() в один большой метод замены, просто заприватил их и оставил для лучшей читабельности. завел публичный swapLeader(), который просто вызывает их в нужной последовательности, логика в этом есть имхо.
Ну ок, тогда, получается, ты за возможность "обезглавить" департамент. Такое тоже возможно, почему бы и нет. Просто если оставить только swapLeader, то можно запретить делать департамент без босса или с несколькими боссами. А с promote/demote это возможно.
> В общем тут у меня проблема и не понимание как из этого слабого места выкрутиться. [про абстрактные методы]
Сделать абс. методы вроде getStartingSalary():float { return 500; } для каждого значения.
> И просто вынес это в отдельное поле да еще и выставляющееся в конструкторе. Не понял если честно что в этом плохого.
Ненужное дублирование данных, по моему. Можно подумать, что это какой-то отдельный список, не совпадающий с тем, что в компании. Ничего страшного в том, чтобы сделать getDepartments(), нету.
> Может быть стоит антикризис сделать вообще статическим классом?
Не думаю. Тогда ты должен будешь хранить компанию в статическом поле и нельзя работать с несколькими компаниями.
> А просто передавать ему объект, а он его будет возвращать в измененном виде аки обычная процедурная функция?
Вообще, можно.Но лучше бы обычный метод, а не статический. Так как в теории у "антикризисного менеджера" могут быть настройки (сколько процентов увольнять), зависимости, а для них нужны поля и $this.
Кстати, у нас еще есть задача про Гостиницу. Не хочешь отточить навыки ООП?
А не подскажет ли кто-нибудь, где можно почитать описание такой вот не хитрой конструкции в статическом методе (его части, там несколько подобных конструкций следуют одна за другой):
if ( something true or false) { return; }
Этот метод вызывается через Paamayim Nekudotayim и в принципе понятно, что он делает, он возвращает вычисленное выражение от if всё дальше и дальше накапливая вычисления...Но описания такого подхода, что прос то return; и всё, я нигде не нашёл, подскажите, будьте любезны.
Это копия, сохраненная 12 мая 2018 года.
Скачать тред: только с превью, с превью и прикрепленными файлами.
Второй вариант может долго скачиваться. Файлы будут только в живых или недавно утонувших тредах. Подробнее
Если вам полезен архив М.Двача, пожертвуйте на оплату сервера.