diff --git a/Dockerfile b/Dockerfile index 31fdf1ae..95e3f9bf 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ FROM hexletbasics/base-image -ARG PHP_VERSION=8.4 +ARG PHP_VERSION=8.5 WORKDIR /exercises-php diff --git a/composer.json b/composer.json index a2cd8579..df5cbfde 100644 --- a/composer.json +++ b/composer.json @@ -17,9 +17,9 @@ } ], "autoload": { - "files": [ - "src/Functions.php" - ] + "psr-4": { + "HexletBasics\\Exercise\\": "src/" + } }, "require-dev": { "friendsofphp/php-cs-fixer": "^3.0", diff --git a/modules/10-basics/10-hello-world/index.php b/modules/10-basics/10-hello-world/Solution.php similarity index 100% rename from modules/10-basics/10-hello-world/index.php rename to modules/10-basics/10-hello-world/Solution.php diff --git a/modules/10-basics/10-hello-world/SolutionTest.php b/modules/10-basics/10-hello-world/SolutionTest.php index 3934daad..a2377bf9 100644 --- a/modules/10-basics/10-hello-world/SolutionTest.php +++ b/modules/10-basics/10-hello-world/SolutionTest.php @@ -2,9 +2,7 @@ namespace HexletBasics\Basics\HelloWorld; -use PHPUnit\Framework\TestCase; - -\HexletBasics\Functions\runScript(); +use HexletBasics\Exercise\TestCase; class SolutionTest extends TestCase { @@ -12,6 +10,5 @@ public function test() { $expected = 'Hello, World!'; $this->expectOutputString($expected); - require 'index.php'; } } diff --git a/modules/10-basics/10-hello-world/ru/README.md b/modules/10-basics/10-hello-world/ru/README.md index f303ed9c..8974c7e1 100644 --- a/modules/10-basics/10-hello-world/ru/README.md +++ b/modules/10-basics/10-hello-world/ru/README.md @@ -1,42 +1,85 @@ -В этом уроке мы сразу напишем первую программу. Мы узнаем, какие команды понадобятся для этого и какие теги нужно использовать, чтобы программа, которая выполняет код, восприняла его. Также узнаем, зачем в коде нужны комментарии. +Изучение нового языка программирования традиционно начинается с программы 'Hello, World!'. Это простая программа, которая выводит приветствие на экран и знакомит с синтаксисом и структурой нового языка. -## Как написать простую программу +```text +Hello, World! +``` + +![Hello World](./assets/hello-world.png) -Чтобы написать программу и вывести результат на экран, используют два способа: +Этой традиции уже больше сорока лет, и мы тоже начнем с нее. В первом уроке мы напишем программу `Hello, World!`. На PHP эта программа выглядит так: -* Через команду `echo` -* Через команду `print_r()` +```php + Hello, World! +print_r('Хекслет - школа программирования'); ``` +Команда остается той же, меняется только содержимое скобок. Чтобы программа понимала, что это именно текст, он заключается в кавычки. Можно использовать одинарные `'...'` или двойные `"..."`, но открывающая и закрывающая кавычки должны совпадать. -Вывод на экран выполняется с помощью специальной команды `echo`. После нее в одиночных кавычках указывается строка для вывода. В конце обязательно ставим точку с запятой. +```php + РЕЗУЛЬТАТ`. +В PHP принято использовать одинарные кавычки для строк. Если внутри строки есть апостроф, одинарные кавычки сломают синтаксис, поэтому в таких случаях используют двойные. -### Пишем программу через `print_r()` +```php + Hello, World! ``` +Для удобства мы будем показывать результат запуска строк кода так: `// => РЕЗУЛЬТАТ`. + +В простых ситуациях между `echo` и `print_r()` нет разницы — можно использовать любую команду. А там, где на экран нужно выводить не просто числа или строки, а, например, массивы, `echo` не сможет этого сделать, а `print_r()` все выведет. -В этом случае строка указывается в скобках сразу после имени функции. В конце также нужно ставить `;`. +## Значение символов + +Код состоит из команд, и каждая из них должна быть написана в определенной форме. Помимо букв, в коде важны кавычки `'` и `"`, скобки `()` и знаки препинания. Пропущенный или перепутанный знак приведет к тому, что программа не запустится. Попробуйте определить, какая ошибка допущена в каждой из строк? + +```php + [Немного о 'Hello, - World!'](https://ru.hexlet.io/blog/posts/moy-chelovek-menya-ponimaet-istoriya-frazy-hello-world-i-ee-analogov) + World!'](https://ru.hexlet.io/blog/posts/moy-chelovek-menya-ponimaet-istoriya-frazy-hello-world-i-ee-analogov?utm_source=code-basics&utm_medium=referral&utm_campaign=blog&utm_content=lesson) diff --git a/modules/10-basics/20-tags/Makefile b/modules/10-basics/15-tags/Makefile similarity index 100% rename from modules/10-basics/20-tags/Makefile rename to modules/10-basics/15-tags/Makefile diff --git a/modules/10-basics/20-tags/index.php b/modules/10-basics/15-tags/Solution.php similarity index 100% rename from modules/10-basics/20-tags/index.php rename to modules/10-basics/15-tags/Solution.php diff --git a/modules/10-basics/20-tags/SolutionTest.php b/modules/10-basics/15-tags/SolutionTest.php similarity index 68% rename from modules/10-basics/20-tags/SolutionTest.php rename to modules/10-basics/15-tags/SolutionTest.php index 88089397..8d77257f 100644 --- a/modules/10-basics/20-tags/SolutionTest.php +++ b/modules/10-basics/15-tags/SolutionTest.php @@ -2,9 +2,7 @@ namespace HexletBasics\Basics\Tags; -use PHPUnit\Framework\TestCase; - -\HexletBasics\Functions\runScript(); +use HexletBasics\Exercise\TestCase; class SolutionTest extends TestCase { @@ -12,6 +10,5 @@ public function test() { $expected = 'King in the North!'; $this->expectOutputString($expected); - require 'index.php'; } } diff --git a/modules/10-basics/20-tags/description.es.yml b/modules/10-basics/15-tags/description.es.yml similarity index 100% rename from modules/10-basics/20-tags/description.es.yml rename to modules/10-basics/15-tags/description.es.yml diff --git a/modules/10-basics/20-tags/en/EXERCISE.md b/modules/10-basics/15-tags/en/EXERCISE.md similarity index 100% rename from modules/10-basics/20-tags/en/EXERCISE.md rename to modules/10-basics/15-tags/en/EXERCISE.md diff --git a/modules/10-basics/20-tags/en/README.md b/modules/10-basics/15-tags/en/README.md similarity index 100% rename from modules/10-basics/20-tags/en/README.md rename to modules/10-basics/15-tags/en/README.md diff --git a/modules/10-basics/20-tags/en/data.yml b/modules/10-basics/15-tags/en/data.yml similarity index 100% rename from modules/10-basics/20-tags/en/data.yml rename to modules/10-basics/15-tags/en/data.yml diff --git a/modules/10-basics/20-tags/es/EXERCISE.md b/modules/10-basics/15-tags/es/EXERCISE.md similarity index 100% rename from modules/10-basics/20-tags/es/EXERCISE.md rename to modules/10-basics/15-tags/es/EXERCISE.md diff --git a/modules/10-basics/20-tags/es/README.md b/modules/10-basics/15-tags/es/README.md similarity index 100% rename from modules/10-basics/20-tags/es/README.md rename to modules/10-basics/15-tags/es/README.md diff --git a/modules/10-basics/20-tags/es/data.yml b/modules/10-basics/15-tags/es/data.yml similarity index 100% rename from modules/10-basics/20-tags/es/data.yml rename to modules/10-basics/15-tags/es/data.yml diff --git a/modules/10-basics/20-tags/ru/EXERCISE.md b/modules/10-basics/15-tags/ru/EXERCISE.md similarity index 100% rename from modules/10-basics/20-tags/ru/EXERCISE.md rename to modules/10-basics/15-tags/ru/EXERCISE.md diff --git a/modules/10-basics/20-tags/ru/README.md b/modules/10-basics/15-tags/ru/README.md similarity index 100% rename from modules/10-basics/20-tags/ru/README.md rename to modules/10-basics/15-tags/ru/README.md diff --git a/modules/10-basics/20-tags/ru/data.yml b/modules/10-basics/15-tags/ru/data.yml similarity index 100% rename from modules/10-basics/20-tags/ru/data.yml rename to modules/10-basics/15-tags/ru/data.yml diff --git a/modules/10-basics/30-comments/Makefile b/modules/10-basics/20-comments/Makefile similarity index 100% rename from modules/10-basics/30-comments/Makefile rename to modules/10-basics/20-comments/Makefile diff --git a/modules/10-basics/20-comments/Solution.php b/modules/10-basics/20-comments/Solution.php new file mode 100644 index 00000000..ba5d44e4 --- /dev/null +++ b/modules/10-basics/20-comments/Solution.php @@ -0,0 +1,3 @@ +expectOutputString(''); + $content = file_get_contents('Solution.php'); + $this->assertStringContainsString('// TODO: добавить функцию приветствия', $content); + } +} diff --git a/modules/10-basics/30-comments/description.es.yml b/modules/10-basics/20-comments/description.es.yml similarity index 100% rename from modules/10-basics/30-comments/description.es.yml rename to modules/10-basics/20-comments/description.es.yml diff --git a/modules/10-basics/30-comments/en/EXERCISE.md b/modules/10-basics/20-comments/en/EXERCISE.md similarity index 100% rename from modules/10-basics/30-comments/en/EXERCISE.md rename to modules/10-basics/20-comments/en/EXERCISE.md diff --git a/modules/10-basics/30-comments/en/README.md b/modules/10-basics/20-comments/en/README.md similarity index 100% rename from modules/10-basics/30-comments/en/README.md rename to modules/10-basics/20-comments/en/README.md diff --git a/modules/10-basics/30-comments/en/data.yml b/modules/10-basics/20-comments/en/data.yml similarity index 100% rename from modules/10-basics/30-comments/en/data.yml rename to modules/10-basics/20-comments/en/data.yml diff --git a/modules/10-basics/30-comments/es/EXERCISE.md b/modules/10-basics/20-comments/es/EXERCISE.md similarity index 100% rename from modules/10-basics/30-comments/es/EXERCISE.md rename to modules/10-basics/20-comments/es/EXERCISE.md diff --git a/modules/10-basics/30-comments/es/README.md b/modules/10-basics/20-comments/es/README.md similarity index 100% rename from modules/10-basics/30-comments/es/README.md rename to modules/10-basics/20-comments/es/README.md diff --git a/modules/10-basics/30-comments/es/data.yml b/modules/10-basics/20-comments/es/data.yml similarity index 100% rename from modules/10-basics/30-comments/es/data.yml rename to modules/10-basics/20-comments/es/data.yml diff --git a/modules/10-basics/20-comments/ru/EXERCISE.md b/modules/10-basics/20-comments/ru/EXERCISE.md new file mode 100644 index 00000000..c86cb624 --- /dev/null +++ b/modules/10-basics/20-comments/ru/EXERCISE.md @@ -0,0 +1,9 @@ +Вы пишете программу и понимаете, что одну часть нужно доделать позже. Чтобы не забыть, программисты оставляют себе заметки прямо в коде — TODO-комментарии. + +Добавьте в файл такой комментарий: + +```php +// TODO: добавить функцию приветствия +``` + +Когда вернётесь к этому месту позже, комментарий напомнит, что здесь ещё есть незавершённая работа. diff --git a/modules/10-basics/20-comments/ru/README.md b/modules/10-basics/20-comments/ru/README.md new file mode 100644 index 00000000..1805f638 --- /dev/null +++ b/modules/10-basics/20-comments/ru/README.md @@ -0,0 +1,77 @@ +Кроме самого кода, в исходных файлах часто можно встретить комментарии. Это строки, которые интерпретатор не обрабатывает. Программисты пишут их, чтобы пояснить, как работает код, отметить ошибки или напомнить, что нужно доделать. + +```php + +// END +``` + +Увидев *BEGIN* и *END*, пишите свой код между ними, остальное оставляйте без изменений. diff --git a/modules/10-basics/30-comments/ru/data.yml b/modules/10-basics/20-comments/ru/data.yml similarity index 82% rename from modules/10-basics/30-comments/ru/data.yml rename to modules/10-basics/20-comments/ru/data.yml index 64f00d08..7d4f6a51 100644 --- a/modules/10-basics/30-comments/ru/data.yml +++ b/modules/10-basics/20-comments/ru/data.yml @@ -1,6 +1,9 @@ --- name: Комментарии -tips: [] +tips: + - > + [Подробнее о + комментариях](https://www.w3schools.com/php/php_comments.asp) definitions: - name: Комментарий description: > diff --git a/modules/10-basics/30-comments/index.php b/modules/10-basics/30-comments/index.php deleted file mode 100644 index d2b98262..00000000 --- a/modules/10-basics/30-comments/index.php +++ /dev/null @@ -1,3 +0,0 @@ -expectOutputString($expected); - require 'index.php'; } } diff --git a/modules/10-basics/40-instructions/description.es.yml b/modules/10-basics/30-instructions/description.es.yml similarity index 100% rename from modules/10-basics/40-instructions/description.es.yml rename to modules/10-basics/30-instructions/description.es.yml diff --git a/modules/10-basics/40-instructions/en/EXERCISE.md b/modules/10-basics/30-instructions/en/EXERCISE.md similarity index 100% rename from modules/10-basics/40-instructions/en/EXERCISE.md rename to modules/10-basics/30-instructions/en/EXERCISE.md diff --git a/modules/10-basics/40-instructions/en/README.md b/modules/10-basics/30-instructions/en/README.md similarity index 100% rename from modules/10-basics/40-instructions/en/README.md rename to modules/10-basics/30-instructions/en/README.md diff --git a/modules/10-basics/40-instructions/en/data.yml b/modules/10-basics/30-instructions/en/data.yml similarity index 100% rename from modules/10-basics/40-instructions/en/data.yml rename to modules/10-basics/30-instructions/en/data.yml diff --git a/modules/10-basics/40-instructions/es/EXERCISE.md b/modules/10-basics/30-instructions/es/EXERCISE.md similarity index 100% rename from modules/10-basics/40-instructions/es/EXERCISE.md rename to modules/10-basics/30-instructions/es/EXERCISE.md diff --git a/modules/10-basics/40-instructions/es/README.md b/modules/10-basics/30-instructions/es/README.md similarity index 100% rename from modules/10-basics/40-instructions/es/README.md rename to modules/10-basics/30-instructions/es/README.md diff --git a/modules/10-basics/40-instructions/es/data.yml b/modules/10-basics/30-instructions/es/data.yml similarity index 100% rename from modules/10-basics/40-instructions/es/data.yml rename to modules/10-basics/30-instructions/es/data.yml diff --git a/modules/10-basics/40-instructions/ru/EXERCISE.md b/modules/10-basics/30-instructions/ru/EXERCISE.md similarity index 100% rename from modules/10-basics/40-instructions/ru/EXERCISE.md rename to modules/10-basics/30-instructions/ru/EXERCISE.md diff --git a/modules/10-basics/30-instructions/ru/README.md b/modules/10-basics/30-instructions/ru/README.md new file mode 100644 index 00000000..a0918559 --- /dev/null +++ b/modules/10-basics/30-instructions/ru/README.md @@ -0,0 +1,82 @@ +Команду `print_r('Hexlet')` мы можем назвать инструкцией, она говорит интерпретатору PHP что нужно делать. Таких инструкций может быть сколько угодно. Каждая из них выполняется после того, как закончилась предыдущая и так мы из простых элементов получаем сколь угодно большую и сложную программу. + +```text +Инструкция 1: print_r('Hello') → выполнена + ↓ +Инструкция 2: print_r('World') → выполнена + ↓ +Инструкция 3: print_r('!') → выполнена +``` + +Код на PHP — это набор инструкций, которые отделяются друг от друга символом `;`. Вот пример кода с двумя инструкциями. Эти строки говорят компьютеру вывести фразы на экран. + +```php + Mother of Dragons. Dracarys! -``` - -При запуске этого кода на экран последовательно выводятся два предложения: `Mother of Dragons. Dracarys!`. - -Инструкции можно написать последовательно друг за другом без переноса на новую строчку: - -```php - Mother of Dragons. Dracarys! -``` - -Результат на экране будет таким же. Но такой код неудобно читать, поэтому инструкции располагают друг под другом. diff --git a/modules/10-basics/45-testing/Makefile b/modules/10-basics/40-testing/Makefile similarity index 100% rename from modules/10-basics/45-testing/Makefile rename to modules/10-basics/40-testing/Makefile diff --git a/modules/10-basics/45-testing/index.php b/modules/10-basics/40-testing/Solution.php similarity index 100% rename from modules/10-basics/45-testing/index.php rename to modules/10-basics/40-testing/Solution.php diff --git a/modules/10-basics/45-testing/SolutionTest.php b/modules/10-basics/40-testing/SolutionTest.php similarity index 67% rename from modules/10-basics/45-testing/SolutionTest.php rename to modules/10-basics/40-testing/SolutionTest.php index e177af65..bbf48ac1 100644 --- a/modules/10-basics/45-testing/SolutionTest.php +++ b/modules/10-basics/40-testing/SolutionTest.php @@ -2,9 +2,7 @@ namespace HexletBasics\Basics\Testing; -use PHPUnit\Framework\TestCase; - -\HexletBasics\Functions\runScript(); +use HexletBasics\Exercise\TestCase; class SolutionTest extends TestCase { @@ -12,6 +10,5 @@ public function test() { $expected = '9780262531962'; $this->expectOutputString($expected); - require 'index.php'; } } diff --git a/modules/10-basics/45-testing/description.es.yml b/modules/10-basics/40-testing/description.es.yml similarity index 100% rename from modules/10-basics/45-testing/description.es.yml rename to modules/10-basics/40-testing/description.es.yml diff --git a/modules/10-basics/45-testing/en/EXERCISE.md b/modules/10-basics/40-testing/en/EXERCISE.md similarity index 100% rename from modules/10-basics/45-testing/en/EXERCISE.md rename to modules/10-basics/40-testing/en/EXERCISE.md diff --git a/modules/10-basics/45-testing/en/README.md b/modules/10-basics/40-testing/en/README.md similarity index 100% rename from modules/10-basics/45-testing/en/README.md rename to modules/10-basics/40-testing/en/README.md diff --git a/modules/10-basics/45-testing/en/data.yml b/modules/10-basics/40-testing/en/data.yml similarity index 100% rename from modules/10-basics/45-testing/en/data.yml rename to modules/10-basics/40-testing/en/data.yml diff --git a/modules/10-basics/45-testing/es/EXERCISE.md b/modules/10-basics/40-testing/es/EXERCISE.md similarity index 100% rename from modules/10-basics/45-testing/es/EXERCISE.md rename to modules/10-basics/40-testing/es/EXERCISE.md diff --git a/modules/10-basics/45-testing/es/README.md b/modules/10-basics/40-testing/es/README.md similarity index 100% rename from modules/10-basics/45-testing/es/README.md rename to modules/10-basics/40-testing/es/README.md diff --git a/modules/10-basics/45-testing/es/data.yml b/modules/10-basics/40-testing/es/data.yml similarity index 100% rename from modules/10-basics/45-testing/es/data.yml rename to modules/10-basics/40-testing/es/data.yml diff --git a/modules/10-basics/45-testing/ru/EXERCISE.md b/modules/10-basics/40-testing/ru/EXERCISE.md similarity index 100% rename from modules/10-basics/45-testing/ru/EXERCISE.md rename to modules/10-basics/40-testing/ru/EXERCISE.md diff --git a/modules/10-basics/40-testing/ru/README.md b/modules/10-basics/40-testing/ru/README.md new file mode 100644 index 00000000..b5a87f02 --- /dev/null +++ b/modules/10-basics/40-testing/ru/README.md @@ -0,0 +1,42 @@ +Наш сайт автоматически проверяет ваши решения. Как это работает? + +В самом простом случае проверка запускает ваш код и сравнивает вывод на экран с ожидаемым результатом. Например, если задание звучит так: «Выведите число 10 на экран», то ваш код на PHP может выглядеть так: + +```php +expectOutputString($expected); - require 'index.php'; } } diff --git a/modules/10-basics/50-syntax-errors/index.php b/modules/10-basics/50-syntax-errors/index.php deleted file mode 100644 index 46242713..00000000 --- a/modules/10-basics/50-syntax-errors/index.php +++ /dev/null @@ -1,3 +0,0 @@ - + [Виды ошибок в + PHP](https://www.php.net/manual/ru/language.errors.basics.php) definitions: - name: Синтаксическая ошибка description: нарушение грамматических правил языка программирования. diff --git a/modules/20-arithmetics/20-basic/index.php b/modules/20-arithmetics/20-basic/Solution.php similarity index 100% rename from modules/20-arithmetics/20-basic/index.php rename to modules/20-arithmetics/20-basic/Solution.php diff --git a/modules/20-arithmetics/20-basic/SolutionTest.php b/modules/20-arithmetics/20-basic/SolutionTest.php index e393e5eb..a246685b 100644 --- a/modules/20-arithmetics/20-basic/SolutionTest.php +++ b/modules/20-arithmetics/20-basic/SolutionTest.php @@ -2,9 +2,7 @@ namespace HexletBasics\Arithmetics\Basics; -use PHPUnit\Framework\TestCase; - -\HexletBasics\Functions\runScript(); +use HexletBasics\Exercise\TestCase; class SolutionTest extends TestCase { @@ -12,6 +10,5 @@ public function test() { $expected = '9'; $this->expectOutputString($expected); - require 'index.php'; } } diff --git a/modules/20-arithmetics/20-basic/ru/EXERCISE.md b/modules/20-arithmetics/20-basic/ru/EXERCISE.md index 5dfef630..a8f46734 100644 --- a/modules/20-arithmetics/20-basic/ru/EXERCISE.md +++ b/modules/20-arithmetics/20-basic/ru/EXERCISE.md @@ -1 +1 @@ -Выведите на экран результат деления числа `81` на `9`. +Вы зашли в оптовый магазин и увидели упаковку из 9 батареек за 81 рубль. В обычном магазине одна батарейка стоит 12 рублей. Рассчитайте и выведите цену одной батарейки в оптовой упаковке, чтобы понять, где выгоднее покупать. diff --git a/modules/20-arithmetics/20-basic/ru/README.md b/modules/20-arithmetics/20-basic/ru/README.md index 046cd027..88e49203 100644 --- a/modules/20-arithmetics/20-basic/ru/README.md +++ b/modules/20-arithmetics/20-basic/ru/README.md @@ -1,8 +1,12 @@ -На базовом уровне компьютеры оперируют только числами. Для сложения двух чисел в математике мы пишем, например, `3 + 4`. В программировании — то же самое. В этом уроке разберем, как проводить арифметические операции в коде. +На базовом уровне компьютеры работают только с числами. Даже если вы пишете сложное приложение на современном языке программирования, внутри него всегда происходят многочисленные вычисления: сложение, вычитание, деление и т.д. -## Арифметика в программировании +![Счетные палочки](./assets/arithmetics.png) -Рассмотрим пример программы, которая складывает два числа: +К счастью, чтобы начать программировать, достаточно знать обычную школьную арифметику. С нее мы и начнем. + +## Сложение в PHP + +В математике для сложения мы пишем 3 + 4. В PHP все точно так же: ```php 4 +print_r(3 ** 2); // => 9 +``` + +## Числа с плавающей точкой -Нам нужно попросить интерпретатор сложить `3 + 4` и дать команду сделать что-то с результатом. Например, вывести его на экран: +Помимо целых чисел в PHP есть числа с плавающей точкой, которые используются для работы с дробями. Такие числа записываются через точку: ```php 7 +print_r(3.5 + 1.2); // => 4.7 +print_r(10 / 4); // => 2.5 ``` -Кроме сложения доступны следующие операции: +Иногда мы используем их сами, когда нужно работать именно с дробными значениями, например при подсчете среднего или при работе с деньгами и измерениями. Но числа с плавающей точкой могут появляться и сами, например, в результате операции деления `/`: -* `*` — умножение -* `/` — деление -* `-` — вычитание -* `%` — [остаток от деления](https://ru.wikipedia.org/wiki/Деление_с_остатком) -* `**` — возведение в степень +```php + 4 +print_r(7 / 2); // => 3.5 +``` + +Если результат деления получился целым, PHP оставляет его целым числом, а дробный результат автоматически становится числом с плавающей точкой. + +Причина выделения этого в отдельный тип: компьютеру нужно хранить целые значения и дробные значения по-разному. Для целых он выделяет одни структуры в памяти, для дробных выделяет другие. Поэтому в PHP, как и в других языках программирования, существует два разных вида чисел: int (целые) и float (с плавающей точкой). + +На базовом уровне достаточно помнить: целые числа нужны, когда нет дробей, а числа с плавающей точкой нужны, когда дроби есть. Подробнее мы разберемся с ними дальше по курсу. + +## Что такое остаток от деления (`%`) + +Эта операция называется **взятие остатка от деления**. Она показывает, **что «остается»**, когда одно число делится на другое *не полностью*. Пример: + +```php + 1 +``` + +Почему результат равен 1? + +- 7 делится на 3 дважды: 3 * 2 = 6 +- До 7 остается 1, и это является остатком. + +Другие примеры: + +```php + 2 (10 делится на 4 дважды: 4 * 2 = 8, остаток 2) +print_r(15 % 5); // => 0 (делится без остатка) +``` + +Операция % часто используется в программировании, например: + +- чтобы проверить, делится ли число нацело (если остаток 0) +- чтобы выполнять циклические действия, например, поведение по четным/нечетным индексам + +Мы еще неоднократно встретим % в задачах и разберем его применение на практике. + +## Оформление арифметических выражений + +С точки зрения PHP между `3+4` и `3 + 4` нет разницы. Интерпретатор поймет оба варианта одинаково и в обоих случаях выполнит сложение. Разница только в оформлении кода. В программировании принято ставить пробелы вокруг арифметических операторов, потому что так выражения проще читать: + +```php + Если в редакторе есть запись `// BEGIN` и `// END`, то код нужно писать между этими строчками. +definitions: + - name: Инструкция + description: > + наименьшая автономная часть языка программирования; команда или набор + команд. Программа обычно представляет собой последовательность инструкций. diff --git a/modules/20-arithmetics/25-operator/index.php b/modules/20-arithmetics/25-operator/Solution.php similarity index 63% rename from modules/20-arithmetics/25-operator/index.php rename to modules/20-arithmetics/25-operator/Solution.php index 790c3ea2..d3acae0e 100644 --- a/modules/20-arithmetics/25-operator/index.php +++ b/modules/20-arithmetics/25-operator/Solution.php @@ -2,4 +2,5 @@ // BEGIN print_r(6 - -81); +print_r((6 - -81) / 3); // END diff --git a/modules/20-arithmetics/25-operator/SolutionTest.php b/modules/20-arithmetics/25-operator/SolutionTest.php index 38121b48..a4019612 100644 --- a/modules/20-arithmetics/25-operator/SolutionTest.php +++ b/modules/20-arithmetics/25-operator/SolutionTest.php @@ -2,16 +2,13 @@ namespace HexletBasics\Arithmetics\Operator; -use PHPUnit\Framework\TestCase; - -\HexletBasics\Functions\runScript(); +use HexletBasics\Exercise\TestCase; class SolutionTest extends TestCase { public function test() { - $expected = '87'; + $expected = '8729'; $this->expectOutputString($expected); - require 'index.php'; } } diff --git a/modules/20-arithmetics/25-operator/ru/EXERCISE.md b/modules/20-arithmetics/25-operator/ru/EXERCISE.md index 003cfc9c..ca7ca8a9 100644 --- a/modules/20-arithmetics/25-operator/ru/EXERCISE.md +++ b/modules/20-arithmetics/25-operator/ru/EXERCISE.md @@ -1 +1,8 @@ -Напишите программу, которая посчитает разность между числами `6` и `-81` и выведет ответ на экран. +Подводная лодка находится на глубине -81 м. Палуба спасательного корабля расположена на высоте +6 м над уровнем воды. + +Рассчитайте и выведите на экран: + +1. Полное расстояние всплытия в метрах. +2. Время подъема в минутах — лодка поднимается со скоростью 3 м/мин. + +Обратите внимание, что результаты выведутся «слепленными» в одну строчку без пробела. Мы научимся решать эту проблему в будущих уроках. diff --git a/modules/20-arithmetics/25-operator/ru/README.md b/modules/20-arithmetics/25-operator/ru/README.md index b7b41c59..dfc9d30b 100644 --- a/modules/20-arithmetics/25-operator/ru/README.md +++ b/modules/20-arithmetics/25-operator/ru/README.md @@ -1,8 +1,9 @@ -Знак операции, например, `+`, называют **оператором**. Операторы обычно представлены одним или несколькими символами, реже — словом. Обычно они соответствуют математическим операциям. +В математике и программировании мы часто используем знаки операций, такие как `+`, `-`, `*` и другие. В программировании такие знаки называются операторами. -Операторы выполняют операции над определенными значениями, которые называются **операндами**. +- Оператор представляет собой символ или слово, которое обозначает действие. +- Операнды являются значениями, к которым применяется оператор. -Рассмотрим пример: +Пример: ```php -3 ``` -Выше пример применения унарной операции к числу `3`. Оператор `-` перед тройкой говорит интерпретатору взять число `3` и найти противоположное, то есть `-3`. Это может сбить с толку, потому что `-3` — это одновременно и число, и оператор с операндом. Но у языков программирования такая структура: +В этом случае `-` является унарным оператором, а `3` является операндом. Интерпретатор получает команду: «возьми число 3 и измени его знак». + +Оператор `-` может использоваться по-разному. Когда он стоит **между двумя числами**, это операция вычитания: + +```php + 3 +print_r(10 - 7); // => 3 +``` + +Здесь `-` берет первое число и вычитает из него второе. + +Эта разница особенно заметна при работе с отрицательными числами. Например: ```php 1 +// минус на минус дает плюс +print_r(5 - -2); // => 7 ``` +Сначала мы видим операцию вычитания: `5 - (...)`. Но справа стоит унарный минус `-2`, который превращает `2` в отрицательное число. В итоге получается: `5 - (-2) = 7`. + +Таким образом, значение `-` зависит от контекста: если рядом стоит другое число, это вычитание, иначе это смена знака числа. + То же самое касается и плюса: ```php 3 +print_r(+3); // => 3 print_r(1 + +3); // => 4 ``` + +Главное, что здесь нужно помнить: поведение и даже сама запись здесь полностью соответствует тому, как мы делали это в школе. + +## Ошибки при вычислениях и парсинге + +Если воспринимать `-3` как единое число, можно не заметить, что `-` является отдельным оператором со своим приоритетом. Например: + +```php +- + Всегда отбивайте арифметические операторы пробелами от своих операндов – это + хороший стиль программирования. - | [Операторы в PHP](https://www.php.net/manual/ru/language.operators.php) definitions: - name: Арифметическая операция description: сложение, вычитание, умножение и деление. + - name: Оператор + description: >- + специальный символ, создающий операцию. Например, `+` создает операцию + сложения. + - name: Операнд + description: 'объект, который участвует в операции. `3 * 6`: здесь 3 и 6 — операнды.' - name: Унарная операция description: >- операция с одним операндом. Например, `-3` — унарная операция для diff --git a/modules/20-arithmetics/27-commutativity/Solution.php b/modules/20-arithmetics/27-commutativity/Solution.php new file mode 100644 index 00000000..d516da70 --- /dev/null +++ b/modules/20-arithmetics/27-commutativity/Solution.php @@ -0,0 +1,6 @@ +expectOutputString($expected); - require 'index.php'; } } diff --git a/modules/20-arithmetics/27-commutativity/index.php b/modules/20-arithmetics/27-commutativity/index.php deleted file mode 100644 index e38d8b77..00000000 --- a/modules/20-arithmetics/27-commutativity/index.php +++ /dev/null @@ -1,6 +0,0 @@ - 5 +print_r(2 + 3); // => 5 +``` + +Одинаковый результат подтверждает, что операция коммутативна. + +```text +2 + 3 = 5 3 + 2 = 5 +└──────────┬─────────┘ + одинаковый результат + +2 - 3 = -1 3 - 2 = 1 +└──────────┬─────────┘ + разный результат +``` + +## Некоммутативные операции + +Но не все операции обладают таким свойством. Например, вычитание является некоммутативной операцией: + +```php + -1 +print_r(3 - 2); // => 1 +``` + +Перестановка операндов дает другой результат. + +## В программировании все то же самое + +Коммутативность в программировании работает точно так же, как в арифметике. PHP строго следует математическим правилам. + +Другие некоммутативные операции: + +- Деление: _8 / 2 ≠ 2 / 8_ +- Возведение в степень: _2 **3 ≠ 3** 2_ + +Примеры в коде: + +```php + + [Подробнее про + коммутативность](https://ru.wikipedia.org/wiki/Коммутативность) definitions: - name: Коммутативность description: > diff --git a/modules/20-arithmetics/30-composition/Solution.php b/modules/20-arithmetics/30-composition/Solution.php new file mode 100644 index 00000000..9ce7c99c --- /dev/null +++ b/modules/20-arithmetics/30-composition/Solution.php @@ -0,0 +1,5 @@ +expectOutputString($expected); - require 'index.php'; } } diff --git a/modules/20-arithmetics/30-composition/index.php b/modules/20-arithmetics/30-composition/index.php deleted file mode 100644 index 49c5a8d6..00000000 --- a/modules/20-arithmetics/30-composition/index.php +++ /dev/null @@ -1,5 +0,0 @@ - 4 +``` + +Сначала выполняется умножение: `10 - 6 = 4`. + +Если же в выражении есть отрицательные числа, унарный минус применяется уже после возведения в степень: + +```php + -4, два в степени два, затем применяется минус +print_r(-2 * 5); // => -10, минус два умноженное на пять +print_r(4 + -2); // => 2 +print_r(6 - -2); // => 8 +``` + +Во всех примерах, кроме первого, сначала вычисляется унарный минус (`-2`), и затем проводятся остальные операции. + +Рассмотрим подробнее последний пример: ```php 400 +print_r(6 - -2); // => 8 ``` -Операции можно соединять друг с другом. Это дает возможность вычислять более сложные составные выражения. Такое свойство операций называется **композицией**. +Сначала вычисляется унарный минус (`-2`), и затем операция превращается в `6 - (-2)`, что дает `8`. Это то же самое, что: -Композиция арифметических операций в программировании аналогична композиции из школьной программы. Она распространяется на все операции, а не только на арифметические. +```php + 8 +``` -Чтобы представить, как происходят вычисления внутри интерпретатора, разберем пример: `2 * 4 * 5 * 10`. +## Что нужно запомнить -1. Сначала вычисляется `2 * 4` и получается выражение `8 * 5 * 10` -2. Затем `8 * 5`. В итоге имеем `40 * 10` -3. В конце происходит последнее умножение, и получается результат `400` +- Выражения могут состоять из нескольких операций. +- PHP вычисляет их поэтапно: слева направо, соблюдая приоритет операций. +- Скобки можно использовать, чтобы явно указать порядок вычислений. diff --git a/modules/20-arithmetics/30-composition/ru/data.yml b/modules/20-arithmetics/30-composition/ru/data.yml index bcab44d9..72350aa7 100644 --- a/modules/20-arithmetics/30-composition/ru/data.yml +++ b/modules/20-arithmetics/30-composition/ru/data.yml @@ -1,3 +1,7 @@ --- name: Композиция операций tips: [] +definitions: + - name: Композиция + description: | + метод объединения нескольких простых операций в одну сложную. diff --git a/modules/20-arithmetics/40-priority/Solution.php b/modules/20-arithmetics/40-priority/Solution.php new file mode 100644 index 00000000..2a2ae3b5 --- /dev/null +++ b/modules/20-arithmetics/40-priority/Solution.php @@ -0,0 +1,5 @@ +expectOutputString($expected); - require 'index.php'; } } diff --git a/modules/20-arithmetics/40-priority/index.php b/modules/20-arithmetics/40-priority/index.php deleted file mode 100644 index 3ba8600b..00000000 --- a/modules/20-arithmetics/40-priority/index.php +++ /dev/null @@ -1,5 +0,0 @@ - 6 ``` -Интерпретатор производит арифметические вычисления в правильном порядке: сначала деление и умножение, потом сложение и вычитание, а приоритет возведения в степень выше всех остальных арифметических операций: `2 ** 3 * 2` вычислится в `16`. +Результат равен 6, а не 8. Это объясняется понятием приоритета операций в математике и программировании. Он определяет порядок, в котором выполняются действия: + +- Умножение и деление выполняются раньше сложения и вычитания. +- Возведение в степень (**) имеет еще более высокий приоритет. + +```text +Приоритет операций (от высокого к низкому): + + ** возведение в степень + ↓ + * / % умножение, деление, остаток + ↓ + + - сложение, вычитание +``` + +Например: + +```php + 16, потому что сначала 2 ** 3 = 8, затем 8 * 2 = 16 +``` + +Если рядом идут операции с одинаковым приоритетом, они выполняются слева направо: + +```php + 12, потому что сначала 8 / 2 = 4, затем 4 * 3 = 12 +``` + +## Управление порядком действий + +Иногда нужно изменить порядок вычислений. Для этого используются круглые скобки. Они позволяют задать, какие действия нужно выполнить в первую очередь: + +```php + 8 +``` -Иногда вычисления должны происходить в другом порядке. В этом случае приоритет задают круглыми скобками, например: `(2 + 2) * 2`. Скобки можно ставить вокруг любой операции. Они могут вкладываться друг в друга сколько угодно раз. Вот пара примеров: +Скобки можно ставить вокруг любой части выражения и вкладывать их друг в друга: ```php 9 +print_r(3 ** (4 - 2)); // => 9 print_r(7 * 3 + (4 / 2) - (8 + (2 - 1))); // => 14 ``` -В этом случае главное закрывать скобки в правильном порядке. Это часто становится причиной ошибок не только у новичков, но и у опытных программистов. Для удобства можно сразу ставить открывающую и закрывающую скобки, а потом писать внутреннюю часть. +Главное правило: всегда закрывайте скобки. Непарные скобки вызывают ошибки: и новички, и опытные программисты иногда забывают про закрывающую скобку. -Сейчас большинство редакторов кода делают это автоматически. Например, мы ставим открывающую скобку, а он автоматически ставит закрывающую. Это касается и других парных символов, например, кавычек. О них — в будущих уроках. +> Пишите скобки сразу парой. Например, вводите () и потом заполняйте внутреннюю часть. Большинство редакторов кода (в том числе наш) автоматически добавляют закрывающую скобку, как только вы пишете открывающую. Это касается и других парных символов, например, кавычек. + +## Повышаем читаемость + +Иногда выражение работает правильно, но выглядит запутанно. В таких случаях скобки можно добавить просто для наглядности: они не изменят результат, но улучшат восприятие. + +```php + 10.5 + +// Стало +print_r(((8 / 2) + 5) - (-3 / 2)); // => 10.5 +``` -Иногда выражение сложно воспринимать визуально. Тогда можно расставить скобки, не повлияв на приоритет. Код пишется для людей, а машины будут только исполнять его. Для машин код — или корректный, или не корректный. Для них нет «более» понятного или «менее» понятного кода. Явная расстановка приоритетов упрощает чтение кода другими разработчиками. +Программы пишут люди, и читают их тоже люди. Компьютеру все равно, насколько понятно написан код: достаточно, чтобы он был синтаксически правильным. Для человека понятный и аккуратный код является залогом удобства, особенно при работе в команде или разборе ошибок. diff --git a/modules/20-arithmetics/40-priority/ru/data.yml b/modules/20-arithmetics/40-priority/ru/data.yml index 84df3bea..f716ee70 100644 --- a/modules/20-arithmetics/40-priority/ru/data.yml +++ b/modules/20-arithmetics/40-priority/ru/data.yml @@ -4,3 +4,8 @@ tips: - > [Приоритет операторов](https://www.php.net/manual/ru/language.operators.precedence.php) +definitions: + - name: Выражение + description: > + последовательность действий над данными, приводящая к каком-то результату, + который можно использовать. diff --git a/modules/30-variables/14-errors/Makefile b/modules/20-arithmetics/43-float/Makefile similarity index 100% rename from modules/30-variables/14-errors/Makefile rename to modules/20-arithmetics/43-float/Makefile diff --git a/modules/20-arithmetics/43-float/Solution.php b/modules/20-arithmetics/43-float/Solution.php new file mode 100644 index 00000000..9dcfa518 --- /dev/null +++ b/modules/20-arithmetics/43-float/Solution.php @@ -0,0 +1,5 @@ +expectOutputString($expected); + } +} diff --git a/modules/20-arithmetics/43-float/description.es.yml b/modules/20-arithmetics/43-float/description.es.yml new file mode 100644 index 00000000..cc64fd90 --- /dev/null +++ b/modules/20-arithmetics/43-float/description.es.yml @@ -0,0 +1,73 @@ +--- + +name: Números de punto flotante +theory: | + En matemáticas hay diferentes tipos de números. Por ejemplo: + + - Naturales: números enteros positivos: 1, 2, 3, etc. + - Racionales: números fraccionarios que se pueden representar como una división, por ejemplo: 0.5, 1.75, 3.14. + + Desde el punto de vista de las matemáticas, todo es simple. Pero desde el punto de vista de la computadora, entre estos tipos de números hay un verdadero abismo. Intenta resolver mentalmente: ¿cuánto es `0.2` + `0.1`? Obviamente, `0.3`. PHP mostrará lo mismo al imprimir: + + ```php + 0.3 + ``` + + Todo parece estar bien. Pero hagamos una comprobación: restemos 0.3 de esta suma. Matemáticamente, el resultado debería ser exactamente cero. Esto es lo que dice PHP: + + ```php + 5.5511151231258E-17 + ``` + + En lugar de cero obtenemos una pequeña «cola»: un número en notación exponencial, aproximadamente igual a 0.000000000000000055. La cuestión es que internamente PHP no almacena exactamente 0.3, sino una aproximación de 0.30000000000000004. Al imprimir, el número se redondea a 14 dígitos significativos, por lo que el error no es visible. Pero no desaparece de los cálculos. + + ## ¿Por qué sucede esto? + + Este comportamiento es típico de Python, JavaScript y la mayoría de los demás lenguajes de programación. + + La razón está en el funcionamiento de la computadora. Una computadora trabaja con memoria limitada, mientras que los números racionales son infinitamente precisos. Entre 0.1 y 0.2 se pueden colocar infinitos números. Pero la computadora no puede almacenar el infinito. Aproxima el número, tratando de ajustarlo a la cantidad de bits disponible. + + Estos valores aproximados se llaman números de punto flotante (floating point numbers). Su almacenamiento y los cálculos con ellos siguen reglas estrictas descritas en un estándar especial, IEEE 754, en el que se basan la mayoría de los lenguajes de programación. + + ## Cuándo aparecen estos números + + Los números de punto flotante aparecen en los programas con más frecuencia de lo que parece. Estos son los casos principales: + + - Cuando escribes explícitamente un número fraccionario, por ejemplo 0.1, 2.5, 3.14. + - Cuando realizas una división con resultado fraccionario: + + ```php + 0.5 + print_r(2 / 3); // => 0.66666666666667 + ``` + + Incluso si el resultado parece «bonito», internamente sigue representado como un valor aproximado. Algunas fracciones, como 1 / 3, no pueden representarse exactamente en el sistema binario, por lo que su precisión siempre es limitada. + + ## Dónde es crítico y cómo se trabaja con esto + + Normalmente, un pequeño error no molesta. Pero en cálculos financieros, tareas científicas y de ingeniería, así como en la comparación exacta de resultados, puede convertirse en un problema. En los programas reales, el dinero a menudo se almacena en unidades mínimas, por ejemplo en centavos, es decir, se usan números enteros en lugar de fraccionarios. En otros casos, el resultado se redondea a la cantidad necesaria de dígitos, los números se comparan con un margen de error aceptable o se usan tipos de datos y bibliotecas especiales para cálculos exactos. + + ## Qué hay que recordar + + Las operaciones con números de punto flotante no siempre son exactas, y esto es normal. PHP redondea los números al imprimir, por lo que el error no siempre es visible en la pantalla, pero está presente en los cálculos. La precisión se puede controlar, por ejemplo, mediante el redondeo o la comparación de números con un margen de error dado. Al trabajar con dinero, mediciones precisas o cálculos científicos, es mejor usar tipos de datos especiales que proporcionen control sobre la precisión. + +instructions: | + Estás pagando dos productos en una tienda en línea: el primero cuesta 0.1 rublos, el segundo — 0.2 rublos. El programa de caja debe verificar la precisión de los cálculos: restar los 0.3 rublos esperados del total. + + Calcula e imprime esta diferencia. Esperas ver cero, pero PHP mostrará algo interesante. + +tips: + - > + [Lo que todo informático debe saber sobre la aritmética de punto + flotante](https://www.validlab.com/goldberg/paper.pdf) + +definitions: + - name: Número racional + description: | + un número que se puede representar como una fracción común. diff --git a/modules/20-arithmetics/43-float/en/EXERCISE.md b/modules/20-arithmetics/43-float/en/EXERCISE.md new file mode 100644 index 00000000..d40ef1f6 --- /dev/null +++ b/modules/20-arithmetics/43-float/en/EXERCISE.md @@ -0,0 +1,3 @@ +You are paying for two items in an online store: the first one costs 0.1 rubles, the second one costs 0.2 rubles. The checkout program must verify the accuracy of the calculations: subtract the expected 0.3 rubles from the total. + +Calculate and print this difference. You expect to see zero — but PHP will show something interesting. diff --git a/modules/20-arithmetics/43-float/en/README.md b/modules/20-arithmetics/43-float/en/README.md new file mode 100644 index 00000000..b0292b4f --- /dev/null +++ b/modules/20-arithmetics/43-float/en/README.md @@ -0,0 +1,54 @@ +In mathematics there are different types of numbers. For example: + +- Natural numbers: positive integers: 1, 2, 3, and so on. +- Rational numbers: fractional numbers that can be represented as a division, for example: 0.5, 1.75, 3.14. + +From the point of view of mathematics, everything is simple. But from the computer's point of view, there is a real chasm between these types of numbers. Try to solve mentally: what is `0.2` + `0.1`? Obviously, `0.3`. PHP will show the same when printing: + +```php + 0.3 +``` + +Everything seems fine. But let's check: subtract 0.3 from this sum. Mathematically, the result should be exactly zero. Here is what PHP says: + +```php + 5.5511151231258E-17 +``` + +Instead of zero, we get a tiny "tail" — a number in exponential notation, approximately equal to 0.000000000000000055. The thing is that internally PHP stores not exactly 0.3, but an approximation of 0.30000000000000004. When printing, the number is rounded to 14 significant digits, so the error is not visible. But it does not disappear from the calculations themselves. + +## Why does this happen? + +This behavior is typical for Python, JavaScript, and most other programming languages. + +The reason lies in how computers work. A computer operates with limited memory, while rational numbers are infinitely precise. Infinitely many other numbers can fit between 0.1 and 0.2. But a computer cannot store infinity. It approximates the number, trying to fit it into the available number of bits. + +Such approximate values are called floating point numbers. Their storage and calculations follow strict rules described in a special standard, IEEE 754, which most programming languages rely on. + +## When such numbers appear + +Floating point numbers appear in programs more often than it may seem. Here are the main cases: + +- When you explicitly write a fractional number, for example 0.1, 2.5, 3.14. +- When you perform division with a fractional result: + +```php + 0.5 +print_r(2 / 3); // => 0.66666666666667 +``` + +Even if the result looks "nice", internally it is still represented as an approximate value. Some fractions, such as 1 / 3, cannot be exactly represented in the binary system at all, so their precision is always limited. + +## Where it is critical and how to deal with it + +Usually a small error does not interfere. But in financial calculations, scientific and engineering tasks, as well as in exact comparison of results, it can become a problem. In real programs, money is often stored in minimal units, such as cents, that is, integers are used instead of fractions. In other cases, the result is rounded to the required number of digits, numbers are compared with an acceptable error margin, or special data types and libraries for exact calculations are used. + +## What to remember + +Operations with floating point numbers are not always exact, and this is normal. PHP rounds numbers when printing, so the error is not always visible on the screen — but it is present in the calculations. Precision can be controlled, for example, by rounding or comparing numbers with a given error margin. When working with money, precise measurements, or scientific calculations, it is better to use special data types that provide control over precision. diff --git a/modules/20-arithmetics/43-float/en/data.yml b/modules/20-arithmetics/43-float/en/data.yml new file mode 100644 index 00000000..397451b0 --- /dev/null +++ b/modules/20-arithmetics/43-float/en/data.yml @@ -0,0 +1,10 @@ +--- +name: Floating point numbers +tips: + - > + [What every computer scientist should know about floating-point + arithmetic](https://www.validlab.com/goldberg/paper.pdf) +definitions: + - name: Rational number + description: | + a number that can be represented as a common fraction. diff --git a/modules/20-arithmetics/43-float/es/EXERCISE.md b/modules/20-arithmetics/43-float/es/EXERCISE.md new file mode 100644 index 00000000..a73e3298 --- /dev/null +++ b/modules/20-arithmetics/43-float/es/EXERCISE.md @@ -0,0 +1,3 @@ +Estás pagando dos productos en una tienda en línea: el primero cuesta 0.1 rublos, el segundo — 0.2 rublos. El programa de caja debe verificar la precisión de los cálculos: restar los 0.3 rublos esperados del total. + +Calcula e imprime esta diferencia. Esperas ver cero, pero PHP mostrará algo interesante. diff --git a/modules/20-arithmetics/43-float/es/README.md b/modules/20-arithmetics/43-float/es/README.md new file mode 100644 index 00000000..987069ea --- /dev/null +++ b/modules/20-arithmetics/43-float/es/README.md @@ -0,0 +1,54 @@ +En matemáticas hay diferentes tipos de números. Por ejemplo: + +- Naturales: números enteros positivos: 1, 2, 3, etc. +- Racionales: números fraccionarios que se pueden representar como una división, por ejemplo: 0.5, 1.75, 3.14. + +Desde el punto de vista de las matemáticas, todo es simple. Pero desde el punto de vista de la computadora, entre estos tipos de números hay un verdadero abismo. Intenta resolver mentalmente: ¿cuánto es `0.2` + `0.1`? Obviamente, `0.3`. PHP mostrará lo mismo al imprimir: + +```php + 0.3 +``` + +Todo parece estar bien. Pero hagamos una comprobación: restemos 0.3 de esta suma. Matemáticamente, el resultado debería ser exactamente cero. Esto es lo que dice PHP: + +```php + 5.5511151231258E-17 +``` + +En lugar de cero obtenemos una pequeña «cola»: un número en notación exponencial, aproximadamente igual a 0.000000000000000055. La cuestión es que internamente PHP no almacena exactamente 0.3, sino una aproximación de 0.30000000000000004. Al imprimir, el número se redondea a 14 dígitos significativos, por lo que el error no es visible. Pero no desaparece de los cálculos. + +## ¿Por qué sucede esto? + +Este comportamiento es típico de Python, JavaScript y la mayoría de los demás lenguajes de programación. + +La razón está en el funcionamiento de la computadora. Una computadora trabaja con memoria limitada, mientras que los números racionales son infinitamente precisos. Entre 0.1 y 0.2 se pueden colocar infinitos números. Pero la computadora no puede almacenar el infinito. Aproxima el número, tratando de ajustarlo a la cantidad de bits disponible. + +Estos valores aproximados se llaman números de punto flotante (floating point numbers). Su almacenamiento y los cálculos con ellos siguen reglas estrictas descritas en un estándar especial, IEEE 754, en el que se basan la mayoría de los lenguajes de programación. + +## Cuándo aparecen estos números + +Los números de punto flotante aparecen en los programas con más frecuencia de lo que parece. Estos son los casos principales: + +- Cuando escribes explícitamente un número fraccionario, por ejemplo 0.1, 2.5, 3.14. +- Cuando realizas una división con resultado fraccionario: + +```php + 0.5 +print_r(2 / 3); // => 0.66666666666667 +``` + +Incluso si el resultado parece «bonito», internamente sigue representado como un valor aproximado. Algunas fracciones, como 1 / 3, no pueden representarse exactamente en el sistema binario, por lo que su precisión siempre es limitada. + +## Dónde es crítico y cómo se trabaja con esto + +Normalmente, un pequeño error no molesta. Pero en cálculos financieros, tareas científicas y de ingeniería, así como en la comparación exacta de resultados, puede convertirse en un problema. En los programas reales, el dinero a menudo se almacena en unidades mínimas, por ejemplo en centavos, es decir, se usan números enteros en lugar de fraccionarios. En otros casos, el resultado se redondea a la cantidad necesaria de dígitos, los números se comparan con un margen de error aceptable o se usan tipos de datos y bibliotecas especiales para cálculos exactos. + +## Qué hay que recordar + +Las operaciones con números de punto flotante no siempre son exactas, y esto es normal. PHP redondea los números al imprimir, por lo que el error no siempre es visible en la pantalla, pero está presente en los cálculos. La precisión se puede controlar, por ejemplo, mediante el redondeo o la comparación de números con un margen de error dado. Al trabajar con dinero, mediciones precisas o cálculos científicos, es mejor usar tipos de datos especiales que proporcionen control sobre la precisión. diff --git a/modules/20-arithmetics/43-float/es/data.yml b/modules/20-arithmetics/43-float/es/data.yml new file mode 100644 index 00000000..a54d5e6e --- /dev/null +++ b/modules/20-arithmetics/43-float/es/data.yml @@ -0,0 +1,10 @@ +--- +name: Números de punto flotante +tips: + - > + [Lo que todo informático debe saber sobre la aritmética de punto + flotante](https://www.validlab.com/goldberg/paper.pdf) +definitions: + - name: Número racional + description: | + un número que se puede representar como una fracción común. diff --git a/modules/20-arithmetics/43-float/ru/EXERCISE.md b/modules/20-arithmetics/43-float/ru/EXERCISE.md new file mode 100644 index 00000000..21d2431a --- /dev/null +++ b/modules/20-arithmetics/43-float/ru/EXERCISE.md @@ -0,0 +1,3 @@ +Вы оплачиваете два товара в интернет-магазине: первый стоит 0.1 рубля, второй — 0.2 рубля. Кассовая программа должна проверить точность расчетов: вычесть из итоговой суммы ожидаемые 0.3 рубля. + +Рассчитайте и выведите эту разницу. Ожидаете увидеть ноль — но PHP выдаст кое-что интересное. diff --git a/modules/20-arithmetics/43-float/ru/README.md b/modules/20-arithmetics/43-float/ru/README.md new file mode 100644 index 00000000..9e268c21 --- /dev/null +++ b/modules/20-arithmetics/43-float/ru/README.md @@ -0,0 +1,63 @@ +В математике есть разные типы чисел. Например: + +- Натуральные: целые положительные числа: 1, 2, 3 и т.д. +- Рациональные: дробные числа, которые можно представить в виде деления, например: 0.5, 1.75, 3.14. + +С точки зрения математики все просто. Но с точки зрения компьютера между этими типами чисел лежит настоящая пропасть. Попробуйте мысленно решить: сколько будет `0.2` + `0.1`? Очевидно, `0.3`. PHP при выводе покажет то же самое: + +```php + 0.3 +``` + +Кажется, все в порядке. Но проведем проверку: вычтем из этой суммы 0.3. Математически должен получиться ровно ноль. А вот что скажет PHP: + +```php + 5.5511151231258E-17 +``` + +Вместо нуля мы получаем крошечный «хвостик» — число в экспоненциальной записи, равное примерно 0.000000000000000055. Дело в том, что внутри PHP хранит не ровно 0.3, а приближение 0.30000000000000004. При выводе число округляется до 14 значащих цифр, поэтому погрешность не видна. Но в самих вычислениях она никуда не девается. + +```text +Ожидание: 0.1 + 0.2 → 0.3 +Реальность: 0.1 + 0.2 → 0.30000000000000004 + └── погрешность хранения +Проверка: 0.1 + 0.2 - 0.3 → 5.5511151231258E-17 (а не 0) +``` + +## Почему так происходит? + +Такое поведение характерно для Python, JavaScript и большинства других языков программирования. + +Причина в устройстве компьютера. Компьютер работает с ограниченной памятью, тогда как рациональные числа бесконечно точны. Между 0.1 и 0.2 можно поместить бесконечно много других чисел. Но компьютер не может хранить бесконечность. Он приближает число, стараясь уместить его в доступное количество бит. + +Такие приближенные значения называются числами с плавающей точкой (floating point numbers). Хранение и вычисления с ними подчиняются строгим правилам, описанным в специальном стандарте IEEE 754, на который ориентируются большинство языков программирования. + +## Когда появляются такие числа + +Числа с плавающей точкой появляются в программах чаще, чем может показаться. Вот основные случаи: + +- Когда вы явно пишете дробное число, например 0.1, 2.5, 3.14. +- Когда выполняете деление с дробным результатом: + +```php + 0.5 +print_r(2 / 3); // => 0.66666666666667 +``` + +Даже если результат кажется «красивым», внутри он все равно представлен в виде приближенного значения. Некоторые дроби, такие как 1 / 3, вообще не могут быть точно представлены в двоичной системе, поэтому их точность всегда ограничена. + +## Где это критично и как с этим работают + +Обычно небольшая погрешность не мешает. Но в финансовых расчетах, научных и инженерных задачах, а также при точном сравнении результатов она может стать проблемой. Например, ошибка в доли копейки способна дать неправильную итоговую сумму, а длинная цепочка вычислений может постепенно накапливать неточность. + +В реальных программах с этим работают по-разному. Деньги часто хранят в минимальных единицах, например в копейках, то есть используют целые числа вместо дробных. В других случаях результат округляют до нужного количества знаков, сравнивают числа с допустимой погрешностью или используют специальные типы данных и библиотеки для точных вычислений. + +## Что нужно запомнить + +Операции с числами с плавающей точкой не всегда точны, и это нормально. Такое поведение характерно для большинства языков программирования и объясняется устройством компьютерной памяти. PHP при выводе округляет числа, поэтому погрешность не всегда видна на экране — но в вычислениях она присутствует. Точность можно контролировать, например с помощью округления или сравнения чисел с заданной погрешностью. А при работе с деньгами, точными измерениями или научными расчетами лучше использовать специальные типы данных, которые обеспечивают контроль над точностью. diff --git a/modules/20-arithmetics/43-float/ru/data.yml b/modules/20-arithmetics/43-float/ru/data.yml new file mode 100644 index 00000000..5886c55a --- /dev/null +++ b/modules/20-arithmetics/43-float/ru/data.yml @@ -0,0 +1,10 @@ +--- +name: Числа с плавающей точкой +tips: + - > + [Что нужно знать про арифметику с плавающей + запятой](https://habr.com/ru/articles/112953/) +definitions: + - name: Рациональное число + description: | + число, которое можно представить в виде обыкновенной дроби. diff --git a/modules/20-arithmetics/45-linting/index.php b/modules/20-arithmetics/45-linting/Solution.php similarity index 100% rename from modules/20-arithmetics/45-linting/index.php rename to modules/20-arithmetics/45-linting/Solution.php diff --git a/modules/20-arithmetics/45-linting/SolutionTest.php b/modules/20-arithmetics/45-linting/SolutionTest.php index 9a51fb7e..b8bfb7bd 100644 --- a/modules/20-arithmetics/45-linting/SolutionTest.php +++ b/modules/20-arithmetics/45-linting/SolutionTest.php @@ -2,9 +2,7 @@ namespace HexletBasics\Arithmetics\Linting; -use PHPUnit\Framework\TestCase; - -\HexletBasics\Functions\runScript(); +use HexletBasics\Exercise\TestCase; class SolutionTest extends TestCase { @@ -12,6 +10,5 @@ public function test() { $expected = '4'; $this->expectOutputString($expected); - require 'index.php'; } } diff --git a/modules/20-arithmetics/45-linting/ru/EXERCISE.md b/modules/20-arithmetics/45-linting/ru/EXERCISE.md index 953edd5c..aff6d004 100644 --- a/modules/20-arithmetics/45-linting/ru/EXERCISE.md +++ b/modules/20-arithmetics/45-linting/ru/EXERCISE.md @@ -1 +1,9 @@ -Выведите на экран результат следующего вычисления: «разница между пятью в квадрате и произведением трёх и семи». Напишите код так, чтобы каждый оператор отделялся от операндов пробелами. +Вы получили код от коллеги — он работает правильно, но нарушает стандарт оформления PSR-12. Исправьте пробелы вокруг операторов, не меняя логику: + +```php + 10.5 ``` -Этот вариант уже не нарушает правил, и линтер будет «молчать». +Этот вариант уже не нарушает правил, и линтер будет «молчать». Когда вы только начинаете, такие мелочи могут казаться неважными. Но со временем становится понятно, что именно они формируют единый читаемый стиль. + +## Использование линтера в своих проектах + +Когда вы начнете писать собственные проекты за пределами учебной платформы, линтер будет незаменимым помощником. Его можно настроить в любом редакторе кода, запустить в терминале или подключить к сборке проекта. Линтер показывает ошибки, а PHP CS Fixer умеет и исправлять их автоматически. diff --git a/modules/20-arithmetics/45-linting/ru/data.yml b/modules/20-arithmetics/45-linting/ru/data.yml index 2dd0d71d..9725e2e8 100644 --- a/modules/20-arithmetics/45-linting/ru/data.yml +++ b/modules/20-arithmetics/45-linting/ru/data.yml @@ -1,3 +1,7 @@ --- name: Линтер -tips: [] +tips: + - | + [PSR-12](https://www.php-fig.org/psr/psr-12/) + - | + [PHP CS Fixer](https://github.com/PHP-CS-Fixer/PHP-CS-Fixer) diff --git a/modules/25-strings/10-quotes/Solution.php b/modules/25-strings/10-quotes/Solution.php new file mode 100644 index 00000000..ed6e6303 --- /dev/null +++ b/modules/25-strings/10-quotes/Solution.php @@ -0,0 +1,5 @@ +expectOutputString($expected); - require 'index.php'; } } diff --git a/modules/25-strings/10-quotes/index.php b/modules/25-strings/10-quotes/index.php deleted file mode 100644 index 12b5a98a..00000000 --- a/modules/25-strings/10-quotes/index.php +++ /dev/null @@ -1,5 +0,0 @@ - Dragon's mother said "No" ``` -Нам нужно было добавить `\` для двойных кавычек, но не для апострофа, потому что сама строка создана с двойными кавычками. Если бы строка создавалась с одинарными кавычками, то символ экранирования нужен был бы перед апострофом, но не перед двойными кавычками. +Здесь мы экранируем двойные кавычки внутри строки, заключенной в двойные кавычки. + +Обратите внимание, PHP воспринимает `\"` как один символ-кавычку, а не два символа. То же самое касается `\'`, `\\` и других подобных последовательностей. Они выглядят как два символа в коде, но в строке считаются за один. + +То же самое работает и в обратном случае: ```php Death is \so terribly final +print_r('Dragon\'s mother said "No"'); +// => Dragon's mother said "No" ``` -Также нам может понадобиться вывести сам обратный слеш: +## Как вывести обратный слеш + +Чтобы вывести сам обратный слеш, его тоже нужно экранировать: ```php \ ``` - -Это тоже можно сделать через экранирование, но уже самого себя. diff --git a/modules/25-strings/10-quotes/ru/assets/strings.png b/modules/25-strings/10-quotes/ru/assets/strings.png new file mode 100644 index 00000000..4cce3286 Binary files /dev/null and b/modules/25-strings/10-quotes/ru/assets/strings.png differ diff --git a/modules/25-strings/10-quotes/ru/data.yml b/modules/25-strings/10-quotes/ru/data.yml index e8d8642b..05a961ab 100644 --- a/modules/25-strings/10-quotes/ru/data.yml +++ b/modules/25-strings/10-quotes/ru/data.yml @@ -1,3 +1,5 @@ --- name: Кавычки -tips: [] +tips: + - > + [Строки в PHP](https://www.php.net/manual/ru/language.types.string.php) diff --git a/modules/25-strings/15-escape-characters/Solution.php b/modules/25-strings/15-escape-characters/Solution.php new file mode 100644 index 00000000..24c8ea71 --- /dev/null +++ b/modules/25-strings/15-escape-characters/Solution.php @@ -0,0 +1,5 @@ +expectOutputString($expected); - require 'index.php'; } } diff --git a/modules/25-strings/15-escape-characters/index.php b/modules/25-strings/15-escape-characters/index.php deleted file mode 100644 index 7087d669..00000000 --- a/modules/25-strings/15-escape-characters/index.php +++ /dev/null @@ -1,5 +0,0 @@ - - Are you hungry?- Aaaarrrgh! ``` +Чтобы каждая из них начиналась с новой строки, нужно добавить перевод строки, то есть «нажать Enter». В программировании это реализуется через добавление специальных символов, в данном случае `\n`. Да, это не опечатка. Несмотря на то, что мы видим здесь два символа, с точки зрения PHP это один символ: -Результат: +```php + Hello\nWorld +``` + +## Примеры использования `\n` + +Вот как PHP обрабатывает управляющую последовательность `\n`: + +```text +В коде "Hello\nWorld" + ↓ +На экране Hello + World +``` + +Местоположение `\n` меняет итоговый вывод: ```php Hello\nWorld + +// Если забыть указать второй слеш +print_r("Hello\nWorld"); +// Hello +// World +``` -Символ перевода строки не является специфичным для программирования. Во многих редакторах есть опция, которая позволяет включить отображение невидимых символов. С ее помощью можно понять, где они находятся. Хотя это всего лишь схематичное отображение, у этих символов нет графического представления, они невидимые. +В этом случае PHP понимает `\\` как обычный обратный слеш и показывает строку без перевода строки. -`\n` — это пример **экранирующей последовательности** (escape sequence). Их еще называют управляющими конструкциями. Таких символов не один десяток, но в программировании часто встречаются всего несколько. Программистам часто нужно использовать перевод строки `\n` для правильного форматирования текста. +## Другие управляющие последовательности -Экранирующие последовательности вроде `\n` работают только внутри двойных кавычек. +Кроме `\n`, в PHP есть и другие управляющие последовательности: -Если нам понадобится вывести `\n` именно как текст, то можно воспользоваться уже известным нам способом экранирования — добавить еще один `\` в начале. В итоге последовательность `\\n` отобразится как символы `\` и `n`, которые идут друг за другом. +- `\t` обозначает табуляцию (эквивалент клавиши Tab) +- `\r` обозначает возврат каретки (используется в Windows, но редко применяется в PHP-коде) +- В программировании чаще всего используют именно `\n`, его достаточно для большинства задач -В Windows для перевода строк по умолчанию используется `\r\n`. Такая комбинация хорошо работает только в Windows, но создает проблемы при переносе в другие системы. Например, когда в команде разработчиков есть пользователи как Windows, так и Linux. +## Важные детали -Последовательность `\r\n` имеет разную трактовку в зависимости от выбранной кодировки. Это мы рассмотрим позже. По этой причине в среде разработчиков принято всегда использовать `\n` без `\r`, так как LF всегда трактуется одинаково и отлично работает в любой системе. Поэтому нужно настроить свой редактор на использование `\n`. +- `\n` является одним символом, несмотря на то, что в коде он записан как два (`\` и `n`) +- Управляющие последовательности в PHP работают только внутри двойных кавычек +- На Windows по умолчанию используется комбинация `\r\n`, но в кроссплатформенной разработке принято использовать только `\n`, чтобы избежать проблем при переносе кода между системами. Поэтому стоит настроить свой редактор на использование `\n` diff --git a/modules/25-strings/20-strings-concatenation/Makefile b/modules/25-strings/20-string-concatenation/Makefile similarity index 100% rename from modules/25-strings/20-strings-concatenation/Makefile rename to modules/25-strings/20-string-concatenation/Makefile diff --git a/modules/25-strings/20-string-concatenation/Solution.php b/modules/25-strings/20-string-concatenation/Solution.php new file mode 100644 index 00000000..7cb12677 --- /dev/null +++ b/modules/25-strings/20-string-concatenation/Solution.php @@ -0,0 +1,5 @@ +expectOutputString($expected); - require 'index.php'; } } diff --git a/modules/25-strings/20-strings-concatenation/description.es.yml b/modules/25-strings/20-string-concatenation/description.es.yml similarity index 100% rename from modules/25-strings/20-strings-concatenation/description.es.yml rename to modules/25-strings/20-string-concatenation/description.es.yml diff --git a/modules/25-strings/20-strings-concatenation/en/EXERCISE.md b/modules/25-strings/20-string-concatenation/en/EXERCISE.md similarity index 100% rename from modules/25-strings/20-strings-concatenation/en/EXERCISE.md rename to modules/25-strings/20-string-concatenation/en/EXERCISE.md diff --git a/modules/25-strings/20-strings-concatenation/en/README.md b/modules/25-strings/20-string-concatenation/en/README.md similarity index 100% rename from modules/25-strings/20-strings-concatenation/en/README.md rename to modules/25-strings/20-string-concatenation/en/README.md diff --git a/modules/25-strings/20-strings-concatenation/en/data.yml b/modules/25-strings/20-string-concatenation/en/data.yml similarity index 100% rename from modules/25-strings/20-strings-concatenation/en/data.yml rename to modules/25-strings/20-string-concatenation/en/data.yml diff --git a/modules/25-strings/20-strings-concatenation/es/EXERCISE.md b/modules/25-strings/20-string-concatenation/es/EXERCISE.md similarity index 100% rename from modules/25-strings/20-strings-concatenation/es/EXERCISE.md rename to modules/25-strings/20-string-concatenation/es/EXERCISE.md diff --git a/modules/25-strings/20-strings-concatenation/es/README.md b/modules/25-strings/20-string-concatenation/es/README.md similarity index 100% rename from modules/25-strings/20-strings-concatenation/es/README.md rename to modules/25-strings/20-string-concatenation/es/README.md diff --git a/modules/25-strings/20-strings-concatenation/es/data.yml b/modules/25-strings/20-string-concatenation/es/data.yml similarity index 100% rename from modules/25-strings/20-strings-concatenation/es/data.yml rename to modules/25-strings/20-string-concatenation/es/data.yml diff --git a/modules/25-strings/20-string-concatenation/ru/EXERCISE.md b/modules/25-strings/20-string-concatenation/ru/EXERCISE.md new file mode 100644 index 00000000..23290a99 --- /dev/null +++ b/modules/25-strings/20-string-concatenation/ru/EXERCISE.md @@ -0,0 +1,7 @@ +Сайт автоматически формирует ссылки на страницы пользователей, собирая их из отдельных частей. Соберите ссылку с помощью конкатенации и выведите на экран: + +```text +https://github.com/hexlet/exercises-php +``` + +Каждый компонент URL — отдельная строка: протокол, домен, имя владельца, имя репозитория. diff --git a/modules/25-strings/20-string-concatenation/ru/README.md b/modules/25-strings/20-string-concatenation/ru/README.md new file mode 100644 index 00000000..7c977b6a --- /dev/null +++ b/modules/25-strings/20-string-concatenation/ru/README.md @@ -0,0 +1,85 @@ +Часто строки нужно собирать из нескольких частей, например объединить имя и фамилию, добавить единицу измерения или составить текст из шаблона. Для этого используется операция конкатенации, то есть склеивания строк. + +## Как объединять строки + +В PHP строки объединяются с помощью оператора `.` (точка). Для сложения чисел используется оператор `+`, а для объединения строк в PHP существует отдельный бинарный оператор, который означает склеивание содержимого: + +```php + Dragonstone +``` + +Порядок имеет значение. Сначала идет левая часть (`'Dragon'`), потом правая (`'stone'`). Результат получается в том порядке, в котором указаны операнды. + +Вот как работает объединение нескольких строк. Код: + +```php + Kingswood +print_r('Kings' . 'road'); // => Kingsroad +// Здесь снаружи двойные кавычки, потому что внутри есть одиночная +print_r("King's" . 'Landing'); // => King'sLanding +``` + +PHP позволяет объединять строки, даже если они записаны в разных кавычках. Главное, чтобы обе части были строками. + +## Пробел тоже является символом + +При объединении PHP не вставляет пробелы автоматически. Если между частями должен быть пробел, его нужно указать вручную: + +```php + King's Landing + +// Пробел в начале второй строки +print_r("King's" . ' Landing'); // => King's Landing +``` + +Результат будет одинаковый. Но если пробел не добавить, то слова склеятся. + +## Управляющие последовательности + +В строках можно использовать управляющие последовательности, например `\n` для переноса строки или `\t` для табуляции. Не забывайте, что в PHP они работают только внутри двойных кавычек. При конкатенации они ведут себя так же, как и любые другие символы: + +```php + +// Hello, +// World! + +print_r('A' . "\t" . 'B'); +// => A B +``` + +## Заключение + +Конкатенация представляет собой объединение строк через оператор `.`, и строки можно объединять независимо от типа кавычек. + +- Склеивание происходит строго в порядке слева направо +- Пробелы не добавляются автоматически, их нужно включать в строки вручную diff --git a/modules/25-strings/20-strings-concatenation/ru/data.yml b/modules/25-strings/20-string-concatenation/ru/data.yml similarity index 56% rename from modules/25-strings/20-strings-concatenation/ru/data.yml rename to modules/25-strings/20-string-concatenation/ru/data.yml index 5b4c15a7..88fe3b7d 100644 --- a/modules/25-strings/20-strings-concatenation/ru/data.yml +++ b/modules/25-strings/20-string-concatenation/ru/data.yml @@ -1,5 +1,9 @@ --- name: Конкатенация +tips: + - > + Если в редакторе есть запись `// BEGIN` и `// END`, то код нужно писать + между этими строчками. definitions: - name: Конкатенация description: > diff --git a/modules/25-strings/20-strings-concatenation/index.php b/modules/25-strings/20-strings-concatenation/index.php deleted file mode 100644 index d3d4ee8c..00000000 --- a/modules/25-strings/20-strings-concatenation/index.php +++ /dev/null @@ -1,5 +0,0 @@ - 8 -``` - -Такая программа выведет на экран `8` — результат работы бинарного оператора `+` с операндами `5` и `3`. - -Можно также «сложить» две строки. Такая программа выведет на экран `Dragonstone` — результат работы бинарного оператора `.` с операндами 'Dragon' и 'stone': - -```php - Dragonstone -``` - - -Склеивание строк всегда происходит в том же порядке, в котором записаны операнды. Левый операнд становится левой частью строки, а правый — правой. Вот еще несколько примеров: - -```php - Kingswood -print_r('Kings' . 'road'); // => Kingsroad -print_r("King's" . 'Landing'); // => King'sLanding -``` - -Строки можно склеивать, даже если они записаны с разными кавычками. - -Пробел — такой же символ, как и другие, поэтому сколько пробелов поставить в строке — столько и получится в итоговой строке: - -```php - King's Landing - -// Ставим пробел в правой части -print_r("King's" . ' Landing'); // => King's Landing -``` diff --git a/modules/25-strings/30-encoding/Solution.php b/modules/25-strings/30-encoding/Solution.php new file mode 100644 index 00000000..d0d9d3c4 --- /dev/null +++ b/modules/25-strings/30-encoding/Solution.php @@ -0,0 +1,7 @@ +expectOutputString($expected); - require 'index.php'; } } diff --git a/modules/25-strings/30-encoding/index.php b/modules/25-strings/30-encoding/index.php deleted file mode 100644 index 00a36996..00000000 --- a/modules/25-strings/30-encoding/index.php +++ /dev/null @@ -1,7 +0,0 @@ -- diff --git a/modules/27-data-types/40-primitive-data-types/index.php b/modules/27-data-types/40-primitive-data-types/index.php deleted file mode 100644 index 482c3c63..00000000 --- a/modules/27-data-types/40-primitive-data-types/index.php +++ /dev/null @@ -1,5 +0,0 @@ - 8 -``` - -`'7'` — это строка, а не число, при этом интерпретатор PHP выдал ответ `8`, как если бы мы складывали два числа. Когда PHP видит несоответствие типов, он сам пытается преобразовать информацию. В данном случае он преобразовал строку `'7'` в число `7`, а потом сложил `1` и `7`. - -Не все языки так делают. PHP — это язык со **слабой типизацией**. Он знает о существовании разных типов, но относится к их использованию не строго. Он пытается преобразовывать информацию, когда это кажется разумным. - -В языках со **строгой типизацией** сложить число со строкой не получится. - -PHP был создан для интернета, а в интернете вся информация — это строки. Даже когда мы вводим на сайте номер телефона или год рождения, на сервер эта информация поступает не как числа, а как строки. Поэтому авторы языка решили, что автоматически преобразовывать типы — правильно и удобно. - -Такое автоматическое неявное преобразование типов с одной стороны и правда удобно. Но на практике это свойство языка создает множество ошибок и проблем, которые трудно найти. Код может иногда работать, а иногда не работать. Это зависит от того, «повезло» ли в конкретном случае с автоматическим преобразованием. Программист это заметит не сразу. - -В дальнейших заданиях мы будем встречаться с таким поведением не раз. Часто будет возникать вопрос «почему мой код работает не так, как я ожидаю?». diff --git a/modules/27-data-types/50-data-types-weak-typing/ru/data.yml b/modules/27-data-types/50-data-types-weak-typing/ru/data.yml deleted file mode 100644 index 9253e728..00000000 --- a/modules/27-data-types/50-data-types-weak-typing/ru/data.yml +++ /dev/null @@ -1,3 +0,0 @@ ---- -name: Слабая типизация -tips: [] diff --git a/modules/27-data-types/55-type-conversion/SolutionTest.php b/modules/27-data-types/55-type-conversion/SolutionTest.php deleted file mode 100644 index 2344e7ed..00000000 --- a/modules/27-data-types/55-type-conversion/SolutionTest.php +++ /dev/null @@ -1,17 +0,0 @@ -expectOutputString($expected); - require 'index.php'; - } -} diff --git a/modules/27-data-types/55-type-conversion/index.php b/modules/27-data-types/55-type-conversion/index.php deleted file mode 100644 index 009febdb..00000000 --- a/modules/27-data-types/55-type-conversion/index.php +++ /dev/null @@ -1,5 +0,0 @@ - 'Это 5' -``` - -Явное преобразование типа работает так: перед значением в скобках указывается желаемый тип. В результате значение справа преобразуется в значение другого типа, указанного слева в скобках. На текущий момент мы знакомы только с двумя типами, но преобразование работает для любого типа. - -В более сложных ситуациях при использовании функций, которые будем проходить позже, встречаются множественные преобразования: `(string) (5 + ((int) '4'))`. Порядок вычисления этого выражения следующий: - -```php -expectOutputString($expected); - require 'index.php'; } } diff --git a/modules/30-variables/10-definition/index.php b/modules/30-variables/10-definition/index.php deleted file mode 100644 index ff5bbc77..00000000 --- a/modules/30-variables/10-definition/index.php +++ /dev/null @@ -1,6 +0,0 @@ - Father! -// => Father! ``` -В строчке `$greeting = 'Father!'` значение `'Father!'` присваивается переменной с именем `$greeting`. В PHP имена переменных начинаются со знака *$*. В итоге переменная указывает на данные, которые были в нее записаны. +Результат: + +```text +Father! +Father! +``` + +**Переменная** представляет собой имя, за которым хранится значение. В нашем примере мы создали переменную с именем `$greeting` и записали в нее строку `'Father!'`. + +```text +$greeting = 'Father!'; + +Переменная Значение +┌───────────┐ ┌──────────┐ +│ $greeting │ ──→│ 'Father!'│ +└───────────┘ └──────────┘ +``` + +Строчка `$greeting = 'Father!'` читается так: "возьми значение `'Father!'` и присвой его переменной с именем `$greeting`". Знак `=` здесь является оператором присваивания, а не обозначением равенства как в математике. Он кладет значение в переменную. -Когда переменная создана, можно начать ее использовать. +Когда мы пишем `print_r($greeting)`, интерпретатор подставляет вместо имени `$greeting` то значение, которое в ней хранится. В результате на экран выводится строка `'Father!'`. -## Использование переменной +```text +print_r($greeting) + | + v +print_r('Father!') +``` + +## Имена переменных + +Имена переменных придумывает сам программист. В PHP имя переменной всегда начинается со знака `$`, а дальше можно использовать: + +- Латинские буквы (a-z, A-Z), +- цифры (но не в начале), +- нижнее подчеркивание _. + +Примеры допустимых имен: `$greeting`, `$name1`, `$helloWorld`. PHP различает строчные и заглавные буквы. Переменные `$greeting`, `$Greeting` и `$GREETING` являются тремя разными переменными. + +## Переменные и литералы + +В коде важно различать, где мы используем переменную, а где записываем значение напрямую. Это особенно заметно на примере с `print_r()`: + +```php + Mother! +print_r('greeting'); // => greeting +``` + +В первом случае используется **переменная** `$greeting`, и программа подставляет ее значение. Во втором случае `'greeting'` заключено в кавычки, поэтому это **строковый литерал**, то есть готовое значение, написанное прямо в коде. Здесь различить их помогает знак `$`, но с точки зрения интерпретатора это в любом случае абсолютно разные вещи. + +Литералы представляют собой данные, записанные явно (например, `'Hello'`, `42`, `3.14`). Идентификаторы являются именами переменных и функций (например, `$greeting`, `print_r`), которые указывают на уже существующие значения или команды. + +## Порядок использования + +Переменную нужно сначала создать (присвоить ей значение), а уже потом использовать. Если попытаться обратиться к переменной до ее создания, программа выдаст предупреждение, а вместо значения подставит "пустоту" — `null`: + +```php + Alice +``` + +## Несколько переменных в программе + +В одной программе можно создать сколько угодно переменных. Каждая хранит свои данные и не мешает другим: + +```php + + [Именование в + программировании](https://ru.hexlet.io/blog/posts/naming-in-programming?utm_source=code-basics&utm_medium=referral&utm_campaign=blog&utm_content=lesson) definitions: - name: Переменная description: >- diff --git a/modules/30-variables/12-change/Solution.php b/modules/30-variables/12-change/Solution.php new file mode 100644 index 00000000..340dea2a --- /dev/null +++ b/modules/30-variables/12-change/Solution.php @@ -0,0 +1,9 @@ +expectOutputString($expected); - require 'index.php'; } } diff --git a/modules/30-variables/12-change/index.php b/modules/30-variables/12-change/index.php deleted file mode 100644 index 4409669e..00000000 --- a/modules/30-variables/12-change/index.php +++ /dev/null @@ -1,9 +0,0 @@ - новое значение +``` diff --git a/modules/30-variables/12-change/ru/README.md b/modules/30-variables/12-change/ru/README.md index 50bbb1fb..36f0468c 100644 --- a/modules/30-variables/12-change/ru/README.md +++ b/modules/30-variables/12-change/ru/README.md @@ -1,9 +1,11 @@ -Со временем внутри программы значения переменных могут изменяться: +Само слово "переменная" подсказывает, что ее значение может меняться. Это одна из главных причин, почему переменные вообще существуют. + +Вот простой пример: ```php Father! @@ -11,8 +13,38 @@ $greeting = 'Mother!'; print_r($greeting); // => Mother! ``` -Имя осталось тем же, но внутри другие данные. Переменные в PHP не требуют специального объявления. Вместо этого переменная объявляется при первом ее использовании в программе. +Здесь мы сначала записали в переменную одну строку (_Father!_), потом другую (_Mother!_). Имя переменной не изменилось, но значение внутри стало другим. + +```text +До: $greeting ──→ 'Father!' + ╳ +После: $greeting ──→ 'Mother!' +``` + +## Зачем вообще менять значение? + +В реальных программах переменные меняются постоянно. Вот несколько причин: + +- Программа реагирует на действия пользователя. Например, пока вы вводите какие-то данные, в формы на сайте, они, в этот момент, вполне вероятно, постоянно меняют переменные, которые эти данные содержат +- Промежуточные результаты. Часто данные проходят через серию преобразований, и на каждом этапе переменная обновляется новым значением. Подобный механизм даже есть в калькуляторах, когда промежуточные значения сохраняются с помощью клавиш `m+` или `m-`. +- Хранение состояния. Если вы пишете игру, то положение персонажа, его здоровье, счет и текущий уровень являются переменными, которые постоянно меняются. + +## Переменные создаются по мере использования + +В PHP переменную не нужно "объявлять заранее": она появляется в момент, когда вы впервые записываете в нее значение: + +```php + - Если в редакторе есть запись `// BEGIN` и `// END`, то код нужно писать - между этими строчками. +tips: [] definitions: - name: Переменная description: >- diff --git a/modules/30-variables/13-variables-naming/index.php b/modules/30-variables/13-variables-naming/Solution.php similarity index 100% rename from modules/30-variables/13-variables-naming/index.php rename to modules/30-variables/13-variables-naming/Solution.php diff --git a/modules/30-variables/13-variables-naming/SolutionTest.php b/modules/30-variables/13-variables-naming/SolutionTest.php index 7657c077..0621225e 100644 --- a/modules/30-variables/13-variables-naming/SolutionTest.php +++ b/modules/30-variables/13-variables-naming/SolutionTest.php @@ -2,9 +2,7 @@ namespace HexletBasics\Variables\Naming; -use PHPUnit\Framework\TestCase; - -\HexletBasics\Functions\runScript(); +use HexletBasics\Exercise\TestCase; class SolutionTest extends TestCase { @@ -12,6 +10,5 @@ public function test() { $expected = "2"; $this->expectOutputString($expected); - require 'index.php'; } } diff --git a/modules/30-variables/13-variables-naming/ru/README.md b/modules/30-variables/13-variables-naming/ru/README.md index 21792a4c..c175296b 100644 --- a/modules/30-variables/13-variables-naming/ru/README.md +++ b/modules/30-variables/13-variables-naming/ru/README.md @@ -1,17 +1,47 @@ -В этом уроке мы поговорим об именовании. Изучать эту тему мы начнем с примера. Посмотрим на такую программу: +Представьте, что у нас есть такая программа: ```php [Именование в - программировании](https://ru.hexlet.io/blog/posts/naming-in-programming) + программировании](https://ru.hexlet.io/blog/posts/naming-in-programming?utm_source=code-basics&utm_medium=referral&utm_campaign=blog&utm_content=lesson) - > [Ошибки в именовании - переменных](https://ru.hexlet.io/blog/posts/naming-errors-1) -definitions: [] + переменных](https://ru.hexlet.io/blog/posts/naming-errors-1?utm_source=code-basics&utm_medium=referral&utm_campaign=blog&utm_content=lesson) +definitions: + - name: Переменная + description: >- + способ сохранить информацию и дать ей имя для последующего использования в + коде. diff --git a/modules/30-variables/14-errors/SolutionTest.php b/modules/30-variables/14-errors/SolutionTest.php deleted file mode 100644 index 83cd81d5..00000000 --- a/modules/30-variables/14-errors/SolutionTest.php +++ /dev/null @@ -1,17 +0,0 @@ -expectOutputString($expected); - require 'index.php'; - } -} diff --git a/modules/30-variables/14-errors/description.es.yml b/modules/30-variables/14-errors/description.es.yml deleted file mode 100644 index 66cf5aa3..00000000 --- a/modules/30-variables/14-errors/description.es.yml +++ /dev/null @@ -1,30 +0,0 @@ ---- - -name: Errores al trabajar con variables -theory: | - Es necesario declarar una variable antes de utilizarla. Si se hace después, el programa no funcionará: - - ```php - - Targaryen and Dragon - - -tips: [] - -definitions: [] diff --git a/modules/30-variables/14-errors/en/EXERCISE.md b/modules/30-variables/14-errors/en/EXERCISE.md deleted file mode 100644 index ec8d9933..00000000 --- a/modules/30-variables/14-errors/en/EXERCISE.md +++ /dev/null @@ -1,8 +0,0 @@ - -Find an undeclared variable in the program and declare it by assigning the value `'Dragon'` to it. - -After running the program, the result on the screen should look like this: - -```text -Targaryen and Dragon -``` diff --git a/modules/30-variables/14-errors/en/README.md b/modules/30-variables/14-errors/en/README.md deleted file mode 100644 index c24131df..00000000 --- a/modules/30-variables/14-errors/en/README.md +++ /dev/null @@ -1,13 +0,0 @@ - -The main rule is that a variable must be declared before it can be used. If you do it later, the program simply won't work. - -```php - "Kingsroad" - -// Конкатенируем строку и переменную, в которой записана строка -$first = "Kings"; -$what = $first . "road"; -print_r($what); // => "Kingsroad" - -// Конкатенируем две переменные, в которых записаны строки -$last = 'road'; -$what = $first . $last; -print_r($what); // => "Kingsroad" -``` diff --git a/modules/30-variables/15-expressions/ru/data.yml b/modules/30-variables/15-expressions/ru/data.yml deleted file mode 100644 index 5de10e09..00000000 --- a/modules/30-variables/15-expressions/ru/data.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -name: Выражения в определениях -tips: - - | - Для перевода строчки можно использовать `\n` между выводом долларов и юаней. diff --git a/modules/30-variables/15-expressions/Makefile b/modules/30-variables/15-variables-expressions/Makefile similarity index 100% rename from modules/30-variables/15-expressions/Makefile rename to modules/30-variables/15-variables-expressions/Makefile diff --git a/modules/30-variables/15-expressions/index.php b/modules/30-variables/15-variables-expressions/Solution.php similarity index 100% rename from modules/30-variables/15-expressions/index.php rename to modules/30-variables/15-variables-expressions/Solution.php diff --git a/modules/30-variables/15-expressions/SolutionTest.php b/modules/30-variables/15-variables-expressions/SolutionTest.php similarity index 68% rename from modules/30-variables/15-expressions/SolutionTest.php rename to modules/30-variables/15-variables-expressions/SolutionTest.php index 0be31001..61bcaae1 100644 --- a/modules/30-variables/15-expressions/SolutionTest.php +++ b/modules/30-variables/15-variables-expressions/SolutionTest.php @@ -2,9 +2,7 @@ namespace HexletBasics\Variables\Expressions; -use PHPUnit\Framework\TestCase; - -\HexletBasics\Functions\runScript(); +use HexletBasics\Exercise\TestCase; class SolutionTest extends TestCase { @@ -12,6 +10,5 @@ public function test() { $expected = "125\n863.75"; $this->expectOutputString($expected); - require 'index.php'; } } diff --git a/modules/30-variables/15-expressions/description.es.yml b/modules/30-variables/15-variables-expressions/description.es.yml similarity index 100% rename from modules/30-variables/15-expressions/description.es.yml rename to modules/30-variables/15-variables-expressions/description.es.yml diff --git a/modules/30-variables/15-expressions/en/EXERCISE.md b/modules/30-variables/15-variables-expressions/en/EXERCISE.md similarity index 100% rename from modules/30-variables/15-expressions/en/EXERCISE.md rename to modules/30-variables/15-variables-expressions/en/EXERCISE.md diff --git a/modules/30-variables/15-expressions/en/README.md b/modules/30-variables/15-variables-expressions/en/README.md similarity index 100% rename from modules/30-variables/15-expressions/en/README.md rename to modules/30-variables/15-variables-expressions/en/README.md diff --git a/modules/30-variables/15-expressions/en/data.yml b/modules/30-variables/15-variables-expressions/en/data.yml similarity index 100% rename from modules/30-variables/15-expressions/en/data.yml rename to modules/30-variables/15-variables-expressions/en/data.yml diff --git a/modules/30-variables/15-expressions/es/EXERCISE.md b/modules/30-variables/15-variables-expressions/es/EXERCISE.md similarity index 100% rename from modules/30-variables/15-expressions/es/EXERCISE.md rename to modules/30-variables/15-variables-expressions/es/EXERCISE.md diff --git a/modules/30-variables/15-expressions/es/README.md b/modules/30-variables/15-variables-expressions/es/README.md similarity index 100% rename from modules/30-variables/15-expressions/es/README.md rename to modules/30-variables/15-variables-expressions/es/README.md diff --git a/modules/30-variables/15-expressions/es/data.yml b/modules/30-variables/15-variables-expressions/es/data.yml similarity index 100% rename from modules/30-variables/15-expressions/es/data.yml rename to modules/30-variables/15-variables-expressions/es/data.yml diff --git a/modules/30-variables/15-expressions/ru/EXERCISE.md b/modules/30-variables/15-variables-expressions/ru/EXERCISE.md similarity index 100% rename from modules/30-variables/15-expressions/ru/EXERCISE.md rename to modules/30-variables/15-variables-expressions/ru/EXERCISE.md diff --git a/modules/30-variables/15-variables-expressions/ru/README.md b/modules/30-variables/15-variables-expressions/ru/README.md new file mode 100644 index 00000000..fe116859 --- /dev/null +++ b/modules/30-variables/15-variables-expressions/ru/README.md @@ -0,0 +1,82 @@ +Мы уже знаем, что выражения можно составлять из нескольких операций. Но если записать все вычисление в одну длинную строку, код быстро становится трудным для чтения. + +Например, вот такая запись работает: + +```php + 431.875 +``` + +PHP легко вычислит это выражение. Но человеку читать такой код уже не так удобно. Сразу возникают вопросы: + +- Что означает `1.25`? +- Что означает `6.91`? +- Где заканчивается один шаг вычисления и начинается следующий? + +Чтобы сделать такие вычисления понятнее, переменные можно использовать внутри других выражений. Сначала программа сохраняет промежуточный результат в переменную, а затем подставляет значение этой переменной в следующее вычисление. + +Переменные помогают разбивать сложные вычисления на понятные части и сохранять промежуточные результаты. + +## Конвертация валют через промежуточную валюту + +Представим, что нужно перевести евро в юани, но напрямую такой курс нам недоступен. Тогда сделаем это в два шага: **евро -> доллары -> юани**. Так часто работают банки при оплате покупок за рубежом. + +## Шаг 1. Евро -> Доллары + +Допустим, курс: 1 евро = 1.25 доллара. Хотим перевести 50 евро: + +```php + 62.5 +``` + +В этой строке `50 * $dollarsPerEuro` является выражением, а `$dollarsCount` представляет собой переменную, в которую записывается результат. PHP сначала вычисляет выражение, а уже потом сохраняет результат в переменную. + +Интерпретатору все равно, как записано выражение: + +```php +$dollarsCount = 62.5; +``` + +или + +```php +$dollarsCount = 50 * $dollarsPerEuro; +``` + +Результат будет один и тот же. Но для человека второй вариант полезнее: по имени `$dollarsCount` сразу видно, что на этом шаге мы получили сумму в долларах. + +## Шаг 2. Доллары -> Юани + +Теперь переведем 50 евро в юани, используя доллар как промежуточную валюту. Допустим, курсы валют: 1 доллар = 6.91 юаней, 1 евро = 1.25 долларов. + +```php +- + способ сохранить информацию и дать ей имя для последующего использования в + коде. diff --git a/modules/30-variables/18-concatenation/SolutionTest.php b/modules/30-variables/18-concatenation/SolutionTest.php deleted file mode 100644 index 69a3e0e3..00000000 --- a/modules/30-variables/18-concatenation/SolutionTest.php +++ /dev/null @@ -1,22 +0,0 @@ -expectOutputString($expected); - require 'index.php'; - } -} diff --git a/modules/30-variables/18-concatenation/index.php b/modules/30-variables/18-concatenation/index.php deleted file mode 100644 index 234fef87..00000000 --- a/modules/30-variables/18-concatenation/index.php +++ /dev/null @@ -1,12 +0,0 @@ - "Kingsroad" -``` - -… а значит сумеем конкатенировать строку и одну переменную, в которой записана строка: - -```php - "Kingsroad" -``` - -… и даже конкатенировать две переменные, в которых записаны строки: - -```php - "Kingsroad" -``` diff --git a/modules/30-variables/18-concatenation/Makefile b/modules/30-variables/18-variable-concatenation/Makefile similarity index 100% rename from modules/30-variables/18-concatenation/Makefile rename to modules/30-variables/18-variable-concatenation/Makefile diff --git a/modules/30-variables/18-variable-concatenation/Solution.php b/modules/30-variables/18-variable-concatenation/Solution.php new file mode 100644 index 00000000..daba7cd5 --- /dev/null +++ b/modules/30-variables/18-variable-concatenation/Solution.php @@ -0,0 +1,11 @@ +expectOutputString($expected); + } +} diff --git a/modules/30-variables/18-concatenation/description.es.yml b/modules/30-variables/18-variable-concatenation/description.es.yml similarity index 100% rename from modules/30-variables/18-concatenation/description.es.yml rename to modules/30-variables/18-variable-concatenation/description.es.yml diff --git a/modules/30-variables/18-concatenation/en/EXERCISE.md b/modules/30-variables/18-variable-concatenation/en/EXERCISE.md similarity index 100% rename from modules/30-variables/18-concatenation/en/EXERCISE.md rename to modules/30-variables/18-variable-concatenation/en/EXERCISE.md diff --git a/modules/30-variables/18-concatenation/en/README.md b/modules/30-variables/18-variable-concatenation/en/README.md similarity index 100% rename from modules/30-variables/18-concatenation/en/README.md rename to modules/30-variables/18-variable-concatenation/en/README.md diff --git a/modules/30-variables/18-concatenation/en/data.yml b/modules/30-variables/18-variable-concatenation/en/data.yml similarity index 100% rename from modules/30-variables/18-concatenation/en/data.yml rename to modules/30-variables/18-variable-concatenation/en/data.yml diff --git a/modules/30-variables/18-concatenation/es/EXERCISE.md b/modules/30-variables/18-variable-concatenation/es/EXERCISE.md similarity index 100% rename from modules/30-variables/18-concatenation/es/EXERCISE.md rename to modules/30-variables/18-variable-concatenation/es/EXERCISE.md diff --git a/modules/30-variables/18-concatenation/es/README.md b/modules/30-variables/18-variable-concatenation/es/README.md similarity index 100% rename from modules/30-variables/18-concatenation/es/README.md rename to modules/30-variables/18-variable-concatenation/es/README.md diff --git a/modules/30-variables/18-concatenation/es/data.yml b/modules/30-variables/18-variable-concatenation/es/data.yml similarity index 100% rename from modules/30-variables/18-concatenation/es/data.yml rename to modules/30-variables/18-variable-concatenation/es/data.yml diff --git a/modules/30-variables/18-variable-concatenation/ru/EXERCISE.md b/modules/30-variables/18-variable-concatenation/ru/EXERCISE.md new file mode 100644 index 00000000..e92e8b04 --- /dev/null +++ b/modules/30-variables/18-variable-concatenation/ru/EXERCISE.md @@ -0,0 +1,15 @@ +Интернет-магазин отправляет покупателю письмо после оформления заказа. Письмо генерируется автоматически на основе данных о клиенте. + +Напишите программу, которая генерирует приветствие и тело письма, используя уже готовые переменные, и выводит строки на экран. + +Для приветствия используйте переменные `$firstName` и `$greeting`, запятую и восклицательный знак. Для тела письма используйте переменные `$intro` и `$info` — второе предложение должно быть на новой строке. + +Результат на экране: + +```text +Здравствуйте, Анна! +Спасибо за ваш заказ. +Ожидаемая дата доставки — 3 рабочих дня. +``` + +Выполните задание, используя только два `print_r()`. Не забудьте, что `print_r()` не переводит строку сам — перенос `\n` нужно добавить в нужные места самостоятельно. diff --git a/modules/30-variables/18-variable-concatenation/ru/README.md b/modules/30-variables/18-variable-concatenation/ru/README.md new file mode 100644 index 00000000..20288da1 --- /dev/null +++ b/modules/30-variables/18-variable-concatenation/ru/README.md @@ -0,0 +1,81 @@ +Ранее мы уже склеивали строки напрямую, используя конкатенацию. Теперь сделаем то же самое, но с использованием переменных. Хорошая новость: синтаксис остается тем же. Просто подставляются значения переменных. + +## Склеиваем две строки напрямую + +```php + Kingsroad +``` + +Здесь все просто: две строки соединяются в одну. Так работает конкатенация: оператор `.` складывает строки, создавая новую строку. + +## Склеиваем строку и переменную + +Если в переменной `$first` лежит строка "Kings", мы можем спокойно склеить ее с другой строкой: + +```php + Kingsroad +``` + +PHP подставит значение переменной, выполнит операцию и создаст итоговую строку. + +## Склеиваем две переменные + +Точно так же можно объединить значения двух переменных, если обе содержат строки: + +```php + Kingsroad +``` + +Можно добавлять и пробелы: + +```php +$full = $first . ' ' . $last; +print_r($full); // => Kings road +``` + +```text +$first = 'Kings' +$last = 'road' + +$first . ' ' . $last +└─┬──┘ └──┬─┘ +'Kings' . ' ' . 'road' +└─────────┬────────────┘ + 'Kings road' +``` + +## А что если переменная содержит число? + +Попробуем так: + +```php + Age: 42 +``` + +В PHP такой код работает: оператор `.` всегда склеивает строки, поэтому число автоматически преобразуется в строку. Не во всех языках так — например, в Python склеивание строки и числа приводит к ошибке, и число приходится преобразовывать явно. + +То же самое касается переменных с результатами вычислений: + +```php + 431.875 +print_r('Price in yuans: ' . $price); // => Price in yuans: 431.875 +``` + +Автоматическое преобразование удобно, но требует внимательности: иногда в строку превращается не то, что вы ожидали. Подробнее о таком поведении мы поговорим в уроках про типы данных. diff --git a/modules/30-variables/18-concatenation/ru/data.yml b/modules/30-variables/18-variable-concatenation/ru/data.yml similarity index 52% rename from modules/30-variables/18-concatenation/ru/data.yml rename to modules/30-variables/18-variable-concatenation/ru/data.yml index 53c10189..925260ef 100644 --- a/modules/30-variables/18-concatenation/ru/data.yml +++ b/modules/30-variables/18-variable-concatenation/ru/data.yml @@ -6,4 +6,9 @@ tips: чтобы получить такой двухстрочный вывод тела письма. - > Помните, что можно создать строку, которая содержит только управляющую - последовательность `\n`. + последовательность `\n`. Вы можете конкатенировать эту строку с переменными + для правильного форматирования текста. +definitions: + - name: Конкатенация + description: > + операция соединения двух строк. Например, `print_r("King's " . ' Landing')` diff --git a/modules/30-variables/19-naming-style/Solution.php b/modules/30-variables/19-naming-style/Solution.php new file mode 100644 index 00000000..b7131ef6 --- /dev/null +++ b/modules/30-variables/19-naming-style/Solution.php @@ -0,0 +1,8 @@ +expectOutputString($expected); - require 'index.php'; } } diff --git a/modules/30-variables/19-naming-style/index.php b/modules/30-variables/19-naming-style/index.php deleted file mode 100644 index c15ecce0..00000000 --- a/modules/30-variables/19-naming-style/index.php +++ /dev/null @@ -1,8 +0,0 @@ -expectOutputString($expected); - require 'index.php'; } } diff --git a/modules/30-variables/20-magic-numbers/index.php b/modules/30-variables/20-magic-numbers/index.php deleted file mode 100644 index 0f94634c..00000000 --- a/modules/30-variables/20-magic-numbers/index.php +++ /dev/null @@ -1,9 +0,0 @@ - + [Магические + числа](https://ru.wikipedia.org/wiki/Магическое_число_(программирование)) diff --git a/modules/30-variables/23-constants/Solution.php b/modules/30-variables/23-constants/Solution.php new file mode 100644 index 00000000..63c81dd4 --- /dev/null +++ b/modules/30-variables/23-constants/Solution.php @@ -0,0 +1,5 @@ +assertEquals(3, DRAGONS_BORN_COUNT); + $this->assertEquals(3, MAX_LOGIN_ATTEMPTS); } } diff --git a/modules/30-variables/23-constants/index.php b/modules/30-variables/23-constants/index.php deleted file mode 100644 index 51d5eead..00000000 --- a/modules/30-variables/23-constants/index.php +++ /dev/null @@ -1,5 +0,0 @@ - 3.14 ``` -Создание константы отличается от создания переменной. Оно начинается с ключевого слова `const` и последующего имени константы. При этом знак доллара не нужен. Далее ей присваивается нужное значение. +Здесь PI является константой, которая хранит значение числа π. Создание константы отличается от создания переменной: оно начинается с ключевого слова `const`, а знак доллара перед именем не нужен. Смысл константы в том, что ее значение не меняется в ходе работы программы. -Константы принято именовать буквами в верхнем регистре с `_` в качестве разделителя. Константа тоже может использоваться в любом выражении. Единственное ограничение — константу нельзя изменить. +## Чем отличается константа от переменной? -В PHP много встроенных констант, которые можно использовать в любом месте программы. Вот некоторые из них: +Концепт констант распространен в большинстве языков программирования. В PHP константа является отдельной сущностью языка: в отличие от переменной, ее значение нельзя изменить. Попытка определить константу повторно приводит к ошибке: + +```php +expectOutputString(__DIR__); - require 'index.php'; - } -} diff --git a/modules/30-variables/24-magic-constants/description.es.yml b/modules/30-variables/24-magic-constants/description.es.yml deleted file mode 100644 index e11a3ca9..00000000 --- a/modules/30-variables/24-magic-constants/description.es.yml +++ /dev/null @@ -1,28 +0,0 @@ ---- - -name: Constantes mágicas -theory: | - - Además de las constantes normales, en PHP existe un grupo separado llamado **constantes mágicas**. Sus diferencias son las siguientes: - - * No se pueden definir constantes mágicas por uno mismo, solo se pueden utilizar las existentes. - * Las constantes mágicas comienzan y terminan con los caracteres `__` (dos guiones bajos). - * La magia radica en que estas constantes tienen el mismo valor solo dentro de una parte específica del programa. - - El último punto puede parecer extraño. ¿Cómo pueden ser constantes si su valor cambia? Para ser honestos, no son muy constantes, pero sus cambios están claramente regulados y en la práctica no causan problemas. Algunos ejemplos de estas constantes son: - - * `__LINE__` - contiene la línea actual del archivo en el que se utiliza - * `__FILE__` - la ruta al archivo actual - * `__DIR__` - la ruta al directorio en el que se encuentra el archivo actual - -instructions: | - - Muestra en pantalla la ruta al directorio actual utilizando una constante mágica. - -tips: - - | - [Constantes mágicas](https://php.net/manual/es/language.constants.predefined.php) - -definitions: - - name: Constante mágica - description: una constante especial disponible en PHP; tiene diferentes valores en diferentes contextos. diff --git a/modules/30-variables/24-magic-constants/en/EXERCISE.md b/modules/30-variables/24-magic-constants/en/EXERCISE.md deleted file mode 100644 index 82b21470..00000000 --- a/modules/30-variables/24-magic-constants/en/EXERCISE.md +++ /dev/null @@ -1,2 +0,0 @@ - -Output the path to the current directory using a magic constant. diff --git a/modules/30-variables/24-magic-constants/en/README.md b/modules/30-variables/24-magic-constants/en/README.md deleted file mode 100644 index 6e68dd1d..00000000 --- a/modules/30-variables/24-magic-constants/en/README.md +++ /dev/null @@ -1,12 +0,0 @@ - -In addition to the usual constants, PHP has a separate group of **magic constants**. The differences are as follows: - -* You can't define magic constants yourself, you can only use existing ones. -* Magic constants begin and end with `__` (two underscores). -* The magic is that the constants have the same value only within a certain part of the program. - -This last point may seem strange. What kind of constants are they if their value changes? To put it bluntly, they're not very constant, but their changes are clearly regulated and in practice don't cause problems. Such constants include, for example, the following: - -* `__LINE__` — contains the current line of the file it's used in -* `__FILE__` — path to the current file -* `__DIR__` — the path to the directory where the current file is located diff --git a/modules/30-variables/24-magic-constants/en/data.yml b/modules/30-variables/24-magic-constants/en/data.yml deleted file mode 100644 index 6a4fd466..00000000 --- a/modules/30-variables/24-magic-constants/en/data.yml +++ /dev/null @@ -1,11 +0,0 @@ ---- -name: Magic constants -tips: - - > - [Magic - constants](https://www.php.net/manual/en/language.constants.predefined.php) -definitions: - - name: A magic constant - description: >- - is a special constant available in PHP; it contains different values in - different contexts. diff --git a/modules/30-variables/24-magic-constants/es/EXERCISE.md b/modules/30-variables/24-magic-constants/es/EXERCISE.md deleted file mode 100644 index ec09bb2c..00000000 --- a/modules/30-variables/24-magic-constants/es/EXERCISE.md +++ /dev/null @@ -1,2 +0,0 @@ - -Muestra en pantalla la ruta al directorio actual utilizando una constante mágica. diff --git a/modules/30-variables/24-magic-constants/es/README.md b/modules/30-variables/24-magic-constants/es/README.md deleted file mode 100644 index 57e77e65..00000000 --- a/modules/30-variables/24-magic-constants/es/README.md +++ /dev/null @@ -1,12 +0,0 @@ - -Además de las constantes normales, en PHP existe un grupo separado llamado **constantes mágicas**. Sus diferencias son las siguientes: - -* No se pueden definir constantes mágicas por uno mismo, solo se pueden utilizar las existentes. -* Las constantes mágicas comienzan y terminan con los caracteres `__` (dos guiones bajos). -* La magia radica en que estas constantes tienen el mismo valor solo dentro de una parte específica del programa. - -El último punto puede parecer extraño. ¿Cómo pueden ser constantes si su valor cambia? Para ser honestos, no son muy constantes, pero sus cambios están claramente regulados y en la práctica no causan problemas. Algunos ejemplos de estas constantes son: - -* `__LINE__` - contiene la línea actual del archivo en el que se utiliza -* `__FILE__` - la ruta al archivo actual -* `__DIR__` - la ruta al directorio en el que se encuentra el archivo actual diff --git a/modules/30-variables/24-magic-constants/es/data.yml b/modules/30-variables/24-magic-constants/es/data.yml deleted file mode 100644 index 94a0ad1c..00000000 --- a/modules/30-variables/24-magic-constants/es/data.yml +++ /dev/null @@ -1,11 +0,0 @@ ---- -name: Constantes mágicas -tips: - - > - [Constantes - mágicas](https://php.net/manual/es/language.constants.predefined.php) -definitions: - - name: Constante mágica - description: >- - una constante especial disponible en PHP; tiene diferentes valores en - diferentes contextos. diff --git a/modules/30-variables/24-magic-constants/index.php b/modules/30-variables/24-magic-constants/index.php deleted file mode 100644 index 8aa42cf9..00000000 --- a/modules/30-variables/24-magic-constants/index.php +++ /dev/null @@ -1,5 +0,0 @@ - - [Магические - константы](https://php.net/manual/ru/language.constants.predefined.php) -definitions: - - name: Магическая константа - description: >- - специальная константа, доступная в PHP; содержит разное значение в разных - контекстах. diff --git a/modules/30-variables/25-interpolation/SolutionTest.php b/modules/30-variables/25-interpolation/SolutionTest.php deleted file mode 100644 index 19afe7c3..00000000 --- a/modules/30-variables/25-interpolation/SolutionTest.php +++ /dev/null @@ -1,17 +0,0 @@ -expectOutputString($expected); - require 'index.php'; - } -} diff --git a/modules/30-variables/25-interpolation/index.php b/modules/30-variables/25-interpolation/index.php deleted file mode 100644 index 4dfa44f7..00000000 --- a/modules/30-variables/25-interpolation/index.php +++ /dev/null @@ -1,7 +0,0 @@ -?`. Где вместо `` должна использоваться переменная `$stark`. Вывод должен получиться таким: - -```text -Do you want to eat, Arya? -``` diff --git a/modules/30-variables/25-interpolation/ru/README.md b/modules/30-variables/25-interpolation/ru/README.md deleted file mode 100644 index f867779a..00000000 --- a/modules/30-variables/25-interpolation/ru/README.md +++ /dev/null @@ -1,34 +0,0 @@ -Представим, что нам нужно создать заголовок письма из двух переменных и знаков препинания. Эту задачу можно решить так: - -```php - 'Hello, Joffrey!' -``` - -Это простой случай, но даже здесь нужно приложить усилия, чтобы увидеть, какая в итоге получится строка. Нужно следить за несколькими кавычками и пробелами, и с первого взгляда сложно понять, что и где начинается и заканчивается. - -Есть другой более удобный способ — **интерполяция**. Так это выглядит: - -```php - Hello, Joffrey! -``` - - -В этом примере мы создали одну строку и в нужном нам порядке вставили в нее переменные с помощью фигурных скобок (`{}`). Получился шаблон, куда внесены нужные значения. - -Теперь нам не нужно заботиться об отдельных строках для знаков препинания и пробелов. Эти символы записаны в строке-шаблоне. - -В одной строке можно делать сколько угодно блоков с фигурными скобками. Также интерполяция работает только со строками в двойных кавычках. - -Почти во всех языках интерполяция предпочтительнее конкатенации для объединения строк. Строка при этом получается склеенная, и внутри нее хорошо просматриваются пробелы и другие символы. diff --git a/modules/30-variables/25-interpolation/ru/data.yml b/modules/30-variables/25-interpolation/ru/data.yml deleted file mode 100644 index 390eab8f..00000000 --- a/modules/30-variables/25-interpolation/ru/data.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -name: Интерполяция -tips: [] -definitions: - - name: Интерполяция - description: >- - способ соединения строк через вставку значений переменных в строку-шаблон - с помощью фигурных скобок. Например, `\"Hi, {$name}!\"`. diff --git a/modules/30-variables/30-symbols/SolutionTest.php b/modules/30-variables/30-symbols/SolutionTest.php deleted file mode 100644 index 6a54da1a..00000000 --- a/modules/30-variables/30-symbols/SolutionTest.php +++ /dev/null @@ -1,17 +0,0 @@ -expectOutputString($expected); - require 'index.php'; - } -} diff --git a/modules/30-variables/30-symbols/index.php b/modules/30-variables/30-symbols/index.php deleted file mode 100644 index c43db9c7..00000000 --- a/modules/30-variables/30-symbols/index.php +++ /dev/null @@ -1,9 +0,0 @@ - A -``` - -Квадратные скобки с цифрой — это специальный оператор извлечения строки. Эта цифра называется **индексом** — позицией символа внутри строки. - -Индексы начинаются с нуля почти во всех языках программирования. Чтобы получить первый символ, нужно указать индекс `0`. Индекс последнего элемента равен длине строки минус единица: - -```php - r - -// Вопрос на самопроверку. Что выведет этот код? -$magic = '\nyou'; -print_r($magic[1]); // => ? -``` - -Также допустимо использовать отрицательные индексы. В этом случае идет обращение к символам с конца строки. `-1` — индекс последнего символа, `-2` — предпоследнего и так далее. В отличие от прямой индексации обратный отсчет идет от `-1`: - -```php - r -``` - -Индексом может быть не только конкретное число, но и значение переменной. Вот пример, который приведет к тому же результату — выводу на экран символа `A`: - -```php - A -``` - -Здесь индекс внутри квадратных скобок записан не числом, а переменной. diff --git a/modules/30-variables/30-symbols/ru/data.yml b/modules/30-variables/30-symbols/ru/data.yml deleted file mode 100644 index 405090b7..00000000 --- a/modules/30-variables/30-symbols/ru/data.yml +++ /dev/null @@ -1,3 +0,0 @@ ---- -name: Извлечение символов из строки -tips: [] diff --git a/modules/30-variables/35-heredoc/SolutionTest.php b/modules/30-variables/35-heredoc/SolutionTest.php deleted file mode 100644 index e11976b3..00000000 --- a/modules/30-variables/35-heredoc/SolutionTest.php +++ /dev/null @@ -1,20 +0,0 @@ -expectOutputString($expected); - require 'index.php'; - } -} diff --git a/modules/30-variables/35-heredoc/index.php b/modules/30-variables/35-heredoc/index.php deleted file mode 100644 index 4fdcf328..00000000 --- a/modules/30-variables/35-heredoc/index.php +++ /dev/null @@ -1,10 +0,0 @@ - Пример строки, -// => охватывающей несколько строк, -// => с использованием heredoc-синтаксиса. -// => Здесь не нужно экранировать ни одинарные ', ни двойные " кавычки. -``` - -Перед закрывающим идентификатором, в нашем случае — `EOT`, не должны стоять пробелы, иначе PHP начнет ругаться на ошибку синтаксиса. diff --git a/modules/30-variables/35-heredoc/ru/data.yml b/modules/30-variables/35-heredoc/ru/data.yml deleted file mode 100644 index fd50d7c2..00000000 --- a/modules/30-variables/35-heredoc/ru/data.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -name: Heredoc -definitions: [] -tips: - - > - [Heredoc](https://www.php.net/manual/ru/language.types.string.php#language.types.string.syntax.heredoc) diff --git a/modules/30-variables/24-magic-constants/Makefile b/modules/31-advanced-strings/100-unicode/Makefile similarity index 100% rename from modules/30-variables/24-magic-constants/Makefile rename to modules/31-advanced-strings/100-unicode/Makefile diff --git a/modules/31-advanced-strings/100-unicode/Solution.php b/modules/31-advanced-strings/100-unicode/Solution.php new file mode 100644 index 00000000..a34687e0 --- /dev/null +++ b/modules/31-advanced-strings/100-unicode/Solution.php @@ -0,0 +1,6 @@ +expectOutputString($expected); - require 'index.php'; } } diff --git a/modules/60-deep-into-strings/10-unicode/description.es.yml b/modules/31-advanced-strings/100-unicode/description.es.yml similarity index 100% rename from modules/60-deep-into-strings/10-unicode/description.es.yml rename to modules/31-advanced-strings/100-unicode/description.es.yml diff --git a/modules/60-deep-into-strings/10-unicode/en/EXERCISE.md b/modules/31-advanced-strings/100-unicode/en/EXERCISE.md similarity index 100% rename from modules/60-deep-into-strings/10-unicode/en/EXERCISE.md rename to modules/31-advanced-strings/100-unicode/en/EXERCISE.md diff --git a/modules/60-deep-into-strings/10-unicode/en/README.md b/modules/31-advanced-strings/100-unicode/en/README.md similarity index 100% rename from modules/60-deep-into-strings/10-unicode/en/README.md rename to modules/31-advanced-strings/100-unicode/en/README.md diff --git a/modules/60-deep-into-strings/10-unicode/en/data.yml b/modules/31-advanced-strings/100-unicode/en/data.yml similarity index 100% rename from modules/60-deep-into-strings/10-unicode/en/data.yml rename to modules/31-advanced-strings/100-unicode/en/data.yml diff --git a/modules/60-deep-into-strings/10-unicode/es/EXERCISE.md b/modules/31-advanced-strings/100-unicode/es/EXERCISE.md similarity index 100% rename from modules/60-deep-into-strings/10-unicode/es/EXERCISE.md rename to modules/31-advanced-strings/100-unicode/es/EXERCISE.md diff --git a/modules/60-deep-into-strings/10-unicode/es/README.md b/modules/31-advanced-strings/100-unicode/es/README.md similarity index 100% rename from modules/60-deep-into-strings/10-unicode/es/README.md rename to modules/31-advanced-strings/100-unicode/es/README.md diff --git a/modules/60-deep-into-strings/10-unicode/es/data.yml b/modules/31-advanced-strings/100-unicode/es/data.yml similarity index 100% rename from modules/60-deep-into-strings/10-unicode/es/data.yml rename to modules/31-advanced-strings/100-unicode/es/data.yml diff --git a/modules/31-advanced-strings/100-unicode/ru/EXERCISE.md b/modules/31-advanced-strings/100-unicode/ru/EXERCISE.md new file mode 100644 index 00000000..7b9bbbca --- /dev/null +++ b/modules/31-advanced-strings/100-unicode/ru/EXERCISE.md @@ -0,0 +1,3 @@ +Выведите на экран длину строки `Привет!` двумя способами: сначала с помощью функции `strlen()`, затем — `mb_strlen()`. Каждое значение должно быть на своей строке. + +Так вы своими глазами увидите разницу между количеством байтов и количеством символов в юникод-строке. diff --git a/modules/60-deep-into-strings/10-unicode/ru/README.md b/modules/31-advanced-strings/100-unicode/ru/README.md similarity index 95% rename from modules/60-deep-into-strings/10-unicode/ru/README.md rename to modules/31-advanced-strings/100-unicode/ru/README.md index e0eecfae..4f1e9583 100644 --- a/modules/60-deep-into-strings/10-unicode/ru/README.md +++ b/modules/31-advanced-strings/100-unicode/ru/README.md @@ -1,4 +1,4 @@ -Данные программы хранятся в памяти компьютера в виде последовательности нулей и единиц. На этом уровне нет разницы между строками, числами или булевыми значениями. В памяти все выглядит одинаково. Разница появляется только в результате интерпретации. +Данные программы хранятся в памяти компьютера в виде последовательности нулей и единиц. На этом уровне нет разницы между строками и числами. В памяти все выглядит одинаково. Разница появляется только в результате интерпретации. Программа знает, что внутри некоторой переменной хранится строка, поэтому она берет нули и единички и пропускает их сквозь кодовую таблицу. В ней указано, какому числу соответствует какая буква. В результате программист видит строку. В этом уроке мы обсудим, как работают такие кодовые таблицы. @@ -42,7 +42,7 @@ ```php 13 +print_r(strlen('Привет!')); // => 13 ``` Языки разделились на два лагеря. Одни языки встроили поддержку в уже существующие функции — в итоге переход на UTF-8 никак не отразился на процессе программирования. Среди таких языков есть Java, Ruby, JavaScript. @@ -52,7 +52,7 @@ echo strlen('Привет!'); // => 13 ```php 7 +print_r(mb_strlen('Привет!')); // => 7 ``` А вот достойной альтернативы взятию конкретного символа в строке по индексу не существует. Такую задачу нужно выполнять с помощью функции `mb_substr()`: diff --git a/modules/60-deep-into-strings/10-unicode/ru/data.yml b/modules/31-advanced-strings/100-unicode/ru/data.yml similarity index 100% rename from modules/60-deep-into-strings/10-unicode/ru/data.yml rename to modules/31-advanced-strings/100-unicode/ru/data.yml diff --git a/modules/30-variables/25-interpolation/Makefile b/modules/31-advanced-strings/110-locales/Makefile similarity index 100% rename from modules/30-variables/25-interpolation/Makefile rename to modules/31-advanced-strings/110-locales/Makefile diff --git a/modules/60-deep-into-strings/30-locales/index.php b/modules/31-advanced-strings/110-locales/Solution.php similarity index 100% rename from modules/60-deep-into-strings/30-locales/index.php rename to modules/31-advanced-strings/110-locales/Solution.php diff --git a/modules/60-deep-into-strings/30-locales/SolutionTest.php b/modules/31-advanced-strings/110-locales/SolutionTest.php similarity index 62% rename from modules/60-deep-into-strings/30-locales/SolutionTest.php rename to modules/31-advanced-strings/110-locales/SolutionTest.php index 117c8d06..358fc408 100644 --- a/modules/60-deep-into-strings/30-locales/SolutionTest.php +++ b/modules/31-advanced-strings/110-locales/SolutionTest.php @@ -1,8 +1,8 @@ expectOutputString($expected); - require 'index.php'; } } diff --git a/modules/60-deep-into-strings/30-locales/description.es.yml b/modules/31-advanced-strings/110-locales/description.es.yml similarity index 100% rename from modules/60-deep-into-strings/30-locales/description.es.yml rename to modules/31-advanced-strings/110-locales/description.es.yml diff --git a/modules/60-deep-into-strings/30-locales/en/EXERCISE.md b/modules/31-advanced-strings/110-locales/en/EXERCISE.md similarity index 100% rename from modules/60-deep-into-strings/30-locales/en/EXERCISE.md rename to modules/31-advanced-strings/110-locales/en/EXERCISE.md diff --git a/modules/60-deep-into-strings/30-locales/en/README.md b/modules/31-advanced-strings/110-locales/en/README.md similarity index 100% rename from modules/60-deep-into-strings/30-locales/en/README.md rename to modules/31-advanced-strings/110-locales/en/README.md diff --git a/modules/60-deep-into-strings/30-locales/en/data.yml b/modules/31-advanced-strings/110-locales/en/data.yml similarity index 100% rename from modules/60-deep-into-strings/30-locales/en/data.yml rename to modules/31-advanced-strings/110-locales/en/data.yml diff --git a/modules/60-deep-into-strings/30-locales/es/EXERCISE.md b/modules/31-advanced-strings/110-locales/es/EXERCISE.md similarity index 100% rename from modules/60-deep-into-strings/30-locales/es/EXERCISE.md rename to modules/31-advanced-strings/110-locales/es/EXERCISE.md diff --git a/modules/60-deep-into-strings/30-locales/es/README.md b/modules/31-advanced-strings/110-locales/es/README.md similarity index 100% rename from modules/60-deep-into-strings/30-locales/es/README.md rename to modules/31-advanced-strings/110-locales/es/README.md diff --git a/modules/60-deep-into-strings/30-locales/es/data.yml b/modules/31-advanced-strings/110-locales/es/data.yml similarity index 100% rename from modules/60-deep-into-strings/30-locales/es/data.yml rename to modules/31-advanced-strings/110-locales/es/data.yml diff --git a/modules/60-deep-into-strings/30-locales/ru/EXERCISE.md b/modules/31-advanced-strings/110-locales/ru/EXERCISE.md similarity index 100% rename from modules/60-deep-into-strings/30-locales/ru/EXERCISE.md rename to modules/31-advanced-strings/110-locales/ru/EXERCISE.md diff --git a/modules/60-deep-into-strings/30-locales/ru/README.md b/modules/31-advanced-strings/110-locales/ru/README.md similarity index 100% rename from modules/60-deep-into-strings/30-locales/ru/README.md rename to modules/31-advanced-strings/110-locales/ru/README.md diff --git a/modules/60-deep-into-strings/30-locales/ru/data.yml b/modules/31-advanced-strings/110-locales/ru/data.yml similarity index 100% rename from modules/60-deep-into-strings/30-locales/ru/data.yml rename to modules/31-advanced-strings/110-locales/ru/data.yml diff --git a/modules/30-variables/30-symbols/Makefile b/modules/31-advanced-strings/120-startwith/Makefile similarity index 100% rename from modules/30-variables/30-symbols/Makefile rename to modules/31-advanced-strings/120-startwith/Makefile diff --git a/modules/31-advanced-strings/120-startwith/Solution.php b/modules/31-advanced-strings/120-startwith/Solution.php new file mode 100644 index 00000000..32cf84d6 --- /dev/null +++ b/modules/31-advanced-strings/120-startwith/Solution.php @@ -0,0 +1,5 @@ +expectOutputString($expected); - require 'index.php'; } } diff --git a/modules/60-deep-into-strings/40-startwith/description.es.yml b/modules/31-advanced-strings/120-startwith/description.es.yml similarity index 100% rename from modules/60-deep-into-strings/40-startwith/description.es.yml rename to modules/31-advanced-strings/120-startwith/description.es.yml diff --git a/modules/60-deep-into-strings/40-startwith/en/EXERCISE.md b/modules/31-advanced-strings/120-startwith/en/EXERCISE.md similarity index 100% rename from modules/60-deep-into-strings/40-startwith/en/EXERCISE.md rename to modules/31-advanced-strings/120-startwith/en/EXERCISE.md diff --git a/modules/60-deep-into-strings/40-startwith/en/README.md b/modules/31-advanced-strings/120-startwith/en/README.md similarity index 100% rename from modules/60-deep-into-strings/40-startwith/en/README.md rename to modules/31-advanced-strings/120-startwith/en/README.md diff --git a/modules/60-deep-into-strings/40-startwith/en/data.yml b/modules/31-advanced-strings/120-startwith/en/data.yml similarity index 100% rename from modules/60-deep-into-strings/40-startwith/en/data.yml rename to modules/31-advanced-strings/120-startwith/en/data.yml diff --git a/modules/60-deep-into-strings/40-startwith/es/EXERCISE.md b/modules/31-advanced-strings/120-startwith/es/EXERCISE.md similarity index 100% rename from modules/60-deep-into-strings/40-startwith/es/EXERCISE.md rename to modules/31-advanced-strings/120-startwith/es/EXERCISE.md diff --git a/modules/60-deep-into-strings/40-startwith/es/README.md b/modules/31-advanced-strings/120-startwith/es/README.md similarity index 100% rename from modules/60-deep-into-strings/40-startwith/es/README.md rename to modules/31-advanced-strings/120-startwith/es/README.md diff --git a/modules/60-deep-into-strings/40-startwith/es/data.yml b/modules/31-advanced-strings/120-startwith/es/data.yml similarity index 100% rename from modules/60-deep-into-strings/40-startwith/es/data.yml rename to modules/31-advanced-strings/120-startwith/es/data.yml diff --git a/modules/31-advanced-strings/120-startwith/ru/EXERCISE.md b/modules/31-advanced-strings/120-startwith/ru/EXERCISE.md new file mode 100644 index 00000000..623d938c --- /dev/null +++ b/modules/31-advanced-strings/120-startwith/ru/EXERCISE.md @@ -0,0 +1,3 @@ +В программе нужно вырезать из адреса `https://hexlet.io/courses` имя раздела. Первый шаг — узнать, где оно начинается. + +Выведите на экран позицию, с которой в строке `https://hexlet.io/courses` начинается подстрока `courses`. Используйте функцию `mb_strpos()`. diff --git a/modules/31-advanced-strings/120-startwith/ru/README.md b/modules/31-advanced-strings/120-startwith/ru/README.md new file mode 100644 index 00000000..292ec10c --- /dev/null +++ b/modules/31-advanced-strings/120-startwith/ru/README.md @@ -0,0 +1,27 @@ +Часто в работе со строками нужно определить, входит ли одна строка — **подстрока** — в другую, и если входит, то где. Для этого в PHP есть функция [mb_strpos()](https://php.net/manual/ru/function.mb-strpos.php). Она ищет позицию первого вхождения одной строки в другую: + +```php + 6 +``` + +Функция вернула `6` — индекс буквы `М`, с которой начинается подстрока. Индексы, как обычно, отсчитываются с нуля: + +```php + 0 +``` + +Здесь вернулся `0`: подстрока найдена в самом начале строки. + +Если же подстрока не найдена, `mb_strpos()` возвращает специальное значение `false` — «ложь». При выводе через `print_r()` оно выглядит как пустая строка: + +```php + +``` + +Здесь скрыта ловушка, в которую часто попадают новички: результат `0` («найдено в начале строки») легко спутать с `false` («не найдено вообще»). Чтобы различать их, нужно строгое сравнение — мы разберем его в уроках про логику. А пока запомните: `mb_strpos()` отвечает на вопрос «где?», а не «есть ли?». diff --git a/modules/60-deep-into-strings/40-startwith/ru/data.yml b/modules/31-advanced-strings/120-startwith/ru/data.yml similarity index 100% rename from modules/60-deep-into-strings/40-startwith/ru/data.yml rename to modules/31-advanced-strings/120-startwith/ru/data.yml diff --git a/modules/35-calling-functions/120-function-signature/Makefile b/modules/31-advanced-strings/25-interpolation/Makefile similarity index 100% rename from modules/35-calling-functions/120-function-signature/Makefile rename to modules/31-advanced-strings/25-interpolation/Makefile diff --git a/modules/31-advanced-strings/25-interpolation/Solution.php b/modules/31-advanced-strings/25-interpolation/Solution.php new file mode 100644 index 00000000..f90f5d6d --- /dev/null +++ b/modules/31-advanced-strings/25-interpolation/Solution.php @@ -0,0 +1,8 @@ +expectOutputString($expected); + } +} diff --git a/modules/30-variables/25-interpolation/description.es.yml b/modules/31-advanced-strings/25-interpolation/description.es.yml similarity index 100% rename from modules/30-variables/25-interpolation/description.es.yml rename to modules/31-advanced-strings/25-interpolation/description.es.yml diff --git a/modules/30-variables/25-interpolation/en/EXERCISE.md b/modules/31-advanced-strings/25-interpolation/en/EXERCISE.md similarity index 100% rename from modules/30-variables/25-interpolation/en/EXERCISE.md rename to modules/31-advanced-strings/25-interpolation/en/EXERCISE.md diff --git a/modules/30-variables/25-interpolation/en/README.md b/modules/31-advanced-strings/25-interpolation/en/README.md similarity index 100% rename from modules/30-variables/25-interpolation/en/README.md rename to modules/31-advanced-strings/25-interpolation/en/README.md diff --git a/modules/30-variables/25-interpolation/en/data.yml b/modules/31-advanced-strings/25-interpolation/en/data.yml similarity index 100% rename from modules/30-variables/25-interpolation/en/data.yml rename to modules/31-advanced-strings/25-interpolation/en/data.yml diff --git a/modules/30-variables/25-interpolation/es/EXERCISE.md b/modules/31-advanced-strings/25-interpolation/es/EXERCISE.md similarity index 100% rename from modules/30-variables/25-interpolation/es/EXERCISE.md rename to modules/31-advanced-strings/25-interpolation/es/EXERCISE.md diff --git a/modules/30-variables/25-interpolation/es/README.md b/modules/31-advanced-strings/25-interpolation/es/README.md similarity index 100% rename from modules/30-variables/25-interpolation/es/README.md rename to modules/31-advanced-strings/25-interpolation/es/README.md diff --git a/modules/30-variables/25-interpolation/es/data.yml b/modules/31-advanced-strings/25-interpolation/es/data.yml similarity index 100% rename from modules/30-variables/25-interpolation/es/data.yml rename to modules/31-advanced-strings/25-interpolation/es/data.yml diff --git a/modules/31-advanced-strings/25-interpolation/ru/EXERCISE.md b/modules/31-advanced-strings/25-interpolation/ru/EXERCISE.md new file mode 100644 index 00000000..091a230d --- /dev/null +++ b/modules/31-advanced-strings/25-interpolation/ru/EXERCISE.md @@ -0,0 +1,7 @@ +Интернет-магазин отправляет покупателю подтверждение заказа. Имя покупателя и номер заказа уже хранятся в переменных — нужно подставить их в шаблон сообщения с помощью интерполяции. + +Используйте переменные `$username` и `$orderNumber`, чтобы вывести на экран: + +```text +Здравствуйте, Анна! Ваш заказ #1337 принят. +``` diff --git a/modules/31-advanced-strings/25-interpolation/ru/README.md b/modules/31-advanced-strings/25-interpolation/ru/README.md new file mode 100644 index 00000000..f6a05e19 --- /dev/null +++ b/modules/31-advanced-strings/25-interpolation/ru/README.md @@ -0,0 +1,81 @@ +Вспомним, как работает конкатенация. Для этого мы соединяем нужные строки (или переменные со строками внутри) с помощью точки `.`. + +```php + Hello, Joffrey! +``` + +Но при этом в сложных выражениях становится трудно сразу увидеть, какой текст получится на выходе. Особенно если в строке используются пробелы, запятые или кавычки: они начинают мешать восприятию. Даже текущий пример требует небольшого напряжения, чтобы понять, какая получится строка. + +По этой причине во многих языках существует операция, которая называется интерполяцией. Интерполяция представляет собой способ встраивать значения переменных прямо внутрь строки. В PHP она работает в строках с двойными кавычками. Вот так: + +```php + Hello, Joffrey! +``` + +Имена переменных записываются внутри строки в фигурных скобках, и PHP автоматически подставляет нужные значения: + +```text +$firstName = 'Joff' +$greeting = 'Hello' + +"{$greeting}, {$firstName}!" + └────┬────┘ └────┬─────┘ + 'Hello' 'Joff' + └──────┬──────┘ + 'Hello, Joff!' +``` + +Сравните эти два примера рядом: + +```php + Hello, {$firstName}! +``` + +## Пример + +```php + Hexlet - online courses +``` + +Такая запись легко читается: пробелы, дефисы и символы видны сразу. Строка выглядит именно так, как она появится в выводе. Это делает код понятным и удобным в поддержке. По этой причине в большинстве языков интерполяция является более предпочтительной, чем конкатенация. + +## Почему это важно + +Интерполяция предпочтительнее конкатенации почти во всех современных языках программирования. Она: + +- Упрощает структуру строк. +- Улучшает читаемость кода. +- Снижает количество ошибок при работе с пробелами и знаками препинания. diff --git a/modules/31-advanced-strings/25-interpolation/ru/data.yml b/modules/31-advanced-strings/25-interpolation/ru/data.yml new file mode 100644 index 00000000..8dc1df0e --- /dev/null +++ b/modules/31-advanced-strings/25-interpolation/ru/data.yml @@ -0,0 +1,11 @@ +--- +name: Интерполяция +tips: + - > + [Интерполяция строк в + PHP](https://www.php.net/manual/ru/language.types.string.php#language.types.string.parsing) +definitions: + - name: Интерполяция + description: >- + способ получения сложной строки из нескольких простых с использованием + специальных шаблонов. Например, `\"Hi, {$name}!\"`. diff --git a/modules/35-calling-functions/135-calling-functions-default-arguments/Makefile b/modules/31-advanced-strings/30-symbols/Makefile similarity index 100% rename from modules/35-calling-functions/135-calling-functions-default-arguments/Makefile rename to modules/31-advanced-strings/30-symbols/Makefile diff --git a/modules/31-advanced-strings/30-symbols/Solution.php b/modules/31-advanced-strings/30-symbols/Solution.php new file mode 100644 index 00000000..800066a9 --- /dev/null +++ b/modules/31-advanced-strings/30-symbols/Solution.php @@ -0,0 +1,7 @@ +expectOutputString($expected); + } +} diff --git a/modules/30-variables/30-symbols/description.es.yml b/modules/31-advanced-strings/30-symbols/description.es.yml similarity index 100% rename from modules/30-variables/30-symbols/description.es.yml rename to modules/31-advanced-strings/30-symbols/description.es.yml diff --git a/modules/30-variables/30-symbols/en/EXERCISE.md b/modules/31-advanced-strings/30-symbols/en/EXERCISE.md similarity index 100% rename from modules/30-variables/30-symbols/en/EXERCISE.md rename to modules/31-advanced-strings/30-symbols/en/EXERCISE.md diff --git a/modules/30-variables/30-symbols/en/README.md b/modules/31-advanced-strings/30-symbols/en/README.md similarity index 100% rename from modules/30-variables/30-symbols/en/README.md rename to modules/31-advanced-strings/30-symbols/en/README.md diff --git a/modules/30-variables/30-symbols/en/data.yml b/modules/31-advanced-strings/30-symbols/en/data.yml similarity index 100% rename from modules/30-variables/30-symbols/en/data.yml rename to modules/31-advanced-strings/30-symbols/en/data.yml diff --git a/modules/30-variables/30-symbols/es/EXERCISE.md b/modules/31-advanced-strings/30-symbols/es/EXERCISE.md similarity index 100% rename from modules/30-variables/30-symbols/es/EXERCISE.md rename to modules/31-advanced-strings/30-symbols/es/EXERCISE.md diff --git a/modules/30-variables/30-symbols/es/README.md b/modules/31-advanced-strings/30-symbols/es/README.md similarity index 100% rename from modules/30-variables/30-symbols/es/README.md rename to modules/31-advanced-strings/30-symbols/es/README.md diff --git a/modules/30-variables/30-symbols/es/data.yml b/modules/31-advanced-strings/30-symbols/es/data.yml similarity index 100% rename from modules/30-variables/30-symbols/es/data.yml rename to modules/31-advanced-strings/30-symbols/es/data.yml diff --git a/modules/31-advanced-strings/30-symbols/ru/EXERCISE.md b/modules/31-advanced-strings/30-symbols/ru/EXERCISE.md new file mode 100644 index 00000000..7cf55f2b --- /dev/null +++ b/modules/31-advanced-strings/30-symbols/ru/EXERCISE.md @@ -0,0 +1 @@ +В переменной `$text` спрятано секретное слово. Извлеките нужные символы из переменной по индексам, соедините их и выведите на экран слово `grip`. diff --git a/modules/31-advanced-strings/30-symbols/ru/README.md b/modules/31-advanced-strings/30-symbols/ru/README.md new file mode 100644 index 00000000..f24ff8b3 --- /dev/null +++ b/modules/31-advanced-strings/30-symbols/ru/README.md @@ -0,0 +1,110 @@ +Иногда нужно получить один символ из строки. Например, если сайт знает имя и фамилию пользователя и нужно вывести их в сокращенном формате вида A. Ivanov. Для этого потребуется взять первую букву имени. + +![Извлечение символов из строки](./assets/symbols.png) + +В PHP для доступа к символам строки используют индексацию. Индексация означает, что у каждого символа в строке есть свой номер, то есть индекс. Индексация начинается с нуля: у первого символа индекс `0`, у второго `1` и так далее. Представим, что у нас есть строка: + +```php + A +``` + +Квадратные скобки с индексом внутри — это специальный оператор извлечения символа из строки. Индексы в PHP (и во многих языках) начинаются с нуля: + +```text +Символ A l e x a n d e r +Индекс 0 1 2 3 4 5 6 7 8 +``` + +Длина строки `Alexander` равна `9`, поэтому индекс последнего символа равен `8`, то есть `9 - 1`. + +Чтобы получить, например, последний символ, можно написать: + +```php + r +``` + +Если изменится длина строки, то последний элемент тоже сдвинется и придется указывать новый индекс, по которому расположен этот символ. + +А если выйти за границы строки, PHP сообщит о проблеме: + +```php + r, последний символ +print_r($firstName[-2]); // => e, предпоследний символ +``` + +```text +Строка: 'H' 'e' 'x' 'l' 'e' 't' +Индекс: 0 1 2 3 4 5 +С конца: -6 -5 -4 -3 -2 -1 +``` + +Отрицательные индексы работают так: + +- -1 соответствует последнему символу +- -2 соответствует предпоследнему +- и так далее + +Это удобно и безопасно, потому что работает правильно, даже если строка меняет свою длину. + +Индекс можно хранить в переменной: + +```php + A +``` + +Такой подход полезен, когда индекс вычисляется где-то в коде, а потом используется для доступа к нужному символу. + +## Спецсимволы + +При индексации учитываются обычные буквы, знаки и спецсимволы. Все они занимают позицию в строке и имеют свой индекс, даже если их "не видно" на экране. + +Например, в строке `"\nyou"` первый символ представляет собой `\n` (перенос строки), а под индексом 1 уже идет буква `y`. Поэтому обращение `$magic[1]` вернет именно `y`. Обратите внимание на двойные кавычки: в одинарных кавычках `\n` остался бы двумя отдельными символами — обратным слешем и буквой `n`. + +## Подумайте: что выведет этот код? + +```php + ? +``` + +Вывод будет: + +```text +y +``` diff --git a/modules/31-advanced-strings/30-symbols/ru/assets/symbols.png b/modules/31-advanced-strings/30-symbols/ru/assets/symbols.png new file mode 100644 index 00000000..6093469e Binary files /dev/null and b/modules/31-advanced-strings/30-symbols/ru/assets/symbols.png differ diff --git a/modules/31-advanced-strings/30-symbols/ru/data.yml b/modules/31-advanced-strings/30-symbols/ru/data.yml new file mode 100644 index 00000000..b16dee92 --- /dev/null +++ b/modules/31-advanced-strings/30-symbols/ru/data.yml @@ -0,0 +1,6 @@ +--- +name: Извлечение символов из строки +tips: [] +definitions: + - name: Индекс + description: позиция символа внутри строки. diff --git a/modules/35-calling-functions/180-variadic-arguments/Makefile b/modules/31-advanced-strings/70-slices/Makefile similarity index 100% rename from modules/35-calling-functions/180-variadic-arguments/Makefile rename to modules/31-advanced-strings/70-slices/Makefile diff --git a/modules/31-advanced-strings/70-slices/Solution.php b/modules/31-advanced-strings/70-slices/Solution.php new file mode 100644 index 00000000..9a5f0349 --- /dev/null +++ b/modules/31-advanced-strings/70-slices/Solution.php @@ -0,0 +1,7 @@ +expectOutputString($expected); + } +} diff --git a/modules/31-advanced-strings/70-slices/description.es.yml b/modules/31-advanced-strings/70-slices/description.es.yml new file mode 100644 index 00000000..81bff07c --- /dev/null +++ b/modules/31-advanced-strings/70-slices/description.es.yml @@ -0,0 +1,32 @@ +--- + +name: Subcadenas +theory: | + Usa `substr()` para extraer parte de una cadena. El formato es `substr(cadena, inicio, longitud)`: + + ```php + World! + print_r(substr($text, 7, 5)); // => World + print_r(substr($text, -6)); // => World! (el índice negativo cuenta desde el final) + ``` + + Si se omite la longitud, PHP toma todo desde el índice inicial hasta el final de la cadena. + +instructions: | + Dada la variable `$url = 'https://hexlet.io'`, extrae e imprime el dominio sin el protocolo usando `substr()`: + + ```text + hexlet.io + ``` + +tips: + - > + [Función substr](https://www.php.net/manual/es/function.substr.php) + +definitions: + - name: Subcadena + description: >- + una parte de una cadena extraída según los parámetros dados: inicio y longitud. diff --git a/modules/31-advanced-strings/70-slices/en/EXERCISE.md b/modules/31-advanced-strings/70-slices/en/EXERCISE.md new file mode 100644 index 00000000..9a507b31 --- /dev/null +++ b/modules/31-advanced-strings/70-slices/en/EXERCISE.md @@ -0,0 +1,5 @@ +Given `$url = 'https://hexlet.io'`, extract and print the domain without the protocol using `substr()`: + +```text +hexlet.io +``` diff --git a/modules/31-advanced-strings/70-slices/en/README.md b/modules/31-advanced-strings/70-slices/en/README.md new file mode 100644 index 00000000..8965ba0d --- /dev/null +++ b/modules/31-advanced-strings/70-slices/en/README.md @@ -0,0 +1,12 @@ +Use `substr()` to extract part of a string. The format is `substr(string, start, length)`: + +```php + World! +print_r(substr($text, 7, 5)); // => World +print_r(substr($text, -6)); // => World! (negative index counts from the end) +``` + +If the length is omitted, PHP takes everything from the start index to the end of the string. diff --git a/modules/31-advanced-strings/70-slices/en/data.yml b/modules/31-advanced-strings/70-slices/en/data.yml new file mode 100644 index 00000000..7357bd89 --- /dev/null +++ b/modules/31-advanced-strings/70-slices/en/data.yml @@ -0,0 +1,9 @@ +--- +name: Substrings +tips: + - > + [substr function](https://www.php.net/manual/en/function.substr.php) +definitions: + - name: Substring + description: >- + a part of a string extracted by the given parameters: start and length. diff --git a/modules/31-advanced-strings/70-slices/es/EXERCISE.md b/modules/31-advanced-strings/70-slices/es/EXERCISE.md new file mode 100644 index 00000000..24e4cdb2 --- /dev/null +++ b/modules/31-advanced-strings/70-slices/es/EXERCISE.md @@ -0,0 +1,5 @@ +Dada la variable `$url = 'https://hexlet.io'`, extrae e imprime el dominio sin el protocolo usando `substr()`: + +```text +hexlet.io +``` diff --git a/modules/31-advanced-strings/70-slices/es/README.md b/modules/31-advanced-strings/70-slices/es/README.md new file mode 100644 index 00000000..31b04736 --- /dev/null +++ b/modules/31-advanced-strings/70-slices/es/README.md @@ -0,0 +1,12 @@ +Usa `substr()` para extraer parte de una cadena. El formato es `substr(cadena, inicio, longitud)`: + +```php + World! +print_r(substr($text, 7, 5)); // => World +print_r(substr($text, -6)); // => World! (el índice negativo cuenta desde el final) +``` + +Si se omite la longitud, PHP toma todo desde el índice inicial hasta el final de la cadena. diff --git a/modules/31-advanced-strings/70-slices/es/data.yml b/modules/31-advanced-strings/70-slices/es/data.yml new file mode 100644 index 00000000..c42e4492 --- /dev/null +++ b/modules/31-advanced-strings/70-slices/es/data.yml @@ -0,0 +1,9 @@ +--- +name: Subcadenas +tips: + - > + [Función substr](https://www.php.net/manual/es/function.substr.php) +definitions: + - name: Subcadena + description: >- + una parte de una cadena extraída según los parámetros dados: inicio y longitud. diff --git a/modules/31-advanced-strings/70-slices/ru/EXERCISE.md b/modules/31-advanced-strings/70-slices/ru/EXERCISE.md new file mode 100644 index 00000000..37f156fd --- /dev/null +++ b/modules/31-advanced-strings/70-slices/ru/EXERCISE.md @@ -0,0 +1 @@ +Программа получает полный адрес сайта и должна выделить из него только имя домена — без протокола `https://`. В переменной `$url` хранится адрес `https://hexlet.io`. Извлеките с помощью `substr()` доменное имя `hexlet.io` и выведите на экран. Задание можно сделать разными способами. diff --git a/modules/31-advanced-strings/70-slices/ru/README.md b/modules/31-advanced-strings/70-slices/ru/README.md new file mode 100644 index 00000000..b5fc9dab --- /dev/null +++ b/modules/31-advanced-strings/70-slices/ru/README.md @@ -0,0 +1,150 @@ +Работая со строками, мы часто сталкиваемся с задачей: извлечь часть строки. Например, получить год из даты, имя из полного ФИО или первые несколько символов из адреса электронной почты. Для таких случаев в PHP существует удобный инструмент: встроенная функция `substr()`. + +## Что такое подстрока? + +Подстрока является частью строки. То, что входит внутрь другой строки. Например, в строке `'12-08-2034'` подстрокой может быть `'2034'`, `'12'` или даже `'-'`. Все зависит от того, какую информацию нам нужно извлечь. + +Допустим, у нас есть строка с датой `'12-08-2034'`. Мы хотим получить из нее только год `'2034'`. В этой строке каждый символ имеет индекс (позицию), начиная с нуля: + +```text +'1' '2' '-' '0' '8' '-' '2' '0' '3' '4' + 0 1 2 3 4 5 6 7 8 9 +``` + +Получается, год начинается с индекса 6 и состоит из четырех символов. Чтобы извлечь его, мы используем `substr()`: + +```php + 2034 +``` + +Запись `substr($value, 6, 4)` означает: взять из строки `$value` четыре символа, начиная с индекса 6. Формат: + +```text +substr(строка, начало, длина) +``` + +Обратите внимание: третий параметр задает не индекс конца, а количество символов, которое нужно взять. + +```php + basics (6 символов с индекса 5) +print_r(substr($value, 0, 7)); // => code-ba (7 символов с начала) +print_r(substr($value, 2, 4)); // => de-b +``` + +Как все это считать? Если мы работаем с конкретной строкой, то почти всегда это делается на глаз. + +## Подстрока является строкой + +```php + 1 +substr($value, 3, 2); // => 12 +``` + +`substr()` всегда возвращает строку, даже если в ней только цифры. Это значит, что результат можно использовать, как обычную строку: конкатенировать, печатать, интерполировать и так далее. В том числе из него можно извлечь новую подстроку: + +```php + 12-9 +print_r(substr($part, 0, 2)); // => 12 +``` + +Сначала мы получили подстроку `'12-9'`, а потом извлекли из нее новую подстроку `'12'`. + +## Подстрока до конца или с начала + +Иногда нужно взять часть строки до конца или от начала. Такие ситуации тоже легко обрабатываются: + +```php + let (с индекса 3 до конца) +print_r(substr($value, 0, 3)); // => Hex (от начала, три символа) +``` + +Если длину не указать, PHP сам возьмет все символы от начального индекса до конца строки. + +## Отрицательные индексы + +PHP позволяет считать не только слева направо, но и с конца строки. Для этого используются отрицательные значения: + +```php + t (последний символ) +print_r(substr($value, -3)); // => let (последние три символа) +print_r(substr($value, 1, -1)); // => exle (с индекса 1 до предпоследнего символа) +``` + +Отрицательное начало означает отсчет от конца строки: `-1` соответствует последнему символу, `-2` — предпоследнему и так далее. Отрицательная длина означает «взять все, кроме указанного количества символов с конца». + +Это удобно, когда заранее неизвестна длина строки, но нужно взять «хвост» или «середину» строки относительно конца. + +## Переворот строки + +В некоторых языках, например в Python, у срезов строк есть параметр «шаг», с помощью которого можно взять каждый второй символ или перевернуть строку. У `substr()` шага нет, но для переворота строки в PHP есть отдельная встроенная функция `strrev()`: + +```php + telxeH +``` + +## Подстрока с переменными + +Параметры `substr()` не обязаны быть жестко зафиксированы числами. Можно использовать переменные: + +```php + exle +``` + +Это особенно полезно, когда границы вычисляются во время работы программы. + +## Осторожно: кириллица + +Функция `substr()` работает с байтами, а не с символами. Для латиницы это одно и то же, но символы кириллицы и других нелатинских алфавитов занимают больше одного байта. Для таких строк используется функция `mb_substr()` — подробнее о работе с кодировками мы поговорим в конце курса. + +## Быстрая шпаргалка + +```php + + [Функция substr](https://www.php.net/manual/ru/function.substr.php) +definitions: + - name: Подстрока + description: >- + часть строки, извлеченная по указанным параметрам: началу и длине. diff --git a/modules/27-data-types/40-primitive-data-types/Makefile b/modules/31-advanced-strings/90-multiline-strings/Makefile similarity index 100% rename from modules/27-data-types/40-primitive-data-types/Makefile rename to modules/31-advanced-strings/90-multiline-strings/Makefile diff --git a/modules/31-advanced-strings/90-multiline-strings/Solution.php b/modules/31-advanced-strings/90-multiline-strings/Solution.php new file mode 100644 index 00000000..24c25c8d --- /dev/null +++ b/modules/31-advanced-strings/90-multiline-strings/Solution.php @@ -0,0 +1,12 @@ +expectOutputString($expected); + } +} diff --git a/modules/30-variables/35-heredoc/description.es.yml b/modules/31-advanced-strings/90-multiline-strings/description.es.yml similarity index 100% rename from modules/30-variables/35-heredoc/description.es.yml rename to modules/31-advanced-strings/90-multiline-strings/description.es.yml diff --git a/modules/30-variables/35-heredoc/en/EXERCISE.md b/modules/31-advanced-strings/90-multiline-strings/en/EXERCISE.md similarity index 100% rename from modules/30-variables/35-heredoc/en/EXERCISE.md rename to modules/31-advanced-strings/90-multiline-strings/en/EXERCISE.md diff --git a/modules/30-variables/35-heredoc/en/README.md b/modules/31-advanced-strings/90-multiline-strings/en/README.md similarity index 100% rename from modules/30-variables/35-heredoc/en/README.md rename to modules/31-advanced-strings/90-multiline-strings/en/README.md diff --git a/modules/30-variables/35-heredoc/en/data.yml b/modules/31-advanced-strings/90-multiline-strings/en/data.yml similarity index 100% rename from modules/30-variables/35-heredoc/en/data.yml rename to modules/31-advanced-strings/90-multiline-strings/en/data.yml diff --git a/modules/30-variables/35-heredoc/es/EXERCISE.md b/modules/31-advanced-strings/90-multiline-strings/es/EXERCISE.md similarity index 100% rename from modules/30-variables/35-heredoc/es/EXERCISE.md rename to modules/31-advanced-strings/90-multiline-strings/es/EXERCISE.md diff --git a/modules/30-variables/35-heredoc/es/README.md b/modules/31-advanced-strings/90-multiline-strings/es/README.md similarity index 100% rename from modules/30-variables/35-heredoc/es/README.md rename to modules/31-advanced-strings/90-multiline-strings/es/README.md diff --git a/modules/30-variables/35-heredoc/es/data.yml b/modules/31-advanced-strings/90-multiline-strings/es/data.yml similarity index 100% rename from modules/30-variables/35-heredoc/es/data.yml rename to modules/31-advanced-strings/90-multiline-strings/es/data.yml diff --git a/modules/31-advanced-strings/90-multiline-strings/ru/EXERCISE.md b/modules/31-advanced-strings/90-multiline-strings/ru/EXERCISE.md new file mode 100644 index 00000000..f6ee838b --- /dev/null +++ b/modules/31-advanced-strings/90-multiline-strings/ru/EXERCISE.md @@ -0,0 +1,8 @@ +Интернет-магазин хранит текст письма о статусе заказа в переменной и отправляет его покупателю. Запишите в переменную `$text` текст письма, приведённый ниже. Используйте heredoc-синтаксис. Все переносы строк должны сохраниться. + +```text +Уважаемый пользователь! +Ваш заказ успешно оформлен. +Ожидаемая дата доставки: 3-5 рабочих дней. +Спасибо, что выбрали нас! +``` diff --git a/modules/31-advanced-strings/90-multiline-strings/ru/README.md b/modules/31-advanced-strings/90-multiline-strings/ru/README.md new file mode 100644 index 00000000..fdeb6cb4 --- /dev/null +++ b/modules/31-advanced-strings/90-multiline-strings/ru/README.md @@ -0,0 +1,106 @@ +Иногда текст в программе должен состоять из нескольких строк. Например, при генерации письма, создании шаблона, форматировании сообщения об ошибке или просто работе с длинными текстами. + +Конечно, можно использовать символ перевода строки `\n`, как мы делали раньше: + +```php + Hello, {$name}! +``` + +## Компьютер и человек воспринимают код по-разному + +PHP может обработать и строки с `\n`, и heredoc. Для интерпретатора это одно и то же. Но для человека, читающего код, heredoc намного удобнее и нагляднее. diff --git a/modules/31-advanced-strings/90-multiline-strings/ru/data.yml b/modules/31-advanced-strings/90-multiline-strings/ru/data.yml new file mode 100644 index 00000000..2a0195eb --- /dev/null +++ b/modules/31-advanced-strings/90-multiline-strings/ru/data.yml @@ -0,0 +1,8 @@ +--- +name: Многострочные строки +definitions: [] +tips: + - > + [Heredoc](https://www.php.net/manual/ru/language.types.string.php#language.types.string.syntax.heredoc) + - > + [Nowdoc](https://www.php.net/manual/ru/language.types.string.php#language.types.string.syntax.nowdoc) diff --git a/modules/31-advanced-strings/description.en.yml b/modules/31-advanced-strings/description.en.yml new file mode 100644 index 00000000..1f2b5c47 --- /dev/null +++ b/modules/31-advanced-strings/description.en.yml @@ -0,0 +1,5 @@ +--- + +name: Deeper Into Strings +description: + We continue studying strings and their relationship with variables. We cover interpolation, character extraction, substrings, and multiline strings. diff --git a/modules/31-advanced-strings/description.es.yml b/modules/31-advanced-strings/description.es.yml new file mode 100644 index 00000000..3b9f3636 --- /dev/null +++ b/modules/31-advanced-strings/description.es.yml @@ -0,0 +1,5 @@ +--- + +name: Más sobre cadenas de texto +description: + Continuamos aprendiendo sobre cadenas de texto y su relación con las variables. Exploramos la interpolación, la extracción de caracteres, las subcadenas y las cadenas multilínea. diff --git a/modules/31-advanced-strings/description.ru.yml b/modules/31-advanced-strings/description.ru.yml new file mode 100644 index 00000000..8946cc33 --- /dev/null +++ b/modules/31-advanced-strings/description.ru.yml @@ -0,0 +1,5 @@ +--- + +name: Глубже про строки +description: + Продолжаем изучать строки и их связь с переменными. Разбираем интерполяцию, извлечение символов, получение подстрок и многострочные строки. diff --git a/modules/27-data-types/50-data-types-weak-typing/Makefile b/modules/33-data-types/40-primitive-data-types/Makefile similarity index 100% rename from modules/27-data-types/50-data-types-weak-typing/Makefile rename to modules/33-data-types/40-primitive-data-types/Makefile diff --git a/modules/33-data-types/40-primitive-data-types/Solution.php b/modules/33-data-types/40-primitive-data-types/Solution.php new file mode 100644 index 00000000..ff0e42f5 --- /dev/null +++ b/modules/33-data-types/40-primitive-data-types/Solution.php @@ -0,0 +1,15 @@ +expectOutputString($expected); - require 'index.php'; } } diff --git a/modules/27-data-types/40-primitive-data-types/description.es.yml b/modules/33-data-types/40-primitive-data-types/description.es.yml similarity index 100% rename from modules/27-data-types/40-primitive-data-types/description.es.yml rename to modules/33-data-types/40-primitive-data-types/description.es.yml diff --git a/modules/27-data-types/40-primitive-data-types/en/EXERCISE.md b/modules/33-data-types/40-primitive-data-types/en/EXERCISE.md similarity index 100% rename from modules/27-data-types/40-primitive-data-types/en/EXERCISE.md rename to modules/33-data-types/40-primitive-data-types/en/EXERCISE.md diff --git a/modules/27-data-types/40-primitive-data-types/en/README.md b/modules/33-data-types/40-primitive-data-types/en/README.md similarity index 100% rename from modules/27-data-types/40-primitive-data-types/en/README.md rename to modules/33-data-types/40-primitive-data-types/en/README.md diff --git a/modules/27-data-types/40-primitive-data-types/en/data.yml b/modules/33-data-types/40-primitive-data-types/en/data.yml similarity index 100% rename from modules/27-data-types/40-primitive-data-types/en/data.yml rename to modules/33-data-types/40-primitive-data-types/en/data.yml diff --git a/modules/27-data-types/40-primitive-data-types/es/EXERCISE.md b/modules/33-data-types/40-primitive-data-types/es/EXERCISE.md similarity index 100% rename from modules/27-data-types/40-primitive-data-types/es/EXERCISE.md rename to modules/33-data-types/40-primitive-data-types/es/EXERCISE.md diff --git a/modules/27-data-types/40-primitive-data-types/es/README.md b/modules/33-data-types/40-primitive-data-types/es/README.md similarity index 100% rename from modules/27-data-types/40-primitive-data-types/es/README.md rename to modules/33-data-types/40-primitive-data-types/es/README.md diff --git a/modules/27-data-types/40-primitive-data-types/es/data.yml b/modules/33-data-types/40-primitive-data-types/es/data.yml similarity index 100% rename from modules/27-data-types/40-primitive-data-types/es/data.yml rename to modules/33-data-types/40-primitive-data-types/es/data.yml diff --git a/modules/33-data-types/40-primitive-data-types/ru/EXERCISE.md b/modules/33-data-types/40-primitive-data-types/ru/EXERCISE.md new file mode 100644 index 00000000..c55ade45 --- /dev/null +++ b/modules/33-data-types/40-primitive-data-types/ru/EXERCISE.md @@ -0,0 +1,22 @@ +В программе уже задан текущий год: + +```php + 5 +print_r(-5); // => -5 +``` + +Пример вывода строки: + +```php + 5 +print_r('-5'); // => -5 +``` + +На экране результат выглядит одинаково, но внутри программы это совершенно разные вещи: + +| Значение | Тип данных | +|----------|---------------------| +| `5` | `int` (целое число) | +| `'5'` | `string` (строка) | + +Число `5` и строка `'5'` — разные значения, и операции с ними работают по-разному. Правда, при несоответствии типов PHP часто пытается сам преобразовать один тип в другой. Насколько это удобно и чем опасно — разберем чуть позже в этом модуле. + +## Целые и рациональные числа + +PHP различает два вида чисел: + +- `int` обозначает целые числа: -3, 0, 7, 100000 +- `float` обозначает вещественные (рациональные) числа: 1.0, -3.14, 2.718 + +Такое разделение связано с особенностями устройства компьютеров — мы говорили об этом в уроке про числа с плавающей точкой. + +Пример: + +```php + 10.234 +print_r(-0.4); // => -0.4 +``` + +В них можно записывать дробные значения и использовать их в вычислениях: + +```php + 4.7 +print_r(5.0 / 2.0); // => 2.5 +print_r(2.75 - 0.5); // => 2.25 +``` + +## Примитивные типы + +Типы вроде: + +- string (строка), +- int (целое число), +- float (рациональное число) + +называются примитивными: они встроены прямо в сам язык PHP. + +```text +Примитивные типы PHP +├── int : целые числа (7, -3, 0) +├── float : дробные числа (3.14, -0.5) +├── string : строки ('hello') +└── bool : логический тип (true, false) +``` + +Кроме строк и чисел, в PHP есть булев тип `bool` со значениями `true` и `false`, а также специальное значение `null`. Подробнее мы столкнемся с ними в будущем. + +Существуют и составные типы: массивы, объекты и другие. С ними мы познакомимся позже. Более того, в PHP можно создавать и свои собственные типы (например, классы), но для начала важно хорошо разобраться с примитивами. + +## Строки и строчки + +По-английски строки в программировании называются **strings**, а строчки текстовых файлов — **lines**. В русском языке может быть путаница, поэтому во всех уроках мы будем говорить «строка» для обозначения типа данных «строка», и «строчка» — для lines в файлах. diff --git a/modules/27-data-types/40-primitive-data-types/ru/data.yml b/modules/33-data-types/40-primitive-data-types/ru/data.yml similarity index 92% rename from modules/27-data-types/40-primitive-data-types/ru/data.yml rename to modules/33-data-types/40-primitive-data-types/ru/data.yml index 6fba9029..f67d8a68 100644 --- a/modules/27-data-types/40-primitive-data-types/ru/data.yml +++ b/modules/33-data-types/40-primitive-data-types/ru/data.yml @@ -4,7 +4,7 @@ tips: - > [Литерал](https://ru.wikipedia.org/wiki/%D0%9B%D0%B8%D1%82%D0%B5%D1%80%D0%B0%D0%BB_(%D0%B8%D0%BD%D1%84%D0%BE%D1%80%D0%BC%D0%B0%D1%82%D0%B8%D0%BA%D0%B0)) - | - [Статья о дробных числах](https://habrahabr.ru/post/112953/) + [Статья о дробных числах](https://habr.com/ru/articles/112953/) definitions: - name: Тип данных description: >- diff --git a/modules/27-data-types/55-type-conversion/Makefile b/modules/33-data-types/50-data-types-weak-typing/Makefile similarity index 100% rename from modules/27-data-types/55-type-conversion/Makefile rename to modules/33-data-types/50-data-types-weak-typing/Makefile diff --git a/modules/27-data-types/50-data-types-weak-typing/index.php b/modules/33-data-types/50-data-types-weak-typing/Solution.php similarity index 100% rename from modules/27-data-types/50-data-types-weak-typing/index.php rename to modules/33-data-types/50-data-types-weak-typing/Solution.php diff --git a/modules/27-data-types/50-data-types-weak-typing/SolutionTest.php b/modules/33-data-types/50-data-types-weak-typing/SolutionTest.php similarity index 67% rename from modules/27-data-types/50-data-types-weak-typing/SolutionTest.php rename to modules/33-data-types/50-data-types-weak-typing/SolutionTest.php index afe3146f..c3a89d76 100644 --- a/modules/27-data-types/50-data-types-weak-typing/SolutionTest.php +++ b/modules/33-data-types/50-data-types-weak-typing/SolutionTest.php @@ -2,9 +2,7 @@ namespace HexletBasics\DataTypes\WeakTyping; -use PHPUnit\Framework\TestCase; - -\HexletBasics\Functions\runScript(); +use HexletBasics\Exercise\TestCase; class SolutionTest extends TestCase { @@ -12,6 +10,5 @@ public function test() { $expected = '13'; $this->expectOutputString($expected); - require 'index.php'; } } diff --git a/modules/27-data-types/50-data-types-weak-typing/description.es.yml b/modules/33-data-types/50-data-types-weak-typing/description.es.yml similarity index 100% rename from modules/27-data-types/50-data-types-weak-typing/description.es.yml rename to modules/33-data-types/50-data-types-weak-typing/description.es.yml diff --git a/modules/27-data-types/50-data-types-weak-typing/en/EXERCISE.md b/modules/33-data-types/50-data-types-weak-typing/en/EXERCISE.md similarity index 100% rename from modules/27-data-types/50-data-types-weak-typing/en/EXERCISE.md rename to modules/33-data-types/50-data-types-weak-typing/en/EXERCISE.md diff --git a/modules/27-data-types/50-data-types-weak-typing/en/README.md b/modules/33-data-types/50-data-types-weak-typing/en/README.md similarity index 100% rename from modules/27-data-types/50-data-types-weak-typing/en/README.md rename to modules/33-data-types/50-data-types-weak-typing/en/README.md diff --git a/modules/27-data-types/50-data-types-weak-typing/en/data.yml b/modules/33-data-types/50-data-types-weak-typing/en/data.yml similarity index 100% rename from modules/27-data-types/50-data-types-weak-typing/en/data.yml rename to modules/33-data-types/50-data-types-weak-typing/en/data.yml diff --git a/modules/27-data-types/50-data-types-weak-typing/es/EXERCISE.md b/modules/33-data-types/50-data-types-weak-typing/es/EXERCISE.md similarity index 100% rename from modules/27-data-types/50-data-types-weak-typing/es/EXERCISE.md rename to modules/33-data-types/50-data-types-weak-typing/es/EXERCISE.md diff --git a/modules/27-data-types/50-data-types-weak-typing/es/README.md b/modules/33-data-types/50-data-types-weak-typing/es/README.md similarity index 100% rename from modules/27-data-types/50-data-types-weak-typing/es/README.md rename to modules/33-data-types/50-data-types-weak-typing/es/README.md diff --git a/modules/27-data-types/50-data-types-weak-typing/es/data.yml b/modules/33-data-types/50-data-types-weak-typing/es/data.yml similarity index 100% rename from modules/27-data-types/50-data-types-weak-typing/es/data.yml rename to modules/33-data-types/50-data-types-weak-typing/es/data.yml diff --git a/modules/33-data-types/50-data-types-weak-typing/ru/EXERCISE.md b/modules/33-data-types/50-data-types-weak-typing/ru/EXERCISE.md new file mode 100644 index 00000000..c676b967 --- /dev/null +++ b/modules/33-data-types/50-data-types-weak-typing/ru/EXERCISE.md @@ -0,0 +1,3 @@ +В игре два игрока. Первый набрал `7` очков, второй потерял очки: выражение `(-8 - -2)` описывает его результат. Посчитайте разницу и выведите на экран: `7 - (-8 - -2)`. + +Попробуйте сделать число 7 не числом, а строкой: `'7' - (-8 - -2)`. Сработает ли такой код? Поэкспериментируйте с другими числами тоже. diff --git a/modules/33-data-types/50-data-types-weak-typing/ru/README.md b/modules/33-data-types/50-data-types-weak-typing/ru/README.md new file mode 100644 index 00000000..f4e8c3ff --- /dev/null +++ b/modules/33-data-types/50-data-types-weak-typing/ru/README.md @@ -0,0 +1,64 @@ +Нам известно про два разных типа данных: числа и строки. Мы могли складывать числа, потому что операция сложения — это операция для типа «числа». А что, если применить эту операцию к числу и строке? + +```php + 8 +``` + +`'7'` — это строка, а не число, при этом интерпретатор PHP выдал ответ `8`, как если бы мы складывали два числа. Когда PHP видит несоответствие типов, он сам пытается преобразовать информацию. В данном случае он преобразовал строку `'7'` в число `7`, а потом сложил `1` и `7`. + +## Слабая типизация + +Не все языки так делают. PHP — это язык со **слабой типизацией**. Он знает о существовании разных типов (числа, строки и другие), но относится к их использованию не строго и пытается преобразовывать данные, когда это кажется ему разумным. + +Обратите внимание: оператор `+` в PHP всегда означает арифметику, а для соединения строк есть отдельный оператор — конкатенация `.`. Поэтому в выражении `1 + '7'` PHP превращает строку в число, а в выражении `1 . '7'` — наоборот, число в строку: + +```php + 8 +print_r(1 . '7'); // => 17 +``` + +```text +1 + '7' → 8 (строка превратилась в число, сложение) +'7' - 1 → 6 (строка превратилась в число, вычитание) +1 . '7' → '17' (число превратилось в строку, конкатенация) +``` + +Граница дозволенного у PHP все же есть. Если строку никак нельзя понять как число, современный PHP остановит программу с ошибкой: + +```php +expectOutputString($expected); + } +} diff --git a/modules/33-data-types/52-data-types-immutability/description.es.yml b/modules/33-data-types/52-data-types-immutability/description.es.yml new file mode 100644 index 00000000..db49f53f --- /dev/null +++ b/modules/33-data-types/52-data-types-immutability/description.es.yml @@ -0,0 +1,47 @@ +--- + +name: | + Inmutabilidad de los tipos primitivos + +theory: | + ¿Qué sucede cuando «cambiamos» una cadena de texto en PHP? Las funciones integradas como `strtoupper()` no modifican la cadena original, sino que devuelven una nueva: + + ```php + ALEXANDER + print_r($firstName); // => Alexander + ``` + + Esto se debe a la inmutabilidad de los valores primitivos en PHP: una cadena de texto no puede ser cambiada después de su creación. La inmutabilidad de los tipos primitivos es importante por varias razones, siendo la principal el rendimiento. + + Pero a veces necesitamos cambiar una cadena de texto. Para eso existen las variables: + + ```php + ALEXANDER + ``` + + Hay una gran diferencia entre *cambiar el valor de una variable* y *cambiar el valor en sí*. No se puede cambiar un valor primitivo en PHP, pero se puede reemplazar el valor de una variable sin problemas. + +instructions: | + En los tres nombres de los participantes se esconde una palabra secreta. Componla y muéstrala en pantalla con los caracteres en el siguiente orden: + + 1. El segundo carácter de la primera cadena + 2. El tercer carácter de la tercera cadena + 3. El tercer carácter de la segunda cadena + 4. El séptimo carácter de la segunda cadena + 5. El quinto carácter de la segunda cadena + + Intenta usar interpolación: dentro de las llaves puedes colocar no solo variables enteras, sino también caracteres individuales usando corchetes. + +tips: [] + +definitions: + - name: Inmutabilidad + description: | + estado en el que un objeto o variable no puede ser cambiado después de su creación diff --git a/modules/33-data-types/52-data-types-immutability/en/EXERCISE.md b/modules/33-data-types/52-data-types-immutability/en/EXERCISE.md new file mode 100644 index 00000000..d4d54717 --- /dev/null +++ b/modules/33-data-types/52-data-types-immutability/en/EXERCISE.md @@ -0,0 +1,9 @@ +A secret word is hidden in the three participants' names. Build it and print it out from the characters in this order: + +1. The second character of the first string +2. The third character of the third string +3. The third character of the second string +4. The seventh character of the second string +5. The fifth character of the second string + +Try using interpolation: inside curly brackets you can place not only whole variables, but also individual characters using square brackets. diff --git a/modules/33-data-types/52-data-types-immutability/en/README.md b/modules/33-data-types/52-data-types-immutability/en/README.md new file mode 100644 index 00000000..1f98f652 --- /dev/null +++ b/modules/33-data-types/52-data-types-immutability/en/README.md @@ -0,0 +1,23 @@ +What happens when we "change" a string in PHP? Built-in functions like `strtoupper()` do not modify the original string — they return a new one: + +```php + ALEXANDER +print_r($firstName); // => Alexander +``` + +This happens because of the immutability of primitive values in PHP: a string itself cannot be changed after creation. The immutability of primitive types is important for many reasons. The key reason is performance. + +But sometimes we need to change a string. That's what variables are for: + +```php + ALEXANDER +``` + +There is a big difference between *changing the value of a variable* and *changing the value itself*. You can't change primitive values in PHP, but you can replace the value of a variable without any problem. diff --git a/modules/33-data-types/52-data-types-immutability/en/data.yml b/modules/33-data-types/52-data-types-immutability/en/data.yml new file mode 100644 index 00000000..e02b5da5 --- /dev/null +++ b/modules/33-data-types/52-data-types-immutability/en/data.yml @@ -0,0 +1,5 @@ +--- +name: | + Primitive data types immutability +tips: [] +definitions: [] diff --git a/modules/33-data-types/52-data-types-immutability/es/EXERCISE.md b/modules/33-data-types/52-data-types-immutability/es/EXERCISE.md new file mode 100644 index 00000000..616f33ac --- /dev/null +++ b/modules/33-data-types/52-data-types-immutability/es/EXERCISE.md @@ -0,0 +1,9 @@ +En los tres nombres de los participantes se esconde una palabra secreta. Componla y muéstrala en pantalla con los caracteres en el siguiente orden: + +1. El segundo carácter de la primera cadena +2. El tercer carácter de la tercera cadena +3. El tercer carácter de la segunda cadena +4. El séptimo carácter de la segunda cadena +5. El quinto carácter de la segunda cadena + +Intenta usar interpolación: dentro de las llaves puedes colocar no solo variables enteras, sino también caracteres individuales usando corchetes. diff --git a/modules/33-data-types/52-data-types-immutability/es/README.md b/modules/33-data-types/52-data-types-immutability/es/README.md new file mode 100644 index 00000000..83ad6cab --- /dev/null +++ b/modules/33-data-types/52-data-types-immutability/es/README.md @@ -0,0 +1,23 @@ +¿Qué sucede cuando «cambiamos» una cadena de texto en PHP? Las funciones integradas como `strtoupper()` no modifican la cadena original, sino que devuelven una nueva: + +```php + ALEXANDER +print_r($firstName); // => Alexander +``` + +Esto se debe a la inmutabilidad de los valores primitivos en PHP: una cadena de texto no puede ser cambiada después de su creación. La inmutabilidad de los tipos primitivos es importante por varias razones, siendo la principal el rendimiento. + +Pero a veces necesitamos cambiar una cadena de texto. Para eso existen las variables: + +```php + ALEXANDER +``` + +Hay una gran diferencia entre *cambiar el valor de una variable* y *cambiar el valor en sí*. No se puede cambiar un valor primitivo en PHP, pero se puede reemplazar el valor de una variable sin problemas. diff --git a/modules/33-data-types/52-data-types-immutability/es/data.yml b/modules/33-data-types/52-data-types-immutability/es/data.yml new file mode 100644 index 00000000..708e320a --- /dev/null +++ b/modules/33-data-types/52-data-types-immutability/es/data.yml @@ -0,0 +1,9 @@ +--- +name: | + Inmutabilidad de los tipos primitivos +tips: [] +definitions: + - name: Inmutabilidad + description: > + estado en el que un objeto o variable no puede ser cambiado después de su + creación diff --git a/modules/33-data-types/52-data-types-immutability/ru/EXERCISE.md b/modules/33-data-types/52-data-types-immutability/ru/EXERCISE.md new file mode 100644 index 00000000..88940032 --- /dev/null +++ b/modules/33-data-types/52-data-types-immutability/ru/EXERCISE.md @@ -0,0 +1,9 @@ +В трех именах участников спрятано секретное слово. Составьте и выведите его из символов в таком порядке: + +1. Второй символ из первой строки +2. Третий символ из третьей строки +3. Третий символ из второй строки +4. Седьмой символ из второй строки +5. Пятый символ из второй строки + +Попробуйте использовать интерполяцию: внутри фигурных скобок можно помещать не только целые переменные, но и отдельные символы с помощью квадратных скобок. diff --git a/modules/33-data-types/52-data-types-immutability/ru/README.md b/modules/33-data-types/52-data-types-immutability/ru/README.md new file mode 100644 index 00000000..859d1e02 --- /dev/null +++ b/modules/33-data-types/52-data-types-immutability/ru/README.md @@ -0,0 +1,76 @@ +Представим, что у нас есть строка, и мы хотим сделать все буквы в ней большими. В PHP для этого есть встроенная функция `strtoupper()`: + +```php + ALEXANDER +``` + +Может показаться, что функция изменила нашу строку. Проверим: + +```php + Alexander +``` + +Переменная осталась прежней. Функция `strtoupper()` не меняет исходную строку — она возвращает **новую** строку, составленную из больших букв. Так в PHP работают все функции для работы со строками: само значение после создания изменить нельзя. Программисты говорят, что такие значения **неизменяемые** (или иммутабельные). + +## Почему значения неизменяемые? + +Примитивные значения в PHP (строки, числа, логические значения) ведут себя как значения в математике: число `5` нельзя «отредактировать», можно только получить из него новое число. Это дает важные преимущества: + +- Безопасность: значения не изменятся случайно +- Производительность: с неизменяемыми значениями интерпретатору проще работать +- Предсказуемость: меньше неожиданных эффектов при передаче данных в функции + +## А как тогда изменить строку? + +Если нужно «изменить» строку, создается новая строка и сохраняется в ту же переменную: + +```php + ALEXANDER +``` + +Переменная `$firstName` теперь просто хранит другую строку. Происходит замена значения переменной, а сама строка `'Alexander'` остается нетронутой. + +```text +$firstName = 'Alexander' + +strtoupper($firstName) → 'ALEXANDER' ← создана новая строка +$firstName → 'Alexander' ← исходная не изменилась + +$firstName = strtoupper($firstName) +└──────────────┬───────────────────┘ + в переменной теперь новая строка +``` + +Важно различать две вещи: *изменение значения переменной* и *изменение самого значения*. Значение переменной можно заменить без проблем, а вот само значение — строку, число — изменить нельзя. + +## Новая переменная или та же? + +Переиспользовать переменную стоит только тогда, когда речь идет об одной и той же сущности. Если пользователь ввел новое имя, это уже другая сущность, и лучше создать отдельную переменную: + +```php + + состояние, при котором объект, переменная не могут быть изменены после + создания diff --git a/modules/30-variables/35-heredoc/Makefile b/modules/33-data-types/55-data-types-casting/Makefile similarity index 100% rename from modules/30-variables/35-heredoc/Makefile rename to modules/33-data-types/55-data-types-casting/Makefile diff --git a/modules/33-data-types/55-data-types-casting/Solution.php b/modules/33-data-types/55-data-types-casting/Solution.php new file mode 100644 index 00000000..41b8bd35 --- /dev/null +++ b/modules/33-data-types/55-data-types-casting/Solution.php @@ -0,0 +1,9 @@ +expectOutputString($expected); + } +} diff --git a/modules/27-data-types/55-type-conversion/description.es.yml b/modules/33-data-types/55-data-types-casting/description.es.yml similarity index 100% rename from modules/27-data-types/55-type-conversion/description.es.yml rename to modules/33-data-types/55-data-types-casting/description.es.yml diff --git a/modules/27-data-types/55-type-conversion/en/EXERCISE.md b/modules/33-data-types/55-data-types-casting/en/EXERCISE.md similarity index 100% rename from modules/27-data-types/55-type-conversion/en/EXERCISE.md rename to modules/33-data-types/55-data-types-casting/en/EXERCISE.md diff --git a/modules/27-data-types/55-type-conversion/en/README.md b/modules/33-data-types/55-data-types-casting/en/README.md similarity index 100% rename from modules/27-data-types/55-type-conversion/en/README.md rename to modules/33-data-types/55-data-types-casting/en/README.md diff --git a/modules/27-data-types/55-type-conversion/en/data.yml b/modules/33-data-types/55-data-types-casting/en/data.yml similarity index 100% rename from modules/27-data-types/55-type-conversion/en/data.yml rename to modules/33-data-types/55-data-types-casting/en/data.yml diff --git a/modules/27-data-types/55-type-conversion/es/EXERCISE.md b/modules/33-data-types/55-data-types-casting/es/EXERCISE.md similarity index 100% rename from modules/27-data-types/55-type-conversion/es/EXERCISE.md rename to modules/33-data-types/55-data-types-casting/es/EXERCISE.md diff --git a/modules/27-data-types/55-type-conversion/es/README.md b/modules/33-data-types/55-data-types-casting/es/README.md similarity index 100% rename from modules/27-data-types/55-type-conversion/es/README.md rename to modules/33-data-types/55-data-types-casting/es/README.md diff --git a/modules/27-data-types/55-type-conversion/es/data.yml b/modules/33-data-types/55-data-types-casting/es/data.yml similarity index 100% rename from modules/27-data-types/55-type-conversion/es/data.yml rename to modules/33-data-types/55-data-types-casting/es/data.yml diff --git a/modules/33-data-types/55-data-types-casting/ru/EXERCISE.md b/modules/33-data-types/55-data-types-casting/ru/EXERCISE.md new file mode 100644 index 00000000..ee11dc18 --- /dev/null +++ b/modules/33-data-types/55-data-types-casting/ru/EXERCISE.md @@ -0,0 +1,17 @@ +Термометр показывает температуру с десятичной точкой. Программа должна вывести только целое значение с подписью. + +У вас есть переменная: + +```php + 350 +``` + +Оператор `(int)` получает строку и превращает ее в целое число. + +```php + 0 + +print_r((int) '10'); // => 10 +print_r((int) 3.5); // => 3 (дробная часть отбрасывается) +``` + +```text +'123' ──(int)──→ 123 ──(float)──→ 123.0 + │ + (string) + ↓ + '123' +``` + +## Преобразование в строку с помощью (string) + +Если нужно превратить число в строку, используйте оператор `(string)`: + +```php + '10' +print_r((string) 3.5); // => '3.5' +``` + +Это полезно, например, при формировании текстов, сообщений и вывода: + +```php + Age: 42 +``` + +## Преобразование в число с плавающей точкой с помощью (float) + +Если нужно число с десятичной точкой, используйте `(float)`: + +```php + 2.7 +``` + +Выражение `(float) 5` тоже сработает: получится дробное число `5.0`, хотя `print_r()` выведет его без дробной части — как `5`. + +## Множественные преобразования + +Приведение типа можно использовать и внутри составных выражений. В более сложных ситуациях встречаются множественные преобразования: `(string) (5 + ((int) '4'))`. Порядок вычисления этого выражения следующий: + +```php +expectOutputString($expected); - require 'index.php'; } } diff --git a/modules/35-calling-functions/100-call/ru/EXERCISE.md b/modules/35-calling-functions/100-call/ru/EXERCISE.md index 081bc8d1..112cc739 100644 --- a/modules/35-calling-functions/100-call/ru/EXERCISE.md +++ b/modules/35-calling-functions/100-call/ru/EXERCISE.md @@ -1 +1 @@ -В коде программы определены две переменные, содержащие имена компаний. Посчитайте их общую длину в символах и выведите ее на экран. +Сайт проверяет, вместится ли реклама двух компаний-партнеров в одну строку. В коде определены их названия — посчитайте общее количество символов в обоих названиях с помощью функции `strlen()` и выведите на экран. diff --git a/modules/35-calling-functions/100-call/ru/README.md b/modules/35-calling-functions/100-call/ru/README.md index 5fdd3b8a..b73cdfb3 100644 --- a/modules/35-calling-functions/100-call/ru/README.md +++ b/modules/35-calling-functions/100-call/ru/README.md @@ -1,64 +1,147 @@ -Сложение, конкатенация и остальные рассмотренные операции — это базовые возможности языков программирования. Но со строками можно производить более сложные операции. Их можно переворачивать, менять регистр букв, удалять лишние символы. +Программирование нужно для того, чтобы выполнять самые разные операции. Иногда это простые действия, например сложение чисел или объединение строк. Но чаще это сложные процессы вроде перевода денег со счета на счет, оформления заказа в интернет-магазине, расчета налогов или подготовки отчета. -На более высоком уровне есть прикладная логика конкретного приложения. Программы списывают деньги, считают налоги, формируют отчеты. Количество подобных операций бесконечно и индивидуально для каждой программы. И все они должны быть выражены в коде. В этом помогают функции, с которыми мы познакомимся в этом уроке. +Такие операции невозможно выразить одной командой. За действием вроде «перевести деньги» могут скрываться десятки, сотни и даже тысячи строк кода. Это проверка баланса, списание суммы, учет комиссии, обновление базы данных, отправка уведомления пользователю. -## Какие бывают функции +Чтобы управлять этим кодом и не теряться в деталях, используют функции. Функция объединяет блок кода в единое целое, прячет реализацию и позволяет сосредоточиться на смысле. Для программиста достаточно вызвать функцию и доверить ей всю внутреннюю работу. -Для выражения любой произвольной операции в программировании существуют **функции**. Они бывают встроенными и добавленными программистом. С одной встроенной функцией мы уже знакомы — это `print_r()`. +![Функция](./assets/function.png) -**Функции** — одна из ключевых конструкций в программировании, без них невозможно сделать практически ничего. Сначала мы научимся пользоваться уже созданными функциями, а потом научимся создавать свои. +Представим функцию, которая переводит деньги с одного счета на другой. В реальности внутри нее могут быть сотни строк кода, но мы этого не видим. Снаружи все выглядит как одна простая команда: -## Как работать со встроенными функциями +```php + '!olleH' +// Да-да, print_r тоже функция +print_r('Хекслет!'); + +// Отправка письма пользователю +sendEmail('bob@example.com', 'Добро пожаловать!'); + +// Вычисление налога с указанной суммы +calculateTax(5000, 'Florida'); + +// Проверка, есть ли пользователь в системе +isRegistered('Alice'); + +// Получение случайного числа от 1 до 10 +randomNumber(1, 10); + +// Создание резервной копии базы данных +backupDatabase(); + +// Вычисление длины строки +strlen('Hexlet'); // Результат: 6 ``` -Мы создали переменную `$result` и указали интерпретатору записать в нее результат, который вернет вызов функции `strrev()`. В этом смысле функции идентичны операциям — они всегда возвращают результат своей работы. +В вызове функции сначала пишется ее **имя**, затем круглые **скобки**. Скобки показывают, что это именно вызов. Так мы понимаем, что перед нами функция, а не переменная. -Запись `strrev('Hello!')` означает, что вызывается функция с именем `strrev`, в которую был передан аргумент или параметр `'Hello!'`. +Внутри скобок указываются **аргументы**, то есть данные, которые функция получает для работы. Их может быть несколько, один или вовсе ни одного. -Аргументы нужны функциям для работы так же, как операторам нужны операнды. Функция `strrev()` переворачивает ту строку, которая передается ей в аргументах. +## Откуда берутся функции? -Вызов функции всегда обозначается скобками `()`. Они идут сразу за именем функции. В скобках может быть любое количество аргументов, а иногда — ни одного. Количество зависит от используемой функции. Например, функция `pow()` принимает на вход два аргумента и возводит число, переданное первым параметром, в степень, переданную вторым параметром: +Одни функции встроены в язык (built-in), другие создают сами программисты. + +**Встроенные функции** представляют собой функции, которые идут вместе с языком PHP. Их можно использовать сразу, без дополнительных действий. В качестве примера можно привести функцию `print_r()`. Как говорят, она доступна глобально. + +**Функции, определяемые программистами**, создаются тогда, когда нужно оформить свою логику в отдельный блок. Такую функцию можно назвать любым именем и использовать в коде так же, как встроенные. Мы научимся этому позже. + +Кроме того, существуют функции, которые находятся в отдельных библиотеках. Чтобы ими пользоваться, библиотеку нужно установить и подключить к программе. Подробно этот механизм мы пока не разбираем. Пока достаточно знать, что он позволяет подключить внешний набор функций и сделать их доступными в программе. + +## Функция с одним параметром + +Одной из самых часто используемых встроенных функций является `strlen()`. Она возвращает количество символов в строке. ```php 8 +$message = 'Hello!'; +$count = strlen($message); +print_r($count); // => 6 +``` + +Здесь в строке `'Hello!'` шесть символов, поэтому вызов `strlen($message)` вернет число `6`. -// В современном PHP появился специальный оператор для возведения в степень -$result = 2 ** 3; // 8 +```text +Аргументы Функция Результат +┌──────────┐ ┌──────────┐ ┌──────────┐ +│ 'Hello!' │ ──→ │ strlen() │ ──→ │ 6 │ +└──────────┘ └──────────┘ └──────────┘ ``` -Теперь рассмотрим пример функции, которая не принимает аргументов. Функция `rand()` генерирует и возвращает случайное число: +## Возврат значения + +Возврат значения является одним из ключевых принципов работы функций. Благодаря ему мы можем соединять результаты разных действий и строить более сложную логику. Если функция возвращает значение, то мы можем сохранить его в переменную, передать в другую функцию или использовать в вычислениях. Именно так работает `strlen()`. Она считает количество символов и отдает результат наружу. ```php 12 +``` + +Если бы `strlen()` сразу печатала результат на экран (как делает `print_r()`), то мы бы увидели число, но не смогли бы его использовать: + +```php + 8 + +// 5 во 2-й степени: 5 * 5 +print_r(pow(5, 2)); // => 25 +``` + +По структуре вызов с несколькими параметрами не отличается от вызова с одним. Те же имя функции, скобки и аргументы через запятую внутри. + +## Параметры и аргументы + +В разговорах о функциях то и дело встречаются слова **параметры** и **аргументы**. Они связаны, но не одно и то же. + +О **параметрах** говорят при создании функции. Параметром называют переменную внутри функции, в которую попадает переданное значение. Об **аргументах** говорят при вызове. Аргументом называют то, что мы передаем в функцию. Это может быть число, переменная или любое выражение. + +```php + 8 -// В PHP такой синтаксис невозможен, но есть языки (например, lisp), -// где оно выглядит очень похоже +$x = 2; +// аргумент может быть выражением, оно вычислится до передачи в функцию +print_r(pow($x + 1, 3)); // => 27 ``` -Вопрос на самопроверку. Как узнать, что возвращает вызов `print_r()`? Проверьте. +Запоминать это не обязательно, но пригодится при чтении англоязычной литературы. diff --git a/modules/35-calling-functions/100-call/ru/assets/function.png b/modules/35-calling-functions/100-call/ru/assets/function.png new file mode 100644 index 00000000..f89fee08 Binary files /dev/null and b/modules/35-calling-functions/100-call/ru/assets/function.png differ diff --git a/modules/35-calling-functions/120-function-signature/SolutionTest.php b/modules/35-calling-functions/120-function-signature/SolutionTest.php deleted file mode 100644 index 46c2447b..00000000 --- a/modules/35-calling-functions/120-function-signature/SolutionTest.php +++ /dev/null @@ -1,17 +0,0 @@ -expectOutputString($expected); - require 'index.php'; - } -} diff --git a/modules/35-calling-functions/120-function-signature/description.es.yml b/modules/35-calling-functions/120-function-signature/description.es.yml deleted file mode 100644 index 4755f47b..00000000 --- a/modules/35-calling-functions/120-function-signature/description.es.yml +++ /dev/null @@ -1,87 +0,0 @@ ---- - -name: Firma de la función -theory: | - En esta lección aprenderemos a trabajar con la firma de una función. También aprenderemos cómo una función recibe y devuelve valores. Analizaremos las funciones `abs()` y `round()`. - - ## Función abs() - - La función `abs()`, que devuelve el valor absoluto, recibe un parámetro: un número. Si llamamos a `abs()` sin parámetros, PHP mostrará el siguiente mensaje de error: - - ``` - TypeError: abs() expects exactly 1 argument, 0 given - ``` - - Esto indica que la función espera un parámetro, pero la llamamos sin ninguno. - - Los parámetros de `abs()` solo pueden ser números. Si intentamos pasarle una cadena de texto, obtendremos el siguiente error: - - ``` - TypeError: abs(): Argument #1 ($num) must be of type int|float, string given - ``` - - El resultado de llamar a esta función siempre es un número. Otra función puede tener un número diferente de parámetros y diferentes tipos de parámetros. Por ejemplo, puede existir una función que reciba tres parámetros: un número, una cadena de texto y otro número. - - ¿Cómo sabemos cuántos y qué tipo de parámetros necesita la función `abs()` y qué tipo de valor devuelve? Lo vemos en la **firma** de la función. La firma define los parámetros de entrada y sus tipos, así como el parámetro de salida y su tipo. - - Puedes leer más sobre la función `abs()` en la [documentación oficial de PHP](https://www.php.net/manual/es/function.abs.php). En la sección "Descripción" encontrarás el siguiente texto: - - ```txt - abs(int|float $num): int|float - - Devuelve el valor absoluto de num. - ``` - - Esta es la firma de la función y una breve explicación en español. - - La información se interpreta de la siguiente manera: - - * El nombre de la función es `abs` - * La función recibe un parámetro: un número (num) - * La función devuelve un número - * La función devuelve el valor absoluto de num - - Si hay más de un parámetro, debemos pasarlos en el mismo orden en que están definidos en la firma. Cualquier función siempre devuelve solo un valor. Esta es una limitación del lenguaje y no puede ser violada. - - ## Argumentos por defecto - - Veamos la función `round()`. Esta función redondea un número: - - ```php - - - is a formal description of the types of arguments and the type of return - value of a function. diff --git a/modules/35-calling-functions/120-function-signature/es/EXERCISE.md b/modules/35-calling-functions/120-function-signature/es/EXERCISE.md deleted file mode 100644 index 9c293162..00000000 --- a/modules/35-calling-functions/120-function-signature/es/EXERCISE.md +++ /dev/null @@ -1,5 +0,0 @@ -Ahora es tu turno de mirar la firma de una función en la documentación y entender cómo usarla. Puedes leer la documentación en español, pero un programador debe ser capaz de leer la documentación en inglés. Utiliza diccionarios o traductores si es necesario. Es mejor acostumbrarse y mejorar tus habilidades de lectura en inglés desde el principio, de lo contrario, tendrás dificultades en el futuro. - -En PHP, hay una función llamada `ucfirst()`. Estudia su firma en la página [https://php.net/manual/es/function.ucfirst.php](https://php.net/manual/es/function.ucfirst.php). - -Escribe un programa que utilice la función `ucfirst()` con la variable `$text` y muestre el resultado en pantalla. El valor de la variable `$text` ya está definido. diff --git a/modules/35-calling-functions/120-function-signature/es/README.md b/modules/35-calling-functions/120-function-signature/es/README.md deleted file mode 100644 index 4ae1e666..00000000 --- a/modules/35-calling-functions/120-function-signature/es/README.md +++ /dev/null @@ -1,70 +0,0 @@ -En esta lección aprenderemos a trabajar con la firma de una función. También aprenderemos cómo una función recibe y devuelve valores. Analizaremos las funciones `abs()` y `round()`. - -## Función abs() - -La función `abs()`, que devuelve el valor absoluto, recibe un parámetro: un número. Si llamamos a `abs()` sin parámetros, PHP mostrará el siguiente mensaje de error: - -```text -TypeError: abs() expects exactly 1 argument, 0 given -``` - -Esto indica que la función espera un parámetro, pero la llamamos sin ninguno. - -Los parámetros de `abs()` solo pueden ser números. Si intentamos pasarle una cadena de texto, obtendremos el siguiente error: - -```text -TypeError: abs(): Argument #1 ($num) must be of type int|float, string given -``` - -El resultado de llamar a esta función siempre es un número. Otra función puede tener un número diferente de parámetros y diferentes tipos de parámetros. Por ejemplo, puede existir una función que reciba tres parámetros: un número, una cadena de texto y otro número. - -¿Cómo sabemos cuántos y qué tipo de parámetros necesita la función `abs()` y qué tipo de valor devuelve? Lo vemos en la **firma** de la función. La firma define los parámetros de entrada y sus tipos, así como el parámetro de salida y su tipo. - -Puedes leer más sobre la función `abs()` en la [documentación oficial de PHP](https://www.php.net/manual/es/function.abs.php). En la sección "Descripción" encontrarás el siguiente texto: - -```txt -abs(int|float $num): int|float - -Devuelve el valor absoluto de num. -``` - -Esta es la firma de la función y una breve explicación en español. - -La información se interpreta de la siguiente manera: - -* El nombre de la función es `abs` -* La función recibe un parámetro: un número (num) -* La función devuelve un número -* La función devuelve el valor absoluto de num - -Si hay más de un parámetro, debemos pasarlos en el mismo orden en que están definidos en la firma. Cualquier función siempre devuelve solo un valor. Esta es una limitación del lenguaje y no puede ser violada. - -## Argumentos por defecto - -Veamos la función `round()`. Esta función redondea un número: - -```php -- - descripción formal de los tipos de argumentos y el tipo de valor devuelto - por una función. diff --git a/modules/35-calling-functions/120-function-signature/index.php b/modules/35-calling-functions/120-function-signature/index.php deleted file mode 100644 index a826b95e..00000000 --- a/modules/35-calling-functions/120-function-signature/index.php +++ /dev/null @@ -1,7 +0,0 @@ -- - формальное описание типов аргументов и типа возвращаемого значения - функции. diff --git a/modules/35-calling-functions/135-calling-functions-default-arguments/SolutionTest.php b/modules/35-calling-functions/135-calling-functions-default-arguments/SolutionTest.php deleted file mode 100644 index 3cabcbe8..00000000 --- a/modules/35-calling-functions/135-calling-functions-default-arguments/SolutionTest.php +++ /dev/null @@ -1,17 +0,0 @@ -expectOutputString($expected); - require 'index.php'; - } -} diff --git a/modules/35-calling-functions/135-calling-functions-default-arguments/index.php b/modules/35-calling-functions/135-calling-functions-default-arguments/index.php deleted file mode 100644 index 26ce445f..00000000 --- a/modules/35-calling-functions/135-calling-functions-default-arguments/index.php +++ /dev/null @@ -1,7 +0,0 @@ -expectOutputString($expected); + } +} diff --git a/modules/35-calling-functions/135-calling-functions-default-arguments/description.es.yml b/modules/35-calling-functions/135-calling-functions-default-params/description.es.yml similarity index 100% rename from modules/35-calling-functions/135-calling-functions-default-arguments/description.es.yml rename to modules/35-calling-functions/135-calling-functions-default-params/description.es.yml diff --git a/modules/35-calling-functions/135-calling-functions-default-arguments/en/EXERCISE.md b/modules/35-calling-functions/135-calling-functions-default-params/en/EXERCISE.md similarity index 100% rename from modules/35-calling-functions/135-calling-functions-default-arguments/en/EXERCISE.md rename to modules/35-calling-functions/135-calling-functions-default-params/en/EXERCISE.md diff --git a/modules/35-calling-functions/135-calling-functions-default-arguments/en/README.md b/modules/35-calling-functions/135-calling-functions-default-params/en/README.md similarity index 100% rename from modules/35-calling-functions/135-calling-functions-default-arguments/en/README.md rename to modules/35-calling-functions/135-calling-functions-default-params/en/README.md diff --git a/modules/35-calling-functions/135-calling-functions-default-arguments/en/data.yml b/modules/35-calling-functions/135-calling-functions-default-params/en/data.yml similarity index 100% rename from modules/35-calling-functions/135-calling-functions-default-arguments/en/data.yml rename to modules/35-calling-functions/135-calling-functions-default-params/en/data.yml diff --git a/modules/35-calling-functions/135-calling-functions-default-arguments/es/EXERCISE.md b/modules/35-calling-functions/135-calling-functions-default-params/es/EXERCISE.md similarity index 100% rename from modules/35-calling-functions/135-calling-functions-default-arguments/es/EXERCISE.md rename to modules/35-calling-functions/135-calling-functions-default-params/es/EXERCISE.md diff --git a/modules/35-calling-functions/135-calling-functions-default-arguments/es/README.md b/modules/35-calling-functions/135-calling-functions-default-params/es/README.md similarity index 100% rename from modules/35-calling-functions/135-calling-functions-default-arguments/es/README.md rename to modules/35-calling-functions/135-calling-functions-default-params/es/README.md diff --git a/modules/35-calling-functions/135-calling-functions-default-arguments/es/data.yml b/modules/35-calling-functions/135-calling-functions-default-params/es/data.yml similarity index 100% rename from modules/35-calling-functions/135-calling-functions-default-arguments/es/data.yml rename to modules/35-calling-functions/135-calling-functions-default-params/es/data.yml diff --git a/modules/35-calling-functions/135-calling-functions-default-params/ru/EXERCISE.md b/modules/35-calling-functions/135-calling-functions-default-params/ru/EXERCISE.md new file mode 100644 index 00000000..dbe89819 --- /dev/null +++ b/modules/35-calling-functions/135-calling-functions-default-params/ru/EXERCISE.md @@ -0,0 +1,19 @@ +В коде заданы данные об автомобильной поездке: расстояние, расход топлива, цена топлива и количество пассажиров. + +Вычислите и выведите на экран три значения: + +1. Объем топлива в литрах, необходимый для поездки. Округлите до одного знака после запятой. +2. Общую стоимость поездки в рублях. Округлите до двух знаков после запятой. +3. Стоимость поездки для каждого пассажира в рублях. Округлите до целого числа, вызвав `round()` без второго аргумента. + +Каждое значение выводится на отдельной строке. + +```text +distance ──────┐ + ├──→ fuel ──────┐ +fuelConsumption ───┘ ├──→ tripCost ──────┐ + │ ├──→ perPerson +fuelPrice ─────────────────────┘ │ + │ +passengers ────────────────────────────────────────┘ +``` diff --git a/modules/35-calling-functions/135-calling-functions-default-params/ru/README.md b/modules/35-calling-functions/135-calling-functions-default-params/ru/README.md new file mode 100644 index 00000000..0963aec7 --- /dev/null +++ b/modules/35-calling-functions/135-calling-functions-default-params/ru/README.md @@ -0,0 +1,65 @@ +Некоторые функции в PHP имеют **необязательные параметры**. Это значит, что для них заранее задано значение по умолчанию, и при вызове можно этот параметр не указывать. + +![Автосервис](./assets/default-parameters.png) + +Рассмотрим встроенную функцию `round()`, которая округляет число: + +```php + + [Значения параметров по + умолчанию](https://www.php.net/manual/ru/functions.arguments.php#functions.arguments.default) +definitions: + - name: Параметр по умолчанию + description: необязательный параметр функции. diff --git a/modules/35-calling-functions/150-calling-functions-expression/index.php b/modules/35-calling-functions/150-calling-functions-expression/Solution.php similarity index 61% rename from modules/35-calling-functions/150-calling-functions-expression/index.php rename to modules/35-calling-functions/150-calling-functions-expression/Solution.php index 811c0cdc..440a29fc 100644 --- a/modules/35-calling-functions/150-calling-functions-expression/index.php +++ b/modules/35-calling-functions/150-calling-functions-expression/Solution.php @@ -1,6 +1,6 @@ expectOutputString($expected); - require 'index.php'; } } diff --git a/modules/35-calling-functions/150-calling-functions-expression/ru/EXERCISE.md b/modules/35-calling-functions/150-calling-functions-expression/ru/EXERCISE.md index 5e4d8c62..ce14fa95 100644 --- a/modules/35-calling-functions/150-calling-functions-expression/ru/EXERCISE.md +++ b/modules/35-calling-functions/150-calling-functions-expression/ru/EXERCISE.md @@ -1,8 +1,8 @@ -Выведите на экран первую и последнюю буквы предложения, записанного в переменную `text`, в следующем формате: +Приложение показывает краткую сводку по тексту: его первый и последний символ. Выведите на экран первый и последний символы строки из переменной `$text` в следующем формате: ```text -First: N -Last: t +First: H +Last: ! ``` Постарайтесь создать только одну переменную, в которую сразу запишется нужный текст перед печатью на экран. В этом уроке мы отрабатываем умение собирать составное выражение. diff --git a/modules/35-calling-functions/150-calling-functions-expression/ru/README.md b/modules/35-calling-functions/150-calling-functions-expression/ru/README.md index d3b9fdb9..ac218e03 100644 --- a/modules/35-calling-functions/150-calling-functions-expression/ru/README.md +++ b/modules/35-calling-functions/150-calling-functions-expression/ru/README.md @@ -1,58 +1,106 @@ -В программировании выражение – нечто возвращающее результат, который можно использовать. Напомним, что математические операции по типу сложения и вычитания и строковые операции — это выражения: +Когда мы пишем программы, нам нужно соединять действия друг с другом. Сложение чисел, объединение строк и работа с переменными являются примерами того, как простые шаги можно комбинировать, получая более сложное поведение. ```php 150 ``` -Особенность выражений в том, что они возвращают результат, который можно, например, присвоить переменной или вывести на экран. Например: +В программировании для этого используется понятие **выражение**. Оно обозначает конструкцию, которая вычисляется и дает результат. В примере выше `$rate * $hours + 100` является выражением, составленным из переменных (`$rate`, `$hours`), числового литерала (`100`) и арифметических операций. Все вместе оно возвращает результат, который можно сохранить в переменную или использовать дальше. + +Что нам дает это знание? Мы понимаем, что выражения можно комбинировать бесконечно, постепенно усложняя логику. Каждое новое выражение становится частью большего: ```php 150 + +// Можно комбинировать еще сложнее +$rate = 10; +$hours = 15; +$bonus = 50; +print_r($rate * $hours + $bonus); // => 200 ``` -В этом коде нет нового синтаксиса. Мы только соединили уже известные части, опираясь на их природу. Можно пойти еще дальше: +Функция `print_r()` просто получает готовое значение и выводит его на экран. Способ получения этого значения функции безразличен. Именно поэтому вызовы функций отлично сочетаются с любыми выражениями. + +## Вызов функции внутри функции + +Так как вызов функции сам по себе является выражением, его результат можно сразу передавать другой функции. Это позволяет строить еще более сложные конструкции. ```php 2 +$name = 'python'; + +// Вызов strlen($name) возвращает 6 +// Этот результат сразу используется как аргумент print_r() +print_r(strlen($name)); // => 6 +``` + +Здесь `strlen($name)` вычисляется первым и возвращает число 6. Затем это значение подставляется в вызов `print_r()`. Такая комбинация может быть сколько угодно глубокой. Результат одной функции можно передать в другую, потом в следующую. + +Чтобы правильно читать такие конструкции, нужно помнить про порядок вызова. + +1. Сначала выполняется функция, которая находится «внутри», в нашем случае `strlen($name)`. +2. Затем ее результат подставляется на место вызова. +3. После этого выполняется внешняя функция, в данном случае `print_r()`. + +Таким образом, код `print_r(strlen($name))` можно мысленно разложить так: + +```text +print_r(strlen('python')) + +Шаг 1: strlen('python') → 6 +Шаг 2: print_r(6) → выводит 6 ``` -Все это справедливо для любых функций, например, строковых: +1. `strlen($name)` → `6` +2. `print_r(6)` +3. На экране появляется `6`. + +Этот принцип работает всегда. Сначала вычисляются вложенные вызовы, потом внешний. + +## Использование функций в составе выражений + +Функции возвращают значения, а значит их вызовы можно использовать как аргументы других функций и как часть любых других выражений. ```php Имя пользователя: Toto +$name = 'python'; + +// Вызов strlen($name) возвращает 6 +// Мы вычитаем 1, чтобы получить индекс последнего символа +$lastIndex = strlen($name) - 1; +print_r($lastIndex); // => 5 + +// Можно использовать результат функции в арифметике +$text = 'hexlet'; +$double = strlen($text) * 2; +print_r($double); // => 12 ``` + +Здесь вызовы `strlen($name)` и `strlen($text)` являются полноценными выражениями. Они возвращают значения, которые можно комбинировать с числами, переменными и другими операциями. diff --git a/modules/35-calling-functions/150-calling-functions-expression/ru/data.yml b/modules/35-calling-functions/150-calling-functions-expression/ru/data.yml index d587eabd..46ef8cf7 100644 --- a/modules/35-calling-functions/150-calling-functions-expression/ru/data.yml +++ b/modules/35-calling-functions/150-calling-functions-expression/ru/data.yml @@ -1,2 +1,7 @@ --- name: Вызов функции — выражение +definitions: + - name: Выражение + description: > + последовательность действий над данными, приводящая к какому-то результату, + который можно использовать. diff --git a/modules/35-calling-functions/180-variadic-arguments/SolutionTest.php b/modules/35-calling-functions/180-variadic-arguments/SolutionTest.php deleted file mode 100644 index 14eb6bde..00000000 --- a/modules/35-calling-functions/180-variadic-arguments/SolutionTest.php +++ /dev/null @@ -1,17 +0,0 @@ -expectOutputString($expected); - require 'index.php'; - } -} diff --git a/modules/35-calling-functions/180-variadic-arguments/ru/EXERCISE.md b/modules/35-calling-functions/180-variadic-arguments/ru/EXERCISE.md deleted file mode 100644 index 92bfe495..00000000 --- a/modules/35-calling-functions/180-variadic-arguments/ru/EXERCISE.md +++ /dev/null @@ -1 +0,0 @@ -Посчитайте программно (а не в голове) минимальное число среди 3, 10, 22, -3, 0 — и выведите его на экран. Воспользуйтесь функцией `min()`, которая работает аналогично `max()`. diff --git a/modules/35-calling-functions/180-variadic-arguments/ru/README.md b/modules/35-calling-functions/180-variadic-arguments/ru/README.md deleted file mode 100644 index 948a5016..00000000 --- a/modules/35-calling-functions/180-variadic-arguments/ru/README.md +++ /dev/null @@ -1,16 +0,0 @@ -В этом уроке разберем одну особенность некоторых функций. Они могут принимать переменное число параметров. Но речь идет не о значениях по умолчанию. Посмотрим на этот пример: - -```php -expectOutputString($expected); + } +} diff --git a/modules/35-calling-functions/180-variadic-arguments/description.es.yml b/modules/35-calling-functions/180-variadic-parameters/description.es.yml similarity index 100% rename from modules/35-calling-functions/180-variadic-arguments/description.es.yml rename to modules/35-calling-functions/180-variadic-parameters/description.es.yml diff --git a/modules/35-calling-functions/180-variadic-arguments/en/EXERCISE.md b/modules/35-calling-functions/180-variadic-parameters/en/EXERCISE.md similarity index 100% rename from modules/35-calling-functions/180-variadic-arguments/en/EXERCISE.md rename to modules/35-calling-functions/180-variadic-parameters/en/EXERCISE.md diff --git a/modules/35-calling-functions/180-variadic-arguments/en/README.md b/modules/35-calling-functions/180-variadic-parameters/en/README.md similarity index 100% rename from modules/35-calling-functions/180-variadic-arguments/en/README.md rename to modules/35-calling-functions/180-variadic-parameters/en/README.md diff --git a/modules/35-calling-functions/180-variadic-arguments/en/data.yml b/modules/35-calling-functions/180-variadic-parameters/en/data.yml similarity index 100% rename from modules/35-calling-functions/180-variadic-arguments/en/data.yml rename to modules/35-calling-functions/180-variadic-parameters/en/data.yml diff --git a/modules/35-calling-functions/180-variadic-arguments/es/EXERCISE.md b/modules/35-calling-functions/180-variadic-parameters/es/EXERCISE.md similarity index 100% rename from modules/35-calling-functions/180-variadic-arguments/es/EXERCISE.md rename to modules/35-calling-functions/180-variadic-parameters/es/EXERCISE.md diff --git a/modules/35-calling-functions/180-variadic-arguments/es/README.md b/modules/35-calling-functions/180-variadic-parameters/es/README.md similarity index 100% rename from modules/35-calling-functions/180-variadic-arguments/es/README.md rename to modules/35-calling-functions/180-variadic-parameters/es/README.md diff --git a/modules/35-calling-functions/180-variadic-arguments/es/data.yml b/modules/35-calling-functions/180-variadic-parameters/es/data.yml similarity index 100% rename from modules/35-calling-functions/180-variadic-arguments/es/data.yml rename to modules/35-calling-functions/180-variadic-parameters/es/data.yml diff --git a/modules/35-calling-functions/180-variadic-parameters/ru/EXERCISE.md b/modules/35-calling-functions/180-variadic-parameters/ru/EXERCISE.md new file mode 100644 index 00000000..f8343173 --- /dev/null +++ b/modules/35-calling-functions/180-variadic-parameters/ru/EXERCISE.md @@ -0,0 +1 @@ +За неделю были зафиксированы такие температуры воздуха: 3, 10, 22, -3, 0 градусов. Найдите минимальное значение с помощью функции `min()` и выведите его на экран. diff --git a/modules/35-calling-functions/180-variadic-parameters/ru/README.md b/modules/35-calling-functions/180-variadic-parameters/ru/README.md new file mode 100644 index 00000000..58dce7cc --- /dev/null +++ b/modules/35-calling-functions/180-variadic-parameters/ru/README.md @@ -0,0 +1,41 @@ +Некоторые функции обладают особенностью: они принимают переменное число аргументов. Это не связано со значениями по умолчанию, как в случае с `round()`. Речь идет о том, что количество передаваемых данных не ограничено фиксированным числом. + +Рассмотрим функцию `max()`. Она находит наибольшее значение из переданных данных. + +```php + 10 +print_r(max(1, -3, 2, 3, 2)); // => 3 +``` + +Откроем [документацию](https://www.php.net/manual/ru/function.max.php) и посмотрим на сигнатуру `max()`: + +```php +max(mixed $value, mixed ...$values): mixed +``` + +Это значит: + +- функция требует как минимум одно значение (`$value`); +- дальше можно передавать еще сколько угодно значений (`...$values`) — переменное число аргументов обозначается многоточием `...`; +- функция вернет наибольшее из переданных. + +Тип `mixed` в сигнатуре означает «любой тип»: функция умеет сравнивать не только числа, но и другие значения. + +Если среди аргументов есть несколько одинаковых максимальных значений, возвращается первый из них. + +```php + 5 +``` + +Аналогично работает функция `min()`, только она ищет наименьшее значение: + +```php + 1 +print_r(min(1, -3, 2, 3, 2)); // => -3 +``` diff --git a/modules/35-calling-functions/180-variadic-parameters/ru/data.yml b/modules/35-calling-functions/180-variadic-parameters/ru/data.yml new file mode 100644 index 00000000..70466495 --- /dev/null +++ b/modules/35-calling-functions/180-variadic-parameters/ru/data.yml @@ -0,0 +1,9 @@ +--- +name: Функции с переменным числом параметров +tips: + - > + [Пример функции с переменным числом + параметров](https://www.php.net/manual/ru/function.max.php) +definitions: + - name: Аргумент по умолчанию + description: необязательный аргумент функции. diff --git a/modules/35-calling-functions/270-deterministic/index.php b/modules/35-calling-functions/270-deterministic/Solution.php similarity index 51% rename from modules/35-calling-functions/270-deterministic/index.php rename to modules/35-calling-functions/270-deterministic/Solution.php index 7176b646..ff3027d2 100644 --- a/modules/35-calling-functions/270-deterministic/index.php +++ b/modules/35-calling-functions/270-deterministic/Solution.php @@ -1,5 +1,5 @@ getActualOutputForAssertion(); + $randomRoll = $this->getActualOutputForAssertion(); $this->assertThat( - $randomSide, + $randomRoll, $this->logicalAnd( - $this->greaterThanOrEqual(1), - $this->lessThanOrEqual(6) + $this->greaterThanOrEqual(0), + $this->lessThanOrEqual(10) ) ); } diff --git a/modules/35-calling-functions/270-deterministic/ru/EXERCISE.md b/modules/35-calling-functions/270-deterministic/ru/EXERCISE.md index e73eaa8a..9dd04992 100644 --- a/modules/35-calling-functions/270-deterministic/ru/EXERCISE.md +++ b/modules/35-calling-functions/270-deterministic/ru/EXERCISE.md @@ -1 +1,3 @@ -Выведите на экран случайное число от 1 до 6. Для реализации вам потребуется функция `rand()`, которая может принимать два числа: начальное и конечное +В настольной игре бросают кубик и получают число от 0 до 10. Напишите программу, которая моделирует этот бросок: выводит на экран случайное целое число в диапазоне от 0 до 10. Для этой задачи вам понадобится функция `rand()`, которая может принимать два числа: начальное и конечное значение диапазона. + +Попробуйте решить это задание в одну строчку. diff --git a/modules/35-calling-functions/270-deterministic/ru/README.md b/modules/35-calling-functions/270-deterministic/ru/README.md index a76431ae..957bb5ac 100644 --- a/modules/35-calling-functions/270-deterministic/ru/README.md +++ b/modules/35-calling-functions/270-deterministic/ru/README.md @@ -1,21 +1,24 @@ -Независимо от того, какой язык программирования используется, функции внутри него обладают некоторыми фундаментальными свойствами. Если знать эти свойства, легче прогнозировать поведение функций, способы их тестирования и место их использования. В этом уроке мы изучим такие свойства функций и особенности их работы. +У функций в любом языке программирования есть фундаментальные свойства. Эти свойства помогают понимать, как функция будет вести себя в разных ситуациях, как ее тестировать и где применять. Одним из таких свойств является **детерминированность**. -## Что такое детерминированность +![Двое сидят и разговаривают о детерминированной функции](./assets/deterministic.png) -**Детерминированность** — это одно из фундаментальных свойств функций. Функция будет детерминированной, когда для одних и тех же входных аргументов она возвращает один и тот же результат. Например, функция, которая переворачивает строку, — детерминированная: +**Детерминированная функция** всегда возвращает один и тот же результат при одинаковых входных данных. Например, детерминированной можно назвать функцию, которая считает количество символов: ```php [Детерминированные функции](https://ru.wikipedia.org/wiki/Чистота_функции#Детерминированность_функции) +definitions: + - name: Побочный эффект + description: >- + действие, которое изменяет внешнее окружение (среду выполнения). Например, + вывод на экран или отправка письма. diff --git a/modules/35-calling-functions/900-stdlib/SolutionTest.php b/modules/35-calling-functions/900-stdlib/SolutionTest.php deleted file mode 100644 index fe540095..00000000 --- a/modules/35-calling-functions/900-stdlib/SolutionTest.php +++ /dev/null @@ -1,17 +0,0 @@ -expectOutputString($expected); - require 'index.php'; - } -} diff --git a/modules/35-calling-functions/900-stdlib/description.es.yml b/modules/35-calling-functions/900-stdlib/description.es.yml deleted file mode 100644 index e52fda2c..00000000 --- a/modules/35-calling-functions/900-stdlib/description.es.yml +++ /dev/null @@ -1,33 +0,0 @@ ---- - -name: Biblioteca estándar -theory: | - PHP viene con un conjunto de funciones útiles. Juntas, forman la **biblioteca estándar**. Por lo general, incluye miles de funciones que no se pueden aprender todas, ni es necesario hacerlo. En esta lección, daremos recomendaciones sobre cómo trabajar con nuevas funciones. - - Se supone que cualquier programador sabe dónde buscar la documentación y tiene una idea aproximada de lo que quiere lograr. Por lo tanto, programar sin internet es extremadamente difícil. - - A menudo, los principiantes no saben a dónde ir ni qué buscar. Estos conocimientos y habilidades se adquieren con la experiencia. Durante el aprendizaje y el trabajo, se familiarizan con funciones más interesantes que resuelven sus problemas de una manera más conveniente. Así es como enriquecen su arsenal. - - Aquí hay algunos consejos sobre cómo aprender sobre nuevas funciones: - - * Siempre es necesario tener en cuenta el tipo de datos con el que se está trabajando. Las funciones necesarias se pueden encontrar en la sección correspondiente de la documentación. Por ejemplo, para trabajar con cadenas, es necesario estudiar las funciones de cadenas. - * De vez en cuando, es necesario abrir la sección de funciones estándar relacionadas con el tema que se está estudiando. Es necesario estudiarlas, sus firmas y formas de uso. - * Es necesario leer el código de otras personas con frecuencia, especialmente el código de bibliotecas que utilizamos. Siempre está disponible en GitHub. - - Otra característica de las funciones de PHP de la biblioteca estándar es que están disponibles globalmente. Se pueden llamar en cualquier parte del programa. Sin embargo, esto no se aplica a las funciones escritas por uno mismo. - - La mayoría de las funciones de la biblioteca estándar se centran en funcionalidades o tipos de datos específicos. Por ejemplo, hay un gran conjunto de funciones para el manejo de cadenas, números, etc. Algunas de ellas las veremos durante el proceso de aprendizaje. - -instructions: | - - La función `gettype()` permite determinar el tipo de argumento pasado. El nombre del tipo se devuelve como una cadena. Por ejemplo, llamar a `gettype(10)` devolverá la cadena `"integer"` (integer - número entero). - - Muestra en pantalla el tipo de valor de la variable `$motto`. - -tips: - - | - [Descripción de las funciones de cadenas](https://www.php.net/manual/es/ref.strings.php) - -definitions: - - name: Biblioteca estándar - description: conjunto de funciones útiles que se incluyen en el lenguaje de programación. diff --git a/modules/35-calling-functions/900-stdlib/en/EXERCISE.md b/modules/35-calling-functions/900-stdlib/en/EXERCISE.md deleted file mode 100644 index 92e043bd..00000000 --- a/modules/35-calling-functions/900-stdlib/en/EXERCISE.md +++ /dev/null @@ -1,4 +0,0 @@ - -The `gettype()` function allows you to determine the type of the argument being passed. The name of the type is returned as a string. For example, a call to `gettype(10)` will return the string `"integer"`. - -Print the type of the value of the variable `$motto`. diff --git a/modules/35-calling-functions/900-stdlib/en/README.md b/modules/35-calling-functions/900-stdlib/en/README.md deleted file mode 100644 index 09159d8e..00000000 --- a/modules/35-calling-functions/900-stdlib/en/README.md +++ /dev/null @@ -1,12 +0,0 @@ - -PHP, like any other language, comes with a set of useful features. Altogether, they make up the so-called **standard library**. It usually contains thousands of functions you can't remember, and that you don't have to. It's assumed that any programmer knows where to look for their documentation and has a rough idea of what they want to achieve. And the rest is a matter of technique. Programming without the Internet is extremely difficult. - -To newcomers, it often looks like this: "Go I know not whither and fetch I know not what". In other words, most people have no idea how to learn about these functions when they don't know anything at all. Oddly enough, there's no way to know everything you need to know once and for all. As you grow as a developer, you'll learn all the exciting features that can solve your problems more elegantly, thus expanding your toolbox. - -Here are some tips to learn about new features: - -* Always keep track of what you're working with at the moment (the data type). You'll almost always find the function you need in the corresponding section of the documentation, e.g. you have to study string functions to work with strings. -* Open the standard functions section of the topic you are studying every now and then and just run through them,, learning the signatures and ways to use them. -* Read other people's code more often, especially code from the libraries you're using. It's all available on GitHub. - -Another feature of PHP functions from the Standard Library is that they're *available globally*. In other words, you can call them anywhere in your program (this doesn't work with functions you've written yourself). Most standard library functions are centered around some functionality or some type of data. For example, there's a large block of functions for processing strings, working with numbers, and so on. We'll go over some of them as you continue to study. diff --git a/modules/35-calling-functions/900-stdlib/en/data.yml b/modules/35-calling-functions/900-stdlib/en/data.yml deleted file mode 100644 index c10fba7c..00000000 --- a/modules/35-calling-functions/900-stdlib/en/data.yml +++ /dev/null @@ -1,9 +0,0 @@ ---- -name: Standard Library -tips: - - > - [Description of string - functions](https://www.php.net/manual/en/ref.strings.php) -definitions: - - name: Standard Library - description: a set of useful features included with the programming language. diff --git a/modules/35-calling-functions/900-stdlib/es/EXERCISE.md b/modules/35-calling-functions/900-stdlib/es/EXERCISE.md deleted file mode 100644 index b5e6ec4a..00000000 --- a/modules/35-calling-functions/900-stdlib/es/EXERCISE.md +++ /dev/null @@ -1,4 +0,0 @@ - -La función `gettype()` permite determinar el tipo de argumento pasado. El nombre del tipo se devuelve como una cadena. Por ejemplo, llamar a `gettype(10)` devolverá la cadena `"integer"` (integer - número entero). - -Muestra en pantalla el tipo de valor de la variable `$motto`. diff --git a/modules/35-calling-functions/900-stdlib/es/README.md b/modules/35-calling-functions/900-stdlib/es/README.md deleted file mode 100644 index dd84490c..00000000 --- a/modules/35-calling-functions/900-stdlib/es/README.md +++ /dev/null @@ -1,15 +0,0 @@ -PHP viene con un conjunto de funciones útiles. Juntas, forman la **biblioteca estándar**. Por lo general, incluye miles de funciones que no se pueden aprender todas, ni es necesario hacerlo. En esta lección, daremos recomendaciones sobre cómo trabajar con nuevas funciones. - -Se supone que cualquier programador sabe dónde buscar la documentación y tiene una idea aproximada de lo que quiere lograr. Por lo tanto, programar sin internet es extremadamente difícil. - -A menudo, los principiantes no saben a dónde ir ni qué buscar. Estos conocimientos y habilidades se adquieren con la experiencia. Durante el aprendizaje y el trabajo, se familiarizan con funciones más interesantes que resuelven sus problemas de una manera más conveniente. Así es como enriquecen su arsenal. - -Aquí hay algunos consejos sobre cómo aprender sobre nuevas funciones: - -* Siempre es necesario tener en cuenta el tipo de datos con el que se está trabajando. Las funciones necesarias se pueden encontrar en la sección correspondiente de la documentación. Por ejemplo, para trabajar con cadenas, es necesario estudiar las funciones de cadenas. -* De vez en cuando, es necesario abrir la sección de funciones estándar relacionadas con el tema que se está estudiando. Es necesario estudiarlas, sus firmas y formas de uso. -* Es necesario leer el código de otras personas con frecuencia, especialmente el código de bibliotecas que utilizamos. Siempre está disponible en GitHub. - -Otra característica de las funciones de PHP de la biblioteca estándar es que están disponibles globalmente. Se pueden llamar en cualquier parte del programa. Sin embargo, esto no se aplica a las funciones escritas por uno mismo. - -La mayoría de las funciones de la biblioteca estándar se centran en funcionalidades o tipos de datos específicos. Por ejemplo, hay un gran conjunto de funciones para el manejo de cadenas, números, etc. Algunas de ellas las veremos durante el proceso de aprendizaje. diff --git a/modules/35-calling-functions/900-stdlib/es/data.yml b/modules/35-calling-functions/900-stdlib/es/data.yml deleted file mode 100644 index 339745b2..00000000 --- a/modules/35-calling-functions/900-stdlib/es/data.yml +++ /dev/null @@ -1,11 +0,0 @@ ---- -name: Biblioteca estándar -tips: - - > - [Descripción de las funciones de - cadenas](https://www.php.net/manual/es/ref.strings.php) -definitions: - - name: Biblioteca estándar - description: >- - conjunto de funciones útiles que se incluyen en el lenguaje de - programación. diff --git a/modules/35-calling-functions/900-stdlib/index.php b/modules/35-calling-functions/900-stdlib/index.php deleted file mode 100644 index fdaf42e5..00000000 --- a/modules/35-calling-functions/900-stdlib/index.php +++ /dev/null @@ -1,7 +0,0 @@ -- - набор полезных функций, входящий в комплект поставки языка - программирования. diff --git a/modules/40-define-functions/300-parameters/Makefile b/modules/40-define-functions/100-define-function/Makefile similarity index 100% rename from modules/40-define-functions/300-parameters/Makefile rename to modules/40-define-functions/100-define-function/Makefile diff --git a/modules/40-define-functions/100-define/index.php b/modules/40-define-functions/100-define-function/Solution.php similarity index 60% rename from modules/40-define-functions/100-define/index.php rename to modules/40-define-functions/100-define-function/Solution.php index 7970eae4..7d4380b6 100644 --- a/modules/40-define-functions/100-define/index.php +++ b/modules/40-define-functions/100-define-function/Solution.php @@ -4,11 +4,11 @@ // They are needed here for technical reasons // Just ignore them, they do not affect development -namespace HexletBasics\DefineFunctions\Define; +namespace HexletBasics\DefineFunctions\DefineFunction; // BEGIN -function printMotto() +function sayHello() { - print_r("Winter is coming"); + print_r('Hello, World!'); } // END diff --git a/modules/40-define-functions/100-define-function/SolutionTest.php b/modules/40-define-functions/100-define-function/SolutionTest.php new file mode 100644 index 00000000..887bfae6 --- /dev/null +++ b/modules/40-define-functions/100-define-function/SolutionTest.php @@ -0,0 +1,15 @@ +expectOutputString($expected); + sayHello(); + } +} diff --git a/modules/40-define-functions/100-define/description.es.yml b/modules/40-define-functions/100-define-function/description.es.yml similarity index 100% rename from modules/40-define-functions/100-define/description.es.yml rename to modules/40-define-functions/100-define-function/description.es.yml diff --git a/modules/40-define-functions/100-define/en/EXERCISE.md b/modules/40-define-functions/100-define-function/en/EXERCISE.md similarity index 100% rename from modules/40-define-functions/100-define/en/EXERCISE.md rename to modules/40-define-functions/100-define-function/en/EXERCISE.md diff --git a/modules/40-define-functions/100-define/en/README.md b/modules/40-define-functions/100-define-function/en/README.md similarity index 100% rename from modules/40-define-functions/100-define/en/README.md rename to modules/40-define-functions/100-define-function/en/README.md diff --git a/modules/40-define-functions/100-define/en/data.yml b/modules/40-define-functions/100-define-function/en/data.yml similarity index 100% rename from modules/40-define-functions/100-define/en/data.yml rename to modules/40-define-functions/100-define-function/en/data.yml diff --git a/modules/40-define-functions/100-define/es/EXERCISE.md b/modules/40-define-functions/100-define-function/es/EXERCISE.md similarity index 100% rename from modules/40-define-functions/100-define/es/EXERCISE.md rename to modules/40-define-functions/100-define-function/es/EXERCISE.md diff --git a/modules/40-define-functions/100-define/es/README.md b/modules/40-define-functions/100-define-function/es/README.md similarity index 100% rename from modules/40-define-functions/100-define/es/README.md rename to modules/40-define-functions/100-define-function/es/README.md diff --git a/modules/40-define-functions/100-define/es/data.yml b/modules/40-define-functions/100-define-function/es/data.yml similarity index 100% rename from modules/40-define-functions/100-define/es/data.yml rename to modules/40-define-functions/100-define-function/es/data.yml diff --git a/modules/40-define-functions/100-define-function/ru/EXERCISE.md b/modules/40-define-functions/100-define-function/ru/EXERCISE.md new file mode 100644 index 00000000..9cf719e4 --- /dev/null +++ b/modules/40-define-functions/100-define-function/ru/EXERCISE.md @@ -0,0 +1,9 @@ +Сайт выводит приветствие для каждого посетителя. Реализуйте функцию `sayHello()`, которая выводит на экран фразу `Hello, World!`. + +```php + Hello, World! +``` + +В задачах, в которых нужно реализовать функцию, эту функцию вызывать не нужно. Вызывать функцию будут автоматизированные тесты, которые проверяют ее работоспособность. Пример с вызовом выше показан только для того, чтобы вы понимали, как ваша функция будет использоваться. diff --git a/modules/40-define-functions/100-define-function/ru/README.md b/modules/40-define-functions/100-define-function/ru/README.md new file mode 100644 index 00000000..20a03ada --- /dev/null +++ b/modules/40-define-functions/100-define-function/ru/README.md @@ -0,0 +1,127 @@ +До этого момента мы использовали только уже готовые функции: `print_r()`, `strlen()`, `round()` и другие. Но в PHP можно создавать свои собственные функции и пришла пора научиться это делать. + +## Зачем определять функции + +Допустим, у нас есть несколько похожих участков кода: + +```php + Hello, Hexlet! +sayHello('world'); // => Hello, world! +sayHello('PHP'); // => Hello, PHP! +``` + +Вроде бы количество кода не стало меньше, но появилось кое-что другое. Если эта функция будет использоваться в разных местах, то при необходимости изменить текст, нам будет достаточно поправить только определение функции. И чем сложнее будет задача и чем чаще она будет использоваться в разных местах, тем важнее нужно выделять логику в свои функции. + +Определение собственных функций значительно упрощает поддержку программ еще и потому, что позволяет объединять сложные операции в одну. Например, отправка письма на сайте — это достаточно сложный процесс, который включает взаимодействие с внешними системами. Но вся сложность может быть скрыта за одной простой функцией `send($email, $title, $body)`. Один маленький вызов — и много логики внутри. + +## Синтаксис определения + +```php +function имяФункции(параметры) +{ + тело +} +``` + +```text +function greet($name) ← ключевое слово, имя функции и параметр +{ + return 'Hello, ' . $name; ← тело функции +} +``` + +Ключевое слово `function` начинает определение. В `имяФункции` допускается любое имя, как у переменной (но без знака `$`); в скобках указывается список параметров через запятую. Тело функции заключается в фигурные скобки, внутри пишется обычный PHP-код. + +В отличие от обычных данных, функции выполняют действия, поэтому их имена практически всегда должны быть глаголами: «построить что-то», «нарисовать что-то», «открыть что-то». + +Фигурные скобки показывают, какой код относится к телу функции. Посмотрите на пример: + +```php + Hi! +print_r('Программа продолжается…'); +``` + +Тело выполняется в тот момент, когда запускается функция. Причем каждый вызов функции запускает тело независимо от других вызовов. Тело может быть даже пустым: + +```php + 5 +``` + +Здесь `$a` и `$b` являются входными параметрами, `$total` содержит их сумму, `$average` получается делением суммы на 2, а `print_r()` выводит результат. + +При вызове `printAverage(6, 4)` на экран выведется `5`. + +## Переиспользование и читаемость + +Функции помогают избегать дублирования и делают программы более понятными. Название функции само по себе говорит, что она делает. Это особенно важно в больших проектах, где код читают другие программисты (или вы сами через месяц). + +Кстати, создание функции еще называют реализацией, определением и имплементацией. Такие слова часто встречаются на практике. diff --git a/modules/40-define-functions/100-define/ru/data.yml b/modules/40-define-functions/100-define-function/ru/data.yml similarity index 61% rename from modules/40-define-functions/100-define/ru/data.yml rename to modules/40-define-functions/100-define-function/ru/data.yml index d4032eb1..e93d5487 100644 --- a/modules/40-define-functions/100-define/ru/data.yml +++ b/modules/40-define-functions/100-define-function/ru/data.yml @@ -3,4 +3,4 @@ name: Создание (определение) функций tips: - > [Именование в - программировании](https://ru.hexlet.io/blog/posts/naming-in-programming) + программировании](https://ru.hexlet.io/blog/posts/naming-in-programming?utm_source=code-basics&utm_medium=referral&utm_campaign=blog&utm_content=lesson) diff --git a/modules/40-define-functions/100-define/SolutionTest.php b/modules/40-define-functions/100-define/SolutionTest.php deleted file mode 100644 index 8a3a538a..00000000 --- a/modules/40-define-functions/100-define/SolutionTest.php +++ /dev/null @@ -1,17 +0,0 @@ -expectOutputString($expected); - printMotto(); - } -} diff --git a/modules/40-define-functions/100-define/assets/func_arg.png b/modules/40-define-functions/100-define/assets/func_arg.png deleted file mode 100644 index 996bd114..00000000 Binary files a/modules/40-define-functions/100-define/assets/func_arg.png and /dev/null differ diff --git a/modules/40-define-functions/100-define/ru/EXERCISE.md b/modules/40-define-functions/100-define/ru/EXERCISE.md deleted file mode 100644 index b53e5363..00000000 --- a/modules/40-define-functions/100-define/ru/EXERCISE.md +++ /dev/null @@ -1,9 +0,0 @@ -Реализуйте функцию с именем `printMotto()`, которая выведет на экран фразу *Winter is coming*. - -```php - "Winter is coming" -``` - -В задачах, в которых нужно реализовать функцию, эту функцию вызывать не нужно. Вызывать функцию будут автоматизированные тесты, которые проверяют его работоспособность. Пример с вызовом выше показан только для того, чтобы вы понимали, как ваша функция будет использоваться. diff --git a/modules/40-define-functions/100-define/ru/README.md b/modules/40-define-functions/100-define/ru/README.md deleted file mode 100644 index 4552b862..00000000 --- a/modules/40-define-functions/100-define/ru/README.md +++ /dev/null @@ -1,68 +0,0 @@ -Напомним, что функции бывают встроенными и добавленными программистом. С первыми мы уже познакомились. А в этом уроке научимся создавать собственные. - -Определение собственных функций значительно упрощает написание и поддержку программ. Функции позволяют объединять сложные операции в одну. Например, отправка письма на сайте — это достаточно сложный процесс. Он включает в себя взаимодействие с внешними системами. - -Благодаря возможности определять функции, всю сложность можно скрыть за одной простой функцией: - -```php - 'Hello, Hexlet!' -``` - -В отличие от обычных данных, функции выполняют действия, поэтому их имена практически всегда должны быть глаголами: «построить что-то», «нарисовать что-то», «открыть что-то». - -Все, что описывается в фигурных скобках после имени функции, называется телом функции. Внутри тела можно описывать любой код. Можно сказать, что это маленькая самостоятельная программа, набор произвольных инструкций. - -Тело выполняется в тот момент, когда запускается функция. Причем каждый вызов функции запускает тело независимо от других вызовов. - -Тело функции может быть пустым: - -```php -assertEquals('he...', truncate('hexlet', 2)); + $this->assertEquals('it w...', truncate('it works!', 4)); + } +} diff --git a/modules/40-define-functions/200-return/description.es.yml b/modules/40-define-functions/150-return/description.es.yml similarity index 100% rename from modules/40-define-functions/200-return/description.es.yml rename to modules/40-define-functions/150-return/description.es.yml diff --git a/modules/40-define-functions/200-return/en/EXERCISE.md b/modules/40-define-functions/150-return/en/EXERCISE.md similarity index 100% rename from modules/40-define-functions/200-return/en/EXERCISE.md rename to modules/40-define-functions/150-return/en/EXERCISE.md diff --git a/modules/40-define-functions/200-return/en/README.md b/modules/40-define-functions/150-return/en/README.md similarity index 100% rename from modules/40-define-functions/200-return/en/README.md rename to modules/40-define-functions/150-return/en/README.md diff --git a/modules/40-define-functions/200-return/en/data.yml b/modules/40-define-functions/150-return/en/data.yml similarity index 100% rename from modules/40-define-functions/200-return/en/data.yml rename to modules/40-define-functions/150-return/en/data.yml diff --git a/modules/40-define-functions/200-return/es/EXERCISE.md b/modules/40-define-functions/150-return/es/EXERCISE.md similarity index 100% rename from modules/40-define-functions/200-return/es/EXERCISE.md rename to modules/40-define-functions/150-return/es/EXERCISE.md diff --git a/modules/40-define-functions/200-return/es/README.md b/modules/40-define-functions/150-return/es/README.md similarity index 100% rename from modules/40-define-functions/200-return/es/README.md rename to modules/40-define-functions/150-return/es/README.md diff --git a/modules/40-define-functions/200-return/es/data.yml b/modules/40-define-functions/150-return/es/data.yml similarity index 100% rename from modules/40-define-functions/200-return/es/data.yml rename to modules/40-define-functions/150-return/es/data.yml diff --git a/modules/40-define-functions/150-return/ru/EXERCISE.md b/modules/40-define-functions/150-return/ru/EXERCISE.md new file mode 100644 index 00000000..c338e463 --- /dev/null +++ b/modules/40-define-functions/150-return/ru/EXERCISE.md @@ -0,0 +1,33 @@ +Реализуйте функцию `truncate()`, которая обрезает переданную строку до указанного количества символов, добавляет в конце троеточие и возвращает получившуюся строку. Подобная логика часто используется на сайтах, чтобы отобразить длинный текст в сокращенном виде. + +Функция принимает два параметра: + +1. Строка, которую нужно обрезать +2. Число символов, которые нужно оставить + +Пример того, как должна работать написанная вами функция: + +```php + HEXLET + +$result2 = shout('code-basics'); +print_r($result2); // => CODE-BASICS +``` + +В отличие от `print_r()`, `return` ничего не печатает. Оно просто возвращает значение. Решение о том, что с ним делать, принимает вызывающий код. + +При вызове функции `shout('hexlet')` сначала выполняется выражение `strtoupper($name)`. Оно возвращает строку `'HEXLET'`. Затем `return` отдает это значение наружу, туда, откуда была вызвана функция. В нашем случае это значение сохраняется в переменную `$result`, а потом выводится на экран через `print_r()`. + +А что вернет функция, в которой нет `return`? Проверим на функции из прошлого урока, которая только печатает текст: + +```php + NULL +``` + +Функция без возврата всегда возвращает `null` — специальное значение, которое означает «ничего нет». + +## Возврат вычисленного выражения + +Функции не обязаны просто возвращать параметр. Обычно в `return` указывается **выражение**, которое сначала вычисляется, а потом результат передается наружу. + +```php + Aria Stark +``` + +Возвращать можно и значение переменной. Здесь нужно руководствоваться принципами читаемости кода: + +```php + HEXLET +``` + +Подобный код встречается в реальных программах постоянно. Например, когда пользователь регистрируется на сайте, он может ввести email с лишними пробелами или буквами в разном регистре: ` SuppORT@hexlet.IO`. Перед записью в базу данных такой email готовят точно так же: обрезают пробельные символы и приводят к нижнему регистру. + +## Код после `return` + +Когда PHP доходит до инструкции `return`, выполнение функции останавливается. Все, что написано после нее внутри функции, **не будет выполнено**: + +```php + ? +``` diff --git a/modules/40-define-functions/200-return/ru/assets/sum-php.jpg b/modules/40-define-functions/150-return/ru/assets/sum-php.jpg similarity index 100% rename from modules/40-define-functions/200-return/ru/assets/sum-php.jpg rename to modules/40-define-functions/150-return/ru/assets/sum-php.jpg diff --git a/modules/40-define-functions/150-return/ru/data.yml b/modules/40-define-functions/150-return/ru/data.yml new file mode 100644 index 00000000..62b6f777 --- /dev/null +++ b/modules/40-define-functions/150-return/ru/data.yml @@ -0,0 +1,5 @@ +--- +name: Возврат значений +tips: + - | + [Инструкция return](https://www.php.net/manual/ru/function.return.php) diff --git a/modules/40-define-functions/500-reading-documentation/Makefile b/modules/40-define-functions/200-default-parameters/Makefile similarity index 100% rename from modules/40-define-functions/500-reading-documentation/Makefile rename to modules/40-define-functions/200-default-parameters/Makefile diff --git a/modules/40-define-functions/340-default-parameters/index.php b/modules/40-define-functions/200-default-parameters/Solution.php similarity index 76% rename from modules/40-define-functions/340-default-parameters/index.php rename to modules/40-define-functions/200-default-parameters/Solution.php index d4d986c5..5b270f3d 100644 --- a/modules/40-define-functions/340-default-parameters/index.php +++ b/modules/40-define-functions/200-default-parameters/Solution.php @@ -1,6 +1,6 @@ assertEquals('****1234', getHiddenCard('1234123412341234')); + $this->assertEquals('****4321', getHiddenCard('1234123412344321')); + $this->assertEquals('***4321', getHiddenCard('1234123412344321', 3)); + } +} diff --git a/modules/40-define-functions/340-default-parameters/description.es.yml b/modules/40-define-functions/200-default-parameters/description.es.yml similarity index 100% rename from modules/40-define-functions/340-default-parameters/description.es.yml rename to modules/40-define-functions/200-default-parameters/description.es.yml diff --git a/modules/40-define-functions/340-default-parameters/en/EXERCISE.md b/modules/40-define-functions/200-default-parameters/en/EXERCISE.md similarity index 100% rename from modules/40-define-functions/340-default-parameters/en/EXERCISE.md rename to modules/40-define-functions/200-default-parameters/en/EXERCISE.md diff --git a/modules/40-define-functions/340-default-parameters/en/README.md b/modules/40-define-functions/200-default-parameters/en/README.md similarity index 100% rename from modules/40-define-functions/340-default-parameters/en/README.md rename to modules/40-define-functions/200-default-parameters/en/README.md diff --git a/modules/40-define-functions/340-default-parameters/en/data.yml b/modules/40-define-functions/200-default-parameters/en/data.yml similarity index 100% rename from modules/40-define-functions/340-default-parameters/en/data.yml rename to modules/40-define-functions/200-default-parameters/en/data.yml diff --git a/modules/40-define-functions/340-default-parameters/es/EXERCISE.md b/modules/40-define-functions/200-default-parameters/es/EXERCISE.md similarity index 100% rename from modules/40-define-functions/340-default-parameters/es/EXERCISE.md rename to modules/40-define-functions/200-default-parameters/es/EXERCISE.md diff --git a/modules/40-define-functions/340-default-parameters/es/README.md b/modules/40-define-functions/200-default-parameters/es/README.md similarity index 100% rename from modules/40-define-functions/340-default-parameters/es/README.md rename to modules/40-define-functions/200-default-parameters/es/README.md diff --git a/modules/40-define-functions/340-default-parameters/es/data.yml b/modules/40-define-functions/200-default-parameters/es/data.yml similarity index 100% rename from modules/40-define-functions/340-default-parameters/es/data.yml rename to modules/40-define-functions/200-default-parameters/es/data.yml diff --git a/modules/40-define-functions/200-default-parameters/ru/EXERCISE.md b/modules/40-define-functions/200-default-parameters/ru/EXERCISE.md new file mode 100644 index 00000000..81034a7c --- /dev/null +++ b/modules/40-define-functions/200-default-parameters/ru/EXERCISE.md @@ -0,0 +1,26 @@ +Реализуйте функцию `getHiddenCard()`, которая принимает на вход номер кредитки (состоящий из 16 цифр) в виде строки и возвращает его скрытую версию, которая может использоваться на сайте для отображения. Если исходная карта имела номер *2034399002125581*, то скрытая версия выглядит так *\*\*\*\*5581*. Другими словами, функция заменяет первые 12 символов, на звездочки. Количество звездочек регулируется вторым, необязательным, параметром. Значение по умолчанию — 4. + +```php + Hi +print_r(repeat('Hi', 3)); // => HiHiHi +``` + +В этом примере используется встроенная функция `str_repeat()`. Она работает так: берется исходная строка и повторяется указанное количество раз. Например, `str_repeat('A', 5)` вернет `'AAAAA'`. Эта функция часто применяется при генерации шаблонов, разделителей и повторяющихся фрагментов текста. + +```text +function repeat($text, $times = 2) ← $times имеет значение по умолчанию +{ + ... +} + +repeat('go') → $times = 2 (по умолчанию) +repeat('go', 5) → $times = 5 (явно указано) +``` + +Значение по умолчанию выглядит как обычное присваивание в определении. Оно срабатывает только в том случае, если параметр не передан. К этому нужно привыкнуть. + +Значение по умолчанию может быть даже в том случае, когда параметр один: + +```php + "nothing" +myPrint('Hexlet'); // => "Hexlet" +``` + +## Пример: склейка слов с разделителем + +По умолчанию слова соединяются пробелом, но можно указать другой символ: + +```php + King Road +print_r(joinWords('Dragon', 'stone', '-')); // => Dragon-stone +``` + +## Пример: несколько параметров по умолчанию + +Функция может содержать более одного параметра со значениями по умолчанию. Например, сделаем функцию, которая строит строку-разделитель. По умолчанию символом является дефис, а длина равна 10: + +```php + ---------- +print_r(makeLine('*')); // => ********** +print_r(makeLine('*', 5)); // => ***** +print_r(makeLine('#', 3)); // => ### +``` + +## Ограничение на порядок параметров + +Необязательные параметры всегда указываются в конце списка параметров. С точки зрения синтаксиса невозможно создать функцию, у которой после необязательного параметра идет обязательный: + +```php +assertEquals($expected, sayHurrayThreeTimes()); - } -} diff --git a/modules/40-define-functions/200-return/index.php b/modules/40-define-functions/200-return/index.php deleted file mode 100644 index 76ff85f7..00000000 --- a/modules/40-define-functions/200-return/index.php +++ /dev/null @@ -1,11 +0,0 @@ - 'hurray! hurray! hurray!' -``` - -Вам не нужно вызывать свою функцию, только определить её. diff --git a/modules/40-define-functions/200-return/ru/README.md b/modules/40-define-functions/200-return/ru/README.md deleted file mode 100644 index d3c8510d..00000000 --- a/modules/40-define-functions/200-return/ru/README.md +++ /dev/null @@ -1,140 +0,0 @@ -Функции, которые мы определяли в предыдущих уроках, заканчивали свою работу тем, что печатали на экран какие-то данные: - -```php - NULL -``` - -Изменим функцию `greeting()` так, чтобы она начала возвращать данные вместо их печати. Для этого нам понадобится выполнить возврат вместо печати на экран: - -```php - 'Hello, Hexlet!' -// И даже выполнить какие-то действия над результатом -print_r(strtoupper($message)); // => 'HELLO, HEXLET!' -``` - -Любой код после `return` не выполняется: - -```php - ? -``` diff --git a/modules/40-define-functions/200-return/ru/assets/func_return.png b/modules/40-define-functions/200-return/ru/assets/func_return.png deleted file mode 100644 index c0f696db..00000000 Binary files a/modules/40-define-functions/200-return/ru/assets/func_return.png and /dev/null differ diff --git a/modules/40-define-functions/200-return/ru/data.yml b/modules/40-define-functions/200-return/ru/data.yml deleted file mode 100644 index b9db59ab..00000000 --- a/modules/40-define-functions/200-return/ru/data.yml +++ /dev/null @@ -1,3 +0,0 @@ ---- -name: Возврат значений -tips: [] diff --git a/modules/45-logic/15-predicates/Makefile b/modules/40-define-functions/250-named-arguments/Makefile similarity index 100% rename from modules/45-logic/15-predicates/Makefile rename to modules/40-define-functions/250-named-arguments/Makefile diff --git a/modules/40-define-functions/250-named-arguments/Solution.php b/modules/40-define-functions/250-named-arguments/Solution.php new file mode 100644 index 00000000..7aa577d2 --- /dev/null +++ b/modules/40-define-functions/250-named-arguments/Solution.php @@ -0,0 +1,10 @@ +assertEquals('python', trimAndRepeat('python')); + $this->assertEquals('on', trimAndRepeat('python', offset: 4)); + $this->assertEquals('pythonpython', trimAndRepeat('python', repetitions: 2)); + $this->assertEquals('onon', trimAndRepeat('python', offset: 4, repetitions: 2)); + } +} diff --git a/modules/40-define-functions/250-named-arguments/description.es.yml b/modules/40-define-functions/250-named-arguments/description.es.yml new file mode 100644 index 00000000..f68282a5 --- /dev/null +++ b/modules/40-define-functions/250-named-arguments/description.es.yml @@ -0,0 +1,50 @@ +--- + +name: Argumentos con nombre +theory: | + A partir de PHP 8, los argumentos se pueden pasar por el nombre del parámetro. El nombre se escribe sin `$`, seguido de dos puntos: + + ```php + 1 235 + ``` + +instructions: | + Completa la función `trimAndRepeat()`. Recibe una cadena, un `offset` — el número de caracteres que hay que recortar por la izquierda (0 por defecto), y `repetitions` — cuántas veces hay que repetir la cadena (1 por defecto). La firma ya está definida en la plantilla. La función devuelve la cadena resultante: + + ```php + + [Argumentos con nombre en la + documentación](https://www.php.net/manual/es/functions.arguments.php#functions.named-arguments) diff --git a/modules/40-define-functions/250-named-arguments/en/EXERCISE.md b/modules/40-define-functions/250-named-arguments/en/EXERCISE.md new file mode 100644 index 00000000..518258da --- /dev/null +++ b/modules/40-define-functions/250-named-arguments/en/EXERCISE.md @@ -0,0 +1,15 @@ +Finish the `trimAndRepeat()` function. It takes a string, an `offset` — the number of characters to cut off from the left (0 by default), and `repetitions` — how many times to repeat the string (1 by default). The signature is already defined in the template. The function returns the resulting string: + +```php + 1 235 +``` diff --git a/modules/40-define-functions/250-named-arguments/en/data.yml b/modules/40-define-functions/250-named-arguments/en/data.yml new file mode 100644 index 00000000..94a8a2c2 --- /dev/null +++ b/modules/40-define-functions/250-named-arguments/en/data.yml @@ -0,0 +1,6 @@ +--- +name: Named arguments +tips: + - > + [Named arguments in the + documentation](https://www.php.net/manual/en/functions.arguments.php#functions.named-arguments) diff --git a/modules/40-define-functions/250-named-arguments/es/EXERCISE.md b/modules/40-define-functions/250-named-arguments/es/EXERCISE.md new file mode 100644 index 00000000..061c63fd --- /dev/null +++ b/modules/40-define-functions/250-named-arguments/es/EXERCISE.md @@ -0,0 +1,15 @@ +Completa la función `trimAndRepeat()`. Recibe una cadena, un `offset` — el número de caracteres que hay que recortar por la izquierda (0 por defecto), y `repetitions` — cuántas veces hay que repetir la cadena (1 por defecto). La firma ya está definida en la plantilla. La función devuelve la cadena resultante: + +```php + 1 235 +``` diff --git a/modules/40-define-functions/250-named-arguments/es/data.yml b/modules/40-define-functions/250-named-arguments/es/data.yml new file mode 100644 index 00000000..aaa5d118 --- /dev/null +++ b/modules/40-define-functions/250-named-arguments/es/data.yml @@ -0,0 +1,6 @@ +--- +name: Argumentos con nombre +tips: + - > + [Argumentos con nombre en la + documentación](https://www.php.net/manual/es/functions.arguments.php#functions.named-arguments) diff --git a/modules/40-define-functions/250-named-arguments/ru/EXERCISE.md b/modules/40-define-functions/250-named-arguments/ru/EXERCISE.md new file mode 100644 index 00000000..66000aae --- /dev/null +++ b/modules/40-define-functions/250-named-arguments/ru/EXERCISE.md @@ -0,0 +1,24 @@ +Программа готовит текст уведомлений: убирает ненужные символы с начала и повторяет сообщение нужное количество раз. Допишите функцию `trimAndRepeat()`, которая принимает три параметра: + +* Строку +* `offset` — число символов, на которое нужно обрезать строку слева +* `repetitions` — сколько раз нужно повторить строку перед возвратом получившейся строки + +Число символов для среза по умолчанию равно 0, а количество повторений по умолчанию равно 1. Сигнатура функции с этими значениями уже задана в шаблоне, вам осталось дописать тело. + +Функция должна возвращать полученную строку. + +```php + HiHiHi +``` + +Именованные аргументы можно комбинировать с позиционными, при этом позиционные идут первыми. Такой вызов позволяет указывать только те параметры, которые нужно переопределить: + +```php + HiHiHi +``` + +## Когда использовать именованные аргументы + +Именованные аргументы полезны, когда у функции есть несколько параметров и не все из них нужно менять. В таких случаях можно указать только те параметры, которые важны в конкретном вызове, а остальные оставить со значениями по умолчанию. + +Вы уже знаете, что у встроенной функции `round()` второй параметр необязательный. В именованном вызове используются имена параметров из сигнатуры в документации — `round(int|float $num, int $precision = 0)`: + +```php + 1 235 + +// С именованными — указываем только нужный +number_format(1234.567, thousands_separator: ' '); // => 1 235 +``` + +Разделитель указывать стало проще, даже несмотря на то, что перед ним в списке параметров идут еще два. Именованные аргументы делают вызовы понятнее. Читая код, сразу видно, какое значение к какому параметру относится. diff --git a/modules/40-define-functions/250-named-arguments/ru/data.yml b/modules/40-define-functions/250-named-arguments/ru/data.yml new file mode 100644 index 00000000..ac1151f4 --- /dev/null +++ b/modules/40-define-functions/250-named-arguments/ru/data.yml @@ -0,0 +1,6 @@ +--- +name: Именованные аргументы +tips: + - > + [Именованные аргументы в + документации](https://www.php.net/manual/ru/functions.arguments.php#functions.named-arguments) diff --git a/modules/40-define-functions/300-parameters/SolutionTest.php b/modules/40-define-functions/300-parameters/SolutionTest.php deleted file mode 100644 index f5468f49..00000000 --- a/modules/40-define-functions/300-parameters/SolutionTest.php +++ /dev/null @@ -1,16 +0,0 @@ -assertEquals('Hex...', truncate('Hexlet', 3)); - $this->assertEquals('Hello...', truncate('Hello world', 5)); - } -} diff --git a/modules/40-define-functions/300-parameters/description.es.yml b/modules/40-define-functions/300-parameters/description.es.yml deleted file mode 100644 index 4be527b6..00000000 --- a/modules/40-define-functions/300-parameters/description.es.yml +++ /dev/null @@ -1,111 +0,0 @@ ---- - -name: Parámetros de funciones -theory: | - Las funciones no solo pueden devolver valores, sino también recibirlos como parámetros. Ya nos hemos encontrado con parámetros de funciones: - - ```php - '¡fun...' - ``` - - Puedes implementar esta función de diferentes maneras, solo te daremos una pista. Para resolverlo de esta manera, necesitarás extraer una subcadena de la cadena pasada como primer parámetro a la función `truncate()`. Para hacer esto, utiliza la función [substr()](https://www.php.net/manual/es/function.substr.php). Piensa, en función de la tarea, desde qué índice y con qué longitud debes extraer la subcadena. - - ```php - 'it w...' -``` - -This function can be implemented in different ways, we'll tell you just one of them. To do it this way, you need to take a substring from the string passed as the first parameter to the `truncate()` function. Use the [substr()](https://www.php.net/manual/en/function.substr.php) function to do this. Think, based on the assignment, which index should you extract the substring from, and how long should it be? - - ```php - '¡fun...' -``` - -Puedes implementar esta función de diferentes maneras, solo te daremos una pista. Para resolverlo de esta manera, necesitarás extraer una subcadena de la cadena pasada como primer parámetro a la función `truncate()`. Para hacer esto, utiliza la función [substr()](https://www.php.net/manual/es/function.substr.php). Piensa, en función de la tarea, desde qué índice y con qué longitud debes extraer la subcadena. - - ```php - 'it w...' -``` - -Реализовать эту функцию можно различными способами, подскажем лишь один из них. Для решения этим способом вам понадобится взять подстроку из строки, переданной первым параметром в функцию `truncate()`. Используйте для этого функцию [substr()](https://www.php.net/manual/ru/function.substr.php). Подумайте, исходя из задания, с какого индекса и какой длины вам надо извлечь подстроку? - - ```php - $parameter->getType()?->getName(), + $reflection->getParameters() + ); + $this->assertEquals(['string', 'int'], $parameterTypes, 'You should add type declarations for parameters!'); + $this->assertEquals('string', $reflection->getReturnType()?->getName(), 'You should add a return type declaration!'); + + $this->assertEquals('python', wordMultiply('python', 1)); + $this->assertEquals('pythonpythonpython', wordMultiply('python', 3)); + $this->assertEquals('', wordMultiply('java', 0)); + } +} diff --git a/modules/40-define-functions/300-type-annotations/description.es.yml b/modules/40-define-functions/300-type-annotations/description.es.yml new file mode 100644 index 00000000..2f23b237 --- /dev/null +++ b/modules/40-define-functions/300-type-annotations/description.es.yml @@ -0,0 +1,54 @@ +--- + +name: Declaraciones de tipos +theory: | + PHP admite **declaraciones de tipos** (también conocidas como type hints): puedes indicar los tipos de los parámetros y del valor de retorno de una función. Los tipos de los parámetros se escriben antes del nombre del parámetro, y el tipo de retorno va después de la lista de parámetros, separado por dos puntos: + + ```php + 5 + ``` + + A diferencia de muchos lenguajes, PHP comprueba los tipos en tiempo de ejecución. Un valor incompatible provoca un `TypeError`, mientras que los valores compatibles se convierten automáticamente (`add('2', 3)` devuelve `5`). + + En esta etapa, basta con los tipos simples: `int`, `float`, `string`, `bool`. Si una función no devuelve nada, el tipo de retorno es `void`: + + ```php + phpphp + print_r(wordMultiply($text, 0)); // => + ``` + + Añade declaraciones de tipos a la definición de la función. + + ## Pistas + + * No olvides la declaración del tipo de retorno + * Usa `str_repeat()` para repetir la cadena + +tips: + - > + [Declaraciones de tipos en la + documentación](https://www.php.net/manual/es/language.types.declarations.php) diff --git a/modules/40-define-functions/300-type-annotations/en/EXERCISE.md b/modules/40-define-functions/300-type-annotations/en/EXERCISE.md new file mode 100644 index 00000000..529a0350 --- /dev/null +++ b/modules/40-define-functions/300-type-annotations/en/EXERCISE.md @@ -0,0 +1,16 @@ +Implement the `wordMultiply()` function. It takes a string and a number, and returns the string repeated that many times. If zero is passed, it returns an empty string: + +```php + phpphp +print_r(wordMultiply($text, 0)); // => +``` + +Add type declarations to the function definition. + +## Hints + +* Don't forget the return type declaration +* Use `str_repeat()` to repeat the string diff --git a/modules/40-define-functions/300-type-annotations/en/README.md b/modules/40-define-functions/300-type-annotations/en/README.md new file mode 100644 index 00000000..a83f78b0 --- /dev/null +++ b/modules/40-define-functions/300-type-annotations/en/README.md @@ -0,0 +1,27 @@ +PHP supports **type declarations** (also known as type hints): you can specify the types of parameters and the return value of a function. Parameter types are written before the parameter name, the return type goes after the parameter list, separated by a colon: + +```php + 5 +``` + +Unlike many languages, PHP checks types at runtime. An incompatible value causes a `TypeError`, while compatible values are coerced automatically (`add('2', 3)` returns `5`). + +At this stage, the simple types are enough: `int`, `float`, `string`, `bool`. If a function returns nothing, the return type is `void`: + +```php + + [Type declarations in the + documentation](https://www.php.net/manual/en/language.types.declarations.php) diff --git a/modules/40-define-functions/300-type-annotations/es/EXERCISE.md b/modules/40-define-functions/300-type-annotations/es/EXERCISE.md new file mode 100644 index 00000000..580515ae --- /dev/null +++ b/modules/40-define-functions/300-type-annotations/es/EXERCISE.md @@ -0,0 +1,16 @@ +Implementa la función `wordMultiply()`. Recibe una cadena y un número, y devuelve la cadena repetida esa cantidad de veces. Si se pasa cero, devuelve una cadena vacía: + +```php + phpphp +print_r(wordMultiply($text, 0)); // => +``` + +Añade declaraciones de tipos a la definición de la función. + +## Pistas + +* No olvides la declaración del tipo de retorno +* Usa `str_repeat()` para repetir la cadena diff --git a/modules/40-define-functions/300-type-annotations/es/README.md b/modules/40-define-functions/300-type-annotations/es/README.md new file mode 100644 index 00000000..c82bbbb7 --- /dev/null +++ b/modules/40-define-functions/300-type-annotations/es/README.md @@ -0,0 +1,27 @@ +PHP admite **declaraciones de tipos** (también conocidas como type hints): puedes indicar los tipos de los parámetros y del valor de retorno de una función. Los tipos de los parámetros se escriben antes del nombre del parámetro, y el tipo de retorno va después de la lista de parámetros, separado por dos puntos: + +```php + 5 +``` + +A diferencia de muchos lenguajes, PHP comprueba los tipos en tiempo de ejecución. Un valor incompatible provoca un `TypeError`, mientras que los valores compatibles se convierten automáticamente (`add('2', 3)` devuelve `5`). + +En esta etapa, basta con los tipos simples: `int`, `float`, `string`, `bool`. Si una función no devuelve nada, el tipo de retorno es `void`: + +```php + + [Declaraciones de tipos en la + documentación](https://www.php.net/manual/es/language.types.declarations.php) diff --git a/modules/40-define-functions/300-type-annotations/ru/EXERCISE.md b/modules/40-define-functions/300-type-annotations/ru/EXERCISE.md new file mode 100644 index 00000000..3f2aa9e9 --- /dev/null +++ b/modules/40-define-functions/300-type-annotations/ru/EXERCISE.md @@ -0,0 +1,21 @@ +Приложение создает текстовые разделители из повторяющихся символов — например, `-------` или `=====`. Реализуйте функцию `wordMultiply()`. Она должна принимать два параметра: + +* Строку +* Число, которое обозначает, сколько раз нужно повторить строку + +И возвращает строку, которая повторяется n-раз. Если передается ноль, то возвращается пустая строка. + +```php + phpphp +print_r(wordMultiply($text, 0)); // => +``` + +Укажите объявления типов при определении функции. + +## Подсказки + +* Не забудьте, что тип также нужно указать и у возвращаемого значения +* Повторить строку поможет функция `str_repeat()` diff --git a/modules/40-define-functions/300-type-annotations/ru/README.md b/modules/40-define-functions/300-type-annotations/ru/README.md new file mode 100644 index 00000000..1382028b --- /dev/null +++ b/modules/40-define-functions/300-type-annotations/ru/README.md @@ -0,0 +1,115 @@ +В PHP в функцию можно передать любые значения. Иногда это усложняет понимание кода: не всегда ясно, что именно ожидает функция и что она возвращает. Чтобы сделать код понятнее, в PHP есть **объявления типов** (их еще называют аннотациями типов или type hints). С их помощью можно явно указать, какие значения принимает функция и какой результат она возвращает. Таким образом мы решаем сразу несколько задач: + +- Улучшаем работу редактора кода, получаем подсказки, лучше автодополнение и тому подобное. +- Помогаем ИИ-агентам быстрее видеть структуру и принимать более правильные решения, минимизируя случайные ошибки. +- Появляется возможность проверять корректность программы без ее запуска, за счет статической проверки. Такая проверка не гарантирует, что логика программы написана правильно, но, по крайней мере, в ней не будет ошибок типов. + +## Как указывать типы параметров + +Объявление типов описывает два элемента. Типы параметров указываются прямо в определении функции перед именем каждого параметра. Тип возвращаемого результата указывается после списка параметров через двоеточие. + +Разберем на примере функции, которая вычисляет сумму двух переданных значений: + +```php + 5 +``` + +```text +function concat(string $a, string $b): string + │ │ │ + │ │ └── тип возвращаемого значения + │ └── тип параметра $b + └── тип параметра $a +``` + +Теперь редактор кода будет подсказывать, что функция `add()` принимает два числа и возвращает число. Если попытаться передать неподходящее значение, редактор подсветит это как проблему и предупредит. + +Кстати, такие записи вы уже видели. В уроке про необязательные параметры мы разбирали сигнатуру функции `round()` из документации — `round(int|float $num, int $precision = 0): float`. Это и есть объявления типов. + +## Типы проверяются при выполнении + +В отличие от многих языков, PHP не только подсказывает типы редактору, но и проверяет их во время работы программы. Если передать значение несовместимого типа, программа завершится с ошибкой `TypeError`: + +```php + 5 +``` + +Это то же самое поведение, которое мы разбирали в уроке про слабую типизацию. + +## Какие типы используются в объявлениях + +На этом этапе достаточно знать объявления для простых, примитивных типов данных: + +- `int` для целых чисел, `float` для чисел с плавающей точкой +- `string` для строк +- `bool` для логических значений (true или false) + +```php + Anna, 25 лет, рост 1.7 +``` + +Если функция ничего не возвращает, то в качестве возвращаемого типа указывается `void`. Например, функция может только печатать текст на экран: + +```php + Hello, Anna! +``` + +## Пример с параметрами по умолчанию + +Объявления типов работают одинаково как для обязательных параметров, так и для тех, у которых есть значение по умолчанию. Сначала указывается тип, потом имя параметра и через `=` стандартное значение: + +```php + Hello, Anna +print_r(greet('Kirill', 'Hi')); // => Hi, Kirill +``` + +В этом примере `$name` является обязательным параметром, а `$greeting` имеет значение по умолчанию. Объявления показывают типы обоих параметров и возвращаемого результата. + +## Объявления типов и проверка кода + +Кроме проверки во время выполнения, существуют инструменты **статической проверки кода**, то есть проверки, выполняемой без запуска. «Статическая» значит, что проверка происходит еще до запуска программы. Инструмент читает исходный код и сверяет, соответствуют ли переданные значения указанным типам. Например, если функция принимает строку, а вы передадите число, то при статической проверке это будет показано как ошибка. + +Особенно удобно, когда такие ошибки подсвечивает редактор прямо во время написания кода. Это позволяет сразу увидеть проблему и исправить ее, не дожидаясь запуска программы. Благодаря этому многие неожиданные ошибки отлавливаются заранее и в работающем коде их становится меньше. + +Объявления типов не являются обязательными. Функции можно писать и без них, PHP все равно будет работать. Но когда объявления есть, код становится понятнее для людей и удобнее для редакторов. Указание типов в своем коде считается хорошей практикой. diff --git a/modules/40-define-functions/300-type-annotations/ru/data.yml b/modules/40-define-functions/300-type-annotations/ru/data.yml new file mode 100644 index 00000000..b7924f91 --- /dev/null +++ b/modules/40-define-functions/300-type-annotations/ru/data.yml @@ -0,0 +1,6 @@ +--- +name: Объявления типов +tips: + - > + [Объявления типов в + документации](https://www.php.net/manual/ru/language.types.declarations.php) diff --git a/modules/40-define-functions/340-default-parameters/SolutionTest.php b/modules/40-define-functions/340-default-parameters/SolutionTest.php deleted file mode 100644 index b776f354..00000000 --- a/modules/40-define-functions/340-default-parameters/SolutionTest.php +++ /dev/null @@ -1,21 +0,0 @@ -assertEquals($expected1, $actual1); - - $expected2 = '**4321'; - $actual2 = getHiddenCard('1234123412344321', 2); - $this->assertEquals($expected2, $actual2); - } -} diff --git a/modules/40-define-functions/340-default-parameters/ru/EXERCISE.md b/modules/40-define-functions/340-default-parameters/ru/EXERCISE.md deleted file mode 100644 index 9b3f1030..00000000 --- a/modules/40-define-functions/340-default-parameters/ru/EXERCISE.md +++ /dev/null @@ -1,21 +0,0 @@ - -Реализуйте функцию `getHiddenCard()`, который принимает на вход номер кредитки (состоящий из 16 цифр) в виде строки и возвращает его скрытую версию, которая может использоваться на сайте для отображения. Если исходная карта имела номер *2034399002125581*, то скрытая версия выглядит так *\*\*\*\*5581*. Другими словами, функция заменяет первые 12 символов, на звездочки. Количество звездочек регулируется вторым необязательным параметром. Значение по умолчанию — 4. - -```php - "nothing" -myPrint("Hexlet"); // => "Hexlet" -``` - -Параметров со значениями по умолчанию может быть сколько угодно: - -```php -assertEquals(75, amountPerPerson(300, 4, 0)); + $this->assertEquals(90, amountPerPerson(300, 4, 20)); + $this->assertEquals(129, amountPerPerson(350, 3, 10)); + $this->assertEquals(34, amountPerPerson(100, 3, 0)); + } +} diff --git a/modules/40-define-functions/350-modules/description.es.yml b/modules/40-define-functions/350-modules/description.es.yml new file mode 100644 index 00000000..42043eb9 --- /dev/null +++ b/modules/40-define-functions/350-modules/description.es.yml @@ -0,0 +1,55 @@ +--- + +name: Módulos +theory: | + A medida que un programa crece, el código se divide en archivos separados. En PHP, un archivo se conecta con la instrucción `require` — después de eso, todas sus funciones quedan disponibles: + + ```php + Hi! + ``` + + Las pruebas de este curso usan el mismo mecanismo: cargan tu solución con `require 'Solution.php';`. + + `include` se diferencia de `require` en cómo se gestiona un archivo inexistente: `include` emite una advertencia y el programa continúa, mientras que `require` se detiene con un error. `require_once` carga un archivo solo una vez, lo cual es importante para archivos con funciones: volver a declarar una función provoca un error. + + A diferencia de muchos lenguajes, las funciones integradas de PHP están disponibles en todas partes sin necesidad de importar nada. Por ejemplo, `floor()` redondea un número hacia abajo y `ceil()` hacia arriba: + + ```php + 7 + print_r(ceil(7.1)); // => 8 + ``` + + Para evitar conflictos de nombres, PHP tiene **espacios de nombres** — has visto la línea `namespace HexletBasics\...;` al principio de cada ejercicio. Se estudian en detalle más adelante, en Hexlet. + +instructions: | + Implementa la función `amountPerPerson()`. Recibe el total de la cuenta de un restaurante, el número de personas y el porcentaje de propina, y devuelve la cantidad que paga cada persona. El resultado se redondea hacia arriba — nadie debe pagar de menos. + + Usa la función integrada `ceil()` para redondear. Está disponible de inmediato — no hay que cargar nada. + + ```php + 90 + + // Cuenta 350, 3 personas, propina del 10% — 385 en total, cada uno paga 129 + print_r(amountPerPerson(350, 3, 10)); // => 129 + ``` + + ## Pista + + * Primero calcula el total con la propina, luego divídelo entre el número de personas y redondea hacia arriba + * `ceil()` devuelve un `float`, mientras que la función debe devolver un `int` — la conversión de tipos te ayudará + +tips: + - | + [La instrucción require](https://www.php.net/manual/es/function.require.php) + - | + [La instrucción include](https://www.php.net/manual/es/function.include.php) diff --git a/modules/40-define-functions/350-modules/en/EXERCISE.md b/modules/40-define-functions/350-modules/en/EXERCISE.md new file mode 100644 index 00000000..a300ed2d --- /dev/null +++ b/modules/40-define-functions/350-modules/en/EXERCISE.md @@ -0,0 +1,18 @@ +Implement the `amountPerPerson()` function. It takes a restaurant bill total, the number of people, and a tip percentage, and returns the amount each person pays. The result is rounded up — no one should underpay. + +Use the built-in `ceil()` function for rounding. It is available right away — nothing needs to be loaded. + +```php + 90 + +// Bill 350, 3 people, 10% tip — 385 in total, everyone pays 129 +print_r(amountPerPerson(350, 3, 10)); // => 129 +``` + +## Hint + +* First calculate the total with the tip, then divide it by the number of people and round up +* `ceil()` returns a `float`, while the function must return an `int` — type casting will help diff --git a/modules/40-define-functions/350-modules/en/README.md b/modules/40-define-functions/350-modules/en/README.md new file mode 100644 index 00000000..2b442f61 --- /dev/null +++ b/modules/40-define-functions/350-modules/en/README.md @@ -0,0 +1,25 @@ +As a program grows, the code is split into separate files. In PHP, a file is connected with the `require` statement — after that, all functions from it become available: + +```php + Hi! +``` + +The tests in this course use the same mechanism: they load your solution with `require 'Solution.php';`. + +`include` differs from `require` in how a missing file is handled: `include` emits a warning and the program keeps running, while `require` stops with an error. `require_once` loads a file only once, which matters for files with functions: redeclaring a function causes an error. + +Unlike many languages, PHP's built-in functions are available everywhere without any imports. For example, `floor()` rounds a number down, and `ceil()` rounds it up: + +```php + 7 +print_r(ceil(7.1)); // => 8 +``` + +To deal with name conflicts, PHP has **namespaces** — you have seen the `namespace HexletBasics\...;` line at the beginning of every exercise. They are studied in detail later, at Hexlet. diff --git a/modules/40-define-functions/350-modules/en/data.yml b/modules/40-define-functions/350-modules/en/data.yml new file mode 100644 index 00000000..fc8464ad --- /dev/null +++ b/modules/40-define-functions/350-modules/en/data.yml @@ -0,0 +1,7 @@ +--- +name: Modules +tips: + - | + [The require statement](https://www.php.net/manual/en/function.require.php) + - | + [The include statement](https://www.php.net/manual/en/function.include.php) diff --git a/modules/40-define-functions/350-modules/es/EXERCISE.md b/modules/40-define-functions/350-modules/es/EXERCISE.md new file mode 100644 index 00000000..7b0552ca --- /dev/null +++ b/modules/40-define-functions/350-modules/es/EXERCISE.md @@ -0,0 +1,18 @@ +Implementa la función `amountPerPerson()`. Recibe el total de la cuenta de un restaurante, el número de personas y el porcentaje de propina, y devuelve la cantidad que paga cada persona. El resultado se redondea hacia arriba — nadie debe pagar de menos. + +Usa la función integrada `ceil()` para redondear. Está disponible de inmediato — no hay que cargar nada. + +```php + 90 + +// Cuenta 350, 3 personas, propina del 10% — 385 en total, cada uno paga 129 +print_r(amountPerPerson(350, 3, 10)); // => 129 +``` + +## Pista + +* Primero calcula el total con la propina, luego divídelo entre el número de personas y redondea hacia arriba +* `ceil()` devuelve un `float`, mientras que la función debe devolver un `int` — la conversión de tipos te ayudará diff --git a/modules/40-define-functions/350-modules/es/README.md b/modules/40-define-functions/350-modules/es/README.md new file mode 100644 index 00000000..912c16ea --- /dev/null +++ b/modules/40-define-functions/350-modules/es/README.md @@ -0,0 +1,25 @@ +A medida que un programa crece, el código se divide en archivos separados. En PHP, un archivo se conecta con la instrucción `require` — después de eso, todas sus funciones quedan disponibles: + +```php + Hi! +``` + +Las pruebas de este curso usan el mismo mecanismo: cargan tu solución con `require 'Solution.php';`. + +`include` se diferencia de `require` en cómo se gestiona un archivo inexistente: `include` emite una advertencia y el programa continúa, mientras que `require` se detiene con un error. `require_once` carga un archivo solo una vez, lo cual es importante para archivos con funciones: volver a declarar una función provoca un error. + +A diferencia de muchos lenguajes, las funciones integradas de PHP están disponibles en todas partes sin necesidad de importar nada. Por ejemplo, `floor()` redondea un número hacia abajo y `ceil()` hacia arriba: + +```php + 7 +print_r(ceil(7.1)); // => 8 +``` + +Para evitar conflictos de nombres, PHP tiene **espacios de nombres** — has visto la línea `namespace HexletBasics\...;` al principio de cada ejercicio. Se estudian en detalle más adelante, en Hexlet. diff --git a/modules/40-define-functions/350-modules/es/data.yml b/modules/40-define-functions/350-modules/es/data.yml new file mode 100644 index 00000000..01ba90f1 --- /dev/null +++ b/modules/40-define-functions/350-modules/es/data.yml @@ -0,0 +1,7 @@ +--- +name: Módulos +tips: + - | + [La instrucción require](https://www.php.net/manual/es/function.require.php) + - | + [La instrucción include](https://www.php.net/manual/es/function.include.php) diff --git a/modules/40-define-functions/350-modules/ru/EXERCISE.md b/modules/40-define-functions/350-modules/ru/EXERCISE.md new file mode 100644 index 00000000..12b8b6c9 --- /dev/null +++ b/modules/40-define-functions/350-modules/ru/EXERCISE.md @@ -0,0 +1,18 @@ +Реализуйте функцию `amountPerPerson()`. Она принимает сумму счета в ресторане, количество человек и процент чаевых, а возвращает сумму, которую платит каждый. Итог округляется вверх — никто не должен недоплачивать. + +Для округления используйте встроенную функцию `ceil()`. Она доступна сразу — подключать ничего не нужно. + +```php + 90 + +// Счет 350, 3 человека, чаевые 10% — итого 385, каждый платит 129 +print_r(amountPerPerson(350, 3, 10)); // => 129 +``` + +## Подсказка + +* Сначала посчитайте итоговую сумму с чаевыми, затем разделите на количество человек и округлите вверх +* `ceil()` возвращает число типа `float`, а функция должна вернуть `int` — пригодится приведение типов diff --git a/modules/40-define-functions/350-modules/ru/README.md b/modules/40-define-functions/350-modules/ru/README.md new file mode 100644 index 00000000..2cc9b068 --- /dev/null +++ b/modules/40-define-functions/350-modules/ru/README.md @@ -0,0 +1,88 @@ +Пока программа маленькая, весь код можно хранить в одном файле. Такой подход удобен для простых примеров и небольших задач. Но со временем программа начинает расти. Когда кода становится много, ориентироваться в одном файле становится сложно. Между тем реальные приложения состоят из десятков тысяч строк (как минимум) и сотен файлов. + +Чтобы разделить программу на отдельные логические части, код раскладывают по файлам. Во многих языках такие файлы называются модулями. В PHP модуль — это обычный файл с кодом и расширением `.php`. А язык предоставляет механизм для обращения к функциям и константам из других файлов — подключение файлов. + +## Как подключить файл + +Инструкция `require` подключает указанный файл и делает его содержимое доступным: + +```php + Hi! +``` + +После подключения все функции из файла `helpers.php` доступны так, как будто они были определены прямо в текущем файле. + +Кстати, вы уже видели этот механизм в действии. Автоматизированные тесты в этом курсе подключают файл с вашим решением строкой `require 'Solution.php';` — и после этого могут вызывать функции, которые вы определили. + +## require, include и require_once + +У `require` есть близнец — инструкция `include`. Разница проявляется, когда подключаемый файл не найден: `include` выведет предупреждение, и программа продолжит работу, а `require` остановит выполнение с ошибкой. Если без подключаемого кода программа не имеет смысла, используют `require`. + +Есть и третий вариант — `require_once`. Он подключает файл только один раз, даже если инструкция встречается в программе многократно. Это важно для файлов с функциями: повторное определение функции с тем же именем приводит к ошибке. + +## Встроенные функции доступны без подключения + +Стандартная библиотека PHP устроена проще, чем во многих других языках: встроенные функции доступны в любом месте программы сразу, без какого-либо подключения. Например, функции округления: `floor()` округляет число вниз до ближайшего целого, `ceil()` округляет вверх: + +```php + 7 +print_r(ceil(7.1)); // => 8 +print_r(ceil(7.0)); // => 7 +``` + +Разница заметна, когда число не целое. `floor(7.9)` дает 7, а не 8, потому что 7 — ближайшее целое снизу. + +Встроенные функции, конечно, доступны и в теле своих функций: + +```php + 4 +``` + +Обратите внимание: `ceil()` возвращает число типа `float`, поэтому результат приводится к `int` — так, как мы делали в уроке про преобразование типов. + +## Конфликты имен + +В больших программах разные части кода могут содержать функции с одинаковыми названиями. В PHP нельзя определить две функции с одним именем в одном пространстве — программа завершится с ошибкой `Cannot redeclare function`. + +Для борьбы с конфликтами имен в PHP существуют **пространства имен** (namespaces). Вы видели их в начале каждого задания этого курса — строка `namespace HexletBasics\...;` как раз объявляет пространство имен. Благодаря им мы можем создавать сколько угодно функций с одинаковыми именами, главное чтобы они находились в разных пространствах. Это работает даже со встроенными функциями: + +```php + custom floor +print_r(\floor(3.7)); // => 3 +``` + +Внутри пространства `App\Custom` имя `floor` ссылается на нашу функцию. Встроенная функция при этом никуда не делась — она доступна по полному имени `\floor()`, где обратный слеш означает глобальное пространство. Это особенно важно при использовании сторонних библиотек, потому что разные разработчики могут выбирать одинаковые имена для функций. Подробно пространства имен изучаются дальше, на Хекслете. diff --git a/modules/40-define-functions/350-modules/ru/data.yml b/modules/40-define-functions/350-modules/ru/data.yml new file mode 100644 index 00000000..88b35ae1 --- /dev/null +++ b/modules/40-define-functions/350-modules/ru/data.yml @@ -0,0 +1,7 @@ +--- +name: Модули +tips: + - | + [Инструкция require](https://www.php.net/manual/ru/function.require.php) + - | + [Инструкция include](https://www.php.net/manual/ru/function.include.php) diff --git a/modules/50-loops/26-conditions-inside-loops/Makefile b/modules/40-define-functions/400-packages/Makefile similarity index 100% rename from modules/50-loops/26-conditions-inside-loops/Makefile rename to modules/40-define-functions/400-packages/Makefile diff --git a/modules/40-define-functions/400-packages/Solution.php b/modules/40-define-functions/400-packages/Solution.php new file mode 100644 index 00000000..5bde319b --- /dev/null +++ b/modules/40-define-functions/400-packages/Solution.php @@ -0,0 +1,14 @@ +assertEquals('string', $reflection->getReturnType()?->getName(), 'You should add a return type declaration!'); + + foreach ([1, 7, 42] as $seed) { + srand($seed); + $result = generatePin(); + + srand($seed); + $expected = sprintf('%d%d%d%d', rand(0, 9), rand(0, 9), rand(0, 9), rand(0, 9)); + + $this->assertSame($expected, $result); + $this->assertSame(4, strlen($result)); + } + } +} diff --git a/modules/40-define-functions/400-packages/description.es.yml b/modules/40-define-functions/400-packages/description.es.yml new file mode 100644 index 00000000..25c814b6 --- /dev/null +++ b/modules/40-define-functions/400-packages/description.es.yml @@ -0,0 +1,49 @@ +--- + +name: Paquetes +theory: | + En el ecosistema PHP, la unidad de reutilización y distribución de código es el **paquete** (paquete de Composer). Los paquetes se gestionan con **Composer**, el gestor de paquetes de PHP. Un proyecto describe sus dependencias en el archivo `composer.json`: + + ```json + { + "name": "hexlet-basics/exercises-php", + "require": { + "php": "^8.4", + "nesbot/carbon": "^3.0" + } + } + ``` + + El nombre de un paquete consta de dos partes separadas por una barra: el nombre del editor (vendor) y el nombre del propio paquete, por ejemplo `nesbot/carbon`. El comando `composer install` descarga los paquetes en el directorio `vendor/`. Una sola línea los hace disponibles todos — este mecanismo se llama autocarga (autoloading): + + ```php + por ejemplo, "4823" o "0571" + print_r(generatePin()); // => por ejemplo, "1942" o "0037" + ``` + + Añade la declaración del tipo de retorno. + + ## Pista + + Genera cada uno de los cuatro dígitos con `rand(0, 9)` y construye la cadena usando interpolación. + +tips: + - | + [Composer](https://getcomposer.org/) + - | + [El registro de paquetes Packagist](https://packagist.org/) diff --git a/modules/40-define-functions/400-packages/en/EXERCISE.md b/modules/40-define-functions/400-packages/en/EXERCISE.md new file mode 100644 index 00000000..f04beba6 --- /dev/null +++ b/modules/40-define-functions/400-packages/en/EXERCISE.md @@ -0,0 +1,16 @@ +Implement the `generatePin()` function. It returns a random four-digit PIN code as a string. + +Each digit of the PIN code is an independent random integer from 0 to 9. + +```php + e.g. "4823" or "0571" +print_r(generatePin()); // => e.g. "1942" or "0037" +``` + +Add a return type declaration. + +## Hint + +Generate each of the four digits with `rand(0, 9)` and build the string using interpolation. diff --git a/modules/40-define-functions/400-packages/en/README.md b/modules/40-define-functions/400-packages/en/README.md new file mode 100644 index 00000000..684b4640 --- /dev/null +++ b/modules/40-define-functions/400-packages/en/README.md @@ -0,0 +1,21 @@ +In the PHP ecosystem, the unit of code reuse and distribution is a **package** (a Composer package). Packages are managed by **Composer** — the PHP package manager. A project describes its dependencies in the `composer.json` file: + +```json +{ + "name": "hexlet-basics/exercises-php", + "require": { + "php": "^8.4", + "nesbot/carbon": "^3.0" + } +} +``` + +A package name consists of two parts separated by a slash: the vendor name and the package name itself, e.g. `nesbot/carbon`. The `composer install` command downloads the packages into the `vendor/` directory. A single line makes all of them available — this mechanism is called autoloading: + +```php + por ejemplo, "4823" o "0571" +print_r(generatePin()); // => por ejemplo, "1942" o "0037" +``` + +Añade la declaración del tipo de retorno. + +## Pista + +Genera cada uno de los cuatro dígitos con `rand(0, 9)` y construye la cadena usando interpolación. diff --git a/modules/40-define-functions/400-packages/es/README.md b/modules/40-define-functions/400-packages/es/README.md new file mode 100644 index 00000000..88606da7 --- /dev/null +++ b/modules/40-define-functions/400-packages/es/README.md @@ -0,0 +1,21 @@ +En el ecosistema PHP, la unidad de reutilización y distribución de código es el **paquete** (paquete de Composer). Los paquetes se gestionan con **Composer**, el gestor de paquetes de PHP. Un proyecto describe sus dependencias en el archivo `composer.json`: + +```json +{ + "name": "hexlet-basics/exercises-php", + "require": { + "php": "^8.4", + "nesbot/carbon": "^3.0" + } +} +``` + +El nombre de un paquete consta de dos partes separadas por una barra: el nombre del editor (vendor) y el nombre del propio paquete, por ejemplo `nesbot/carbon`. El comando `composer install` descarga los paquetes en el directorio `vendor/`. Una sola línea los hace disponibles todos — este mecanismo se llama autocarga (autoloading): + +```php + например, "4823" или "0571" +print_r(generatePin()); // => например, "1942" или "0037" +``` + +Укажите объявление типа возвращаемого значения. + +## Подсказка + +Сгенерируйте каждую из четырех цифр через `rand(0, 9)` и соберите строку через интерполяцию. diff --git a/modules/40-define-functions/400-packages/ru/README.md b/modules/40-define-functions/400-packages/ru/README.md new file mode 100644 index 00000000..48f53f4a --- /dev/null +++ b/modules/40-define-functions/400-packages/ru/README.md @@ -0,0 +1,48 @@ +По мере роста программы увеличивается не только количество строк кода, но и количество файлов. Кроме того, удобный код хочется переиспользовать в разных проектах, а не копировать из одного в другой. + +В Python для группировки модулей используют пакеты-директории. В экосистеме PHP единицей переиспользования и распространения служит **пакет** (Composer-пакет). Пакет — это набор PHP-файлов с функциями и классами, который публикуют и устанавливают целиком. + +## Composer + +Пакетами управляет **Composer** — менеджер пакетов PHP. Проект описывает свои зависимости в файле `composer.json`: + +```json +{ + "name": "hexlet-basics/exercises-php", + "require": { + "php": "^8.4", + "nesbot/carbon": "^3.0" + } +} +``` + +Команда `composer install` скачивает все перечисленные пакеты и складывает их в директорию `vendor/`. Добавить новый пакет можно командой `composer require`, например: + +```bash +composer require nesbot/carbon +``` + +## Имя пакета + +Имя пакета состоит из двух частей, разделенных слешем: `nesbot/carbon`. Первая часть — имя издателя (vendor), вторая — имя самого пакета. Такая схема решает конфликты имен: разные разработчики могут опубликовать пакеты с одинаковым названием, и они не будут мешать друг другу — точно так же, как пространства имен позволяют существовать одинаковым функциям. + +## Автозагрузка + +Установленные пакеты попадают в директорию `vendor/`, но подключать каждый файл вручную через `require` не нужно. Composer генерирует специальный файл-автозагрузчик, и одной строки достаточно, чтобы стали доступны все установленные пакеты: + +```php +assertEquals(10.0, getAge(10)); - $this->assertEquals(9.0, getAge(9.1)); - $this->assertEquals(8.0, getAge(8.9)); - $this->assertEquals(8.0, getAge(8.5)); - } -} diff --git a/modules/40-define-functions/500-reading-documentation/description.es.yml b/modules/40-define-functions/500-reading-documentation/description.es.yml deleted file mode 100644 index efabd3db..00000000 --- a/modules/40-define-functions/500-reading-documentation/description.es.yml +++ /dev/null @@ -1,54 +0,0 @@ ---- - -name: Lectura de la documentación -theory: | - - Saber leer la documentación es una de las habilidades más importantes para cualquier desarrollador. - - _A pesar de que existe una traducción, recomiendo aprender a utilizar la documentación en inglés. Las bibliotecas que se utilizan en cientos de proyectos reales casi siempre tienen solo descripciones en inglés._ - - La sección principal a la que los programadores vuelven constantemente es el manual de funciones del lenguaje. En primer lugar, hay muchas funciones y es imposible recordar todo. En segundo lugar, en PHP el problema de la inconsistencia de los parámetros y los valores de retorno de las funciones es especialmente agudo. Por lo tanto, constantemente hay que recordar su orden. - - Para describir las funciones se utiliza una notación propia (su propia sintaxis). Se parece un poco a PHP, pero aún así es diferente, en otras palabras, no es código PHP, sino solo una descripción de la firma de la función. Veamos la función `round()`, que redondea un número: - - ``` - round(int|float $num, int $precision = 0, int $mode = PHP_ROUND_HALF_UP): float - ``` - - El propósito de este formato es mostrar de manera visual los tipos, la cantidad y los valores predeterminados de los parámetros de entrada, así como el tipo del parámetro de salida. Este último siempre se encuentra en la posición más a la derecha, justo después de los dos puntos. En este caso, el tipo de valor de retorno es `float`. - - La enumeración de los parámetros se realiza separándolos por comas entre paréntesis después del nombre de la función. Antes de cada nombre de parámetro se encuentra su tipo. Por ejemplo, el tipo del parámetro `$num` es `float`. El valor predeterminado se establece mediante una asignación, por ejemplo, `$precision` tiene un valor predeterminado de cero. - - Los parámetros con valores predeterminados son parámetros opcionales de la función, y se separan por comas entre sí. Para la función anterior, estos son `$precision` y `$mode`. `$mode`, a su vez, tiene un valor predeterminado igual al valor de la constante `PHP_ROUND_HALF_UP`. Si algún parámetro tiene un valor igual al valor de una constante, significa que en la documentación de esta función hay una enumeración y descripción de todas las constantes posibles que se pueden utilizar como valor de este parámetro. - - Basándonos en lo dicho anteriormente, podemos llamar a la función de la siguiente manera: - - ```php - = 60; } diff --git a/modules/45-logic/10-bool-type/SolutionTest.php b/modules/45-logic/10-bool-type/SolutionTest.php index 3efb6d06..48000215 100644 --- a/modules/45-logic/10-bool-type/SolutionTest.php +++ b/modules/45-logic/10-bool-type/SolutionTest.php @@ -2,14 +2,12 @@ namespace HexletBasics\Logic\BoolType; -use PHPUnit\Framework\TestCase; +use HexletBasics\Exercise\TestCase; class SolutionTest extends TestCase { public function test() { - require 'index.php'; - $this->assertFalse(isPensioner(23)); $this->assertFalse(isPensioner(59)); $this->assertTrue(isPensioner(60)); diff --git a/modules/45-logic/10-bool-type/ru/README.md b/modules/45-logic/10-bool-type/ru/README.md index 3b74a07f..835792b1 100644 --- a/modules/45-logic/10-bool-type/ru/README.md +++ b/modules/45-logic/10-bool-type/ru/README.md @@ -1,51 +1,87 @@ -Кроме арифметических операций в математике есть операции сравнения, например, `5 > 4` или `3 < 1`. Они есть и в программировании. Допустим, когда мы заходим на сайт, введенные логин и пароль сравниваются с теми, какие есть в базе. Если они есть, нас пускают внутрь — аутентифицируют. В этом уроке разберем операции сравнения. +Кроме арифметических операций в математике есть операции сравнения, например, `5 > 4` или `3 < 1`. Они есть и в программировании. Сравнения часто применяются в реальных задачах, связанных с числами. Например, когда мы оформляем покупку в интернет-магазине, система проверяет: хватает ли у пользователя денег на счете, чтобы оплатить товар. Если сумма на счете больше или равна цене товара, заказ подтверждается. При нехватке средств появляется соответствующее сообщение. -Языки программирования адаптировали все математические операции сравнения в неизменном виде, кроме операторов равенства и неравенства. В математике для этого используется обычное равно `=`, но в программировании такое встречается редко. +## Сравнение в программировании -Во многих языках символ `=` используется, чтобы присвоить переменным значения. Поэтому в php сравнивают с помощью `==`. +Начнем с примера, в котором сравнивается два числа: -Список операций сравнения: +```php + 4); // => bool(true) +var_dump(4 > 4); // => bool(false) +``` + +Результатом сравнения является значение типа `bool`. У этого типа есть всего два возможных варианта `true` и `false`. Это специальные значения языка. Их можно использовать напрямую: + +```php + bool(true) +var_dump(false); // => bool(false) +``` + +Обратите внимание на новую функцию `var_dump()`. Привычная нам `print_r()` плохо подходит для вывода логических значений: `true` она печатает как `1`, а `false` — как пустую строку. Функция `var_dump()` выводит и тип, и значение, поэтому для значений типа `bool` используют ее. -* `<` — меньше -* `<=` — меньше или равно -* `>` — больше -* `>=` — больше или равно -* `==` — равно -* `!=` — не равно +На практике значения `true` и `false` редко используют напрямую, но на их основе строится логика поведения программы. Мы с этим сталкиваемся буквально каждый день, когда вводим пинкоды и пароли, когда выполняем какие-то действия, результатом которых могут быть разные варианты. Все эти варианты прописаны внутри программы в виде условных выражений. Программа рассуждает примерно так: *если так-то делай раз, если по-другому, то делай два*. +В PHP доступны следующие операции сравнения: -Эти операции применяются не только к числам. Например, с помощью оператора равенства можно сравнить строки: `password == text` — это сравнение идентичности строк, которые записаны в разных переменных. +* `<` и `<=` обозначают «меньше» и «меньше или равно» +* `>` и `>=` обозначают «больше» и «больше или равно» +* `==` и `!=` обозначают «равно» и «не равно» +* `===` и `!==` обозначают «строго равно» и «строго не равно» -## Логический тип +Языки программирования адаптировали все математические операции сравнения в неизменном виде, кроме операторов равенства и неравенства. В математике для этого используется обычное равно `=`, но в программировании символ `=`, чаще всего, используется, чтобы присвоить переменным значения. Поэтому в PHP сравнивают с помощью `==` и `===`. -Логическая операция типа `5 > 4` или `password == text` — это выражение. Его результат — специальное значение `True` («истина») или `False` («ложь»). Это новый для нас тип данных — `bool`: +Чем различаются эти два оператора? Вспомните урок про слабую типизацию: PHP пытается автоматически преобразовывать типы. Оператор `==` сравнивает значения после такого преобразования, поэтому, например, `0 == '0'` оказывается истиной. Оператор `===` сравнивает строго, без преобразования: значения равны, только если совпадают и тип, и само значение. Неявные преобразования приводят к трудноуловимым ошибкам, поэтому в PHP принято использовать строгие операторы `===` и `!==` — так мы и будем делать в этом курсе. + +Несколько примеров: ```php 4; -print_r($result); // => true -print_r('one' !== 'one'); // => false +var_dump(5 >= 3); // => bool(true) +var_dump(7 < 0); // => bool(false) +var_dump(5 > 5); // => bool(false) +var_dump(5 >= 5); // => bool(true) +var_dump(2 === 5); // => bool(false) +var_dump(2 !== 5); // => bool(true) ``` -Он содержит всего лишь два этих значения. Наряду со строками (string) и целыми и рациональными числами, булев тип (bool) — это один из примитивных типов данных в PHP. +Когда в сравнении используют конкретные значения, то эта операция кажется бессмысленной, мы и так знаем ее результат сравнения и он всегда один и тот же, потому что если 3 больше 2, то это не меняется. Но все меняется, когда значения могут меняться. Попробуем написать простую функцию, которая принимает на вход возраст ребенка и определяет, младенец ли он. Младенцами считаются дети до двух лет (два не включается). + +```php + bool(false) +var_dump(isInfant(2)); // => bool(false) +var_dump(isInfant(1)); // => bool(true) +var_dump(isInfant(0)); // => bool(true) +``` -Попробуем написать простую функцию, которая принимает на вход возраст ребенка и определяет, младенец ли он. Младенцами считаются дети до года. +Когда функции возвращают результат сравнения, они обычно отвечают на вопрос «да» или «нет». Такие функции называют **предикатами**. Их легко узнать по тому, что они возвращают логическое значение `true` или `false`. Часто в их названии есть вопрос или утверждение, которое можно проверить. В PHP предикаты, как правило, начинаются с префикса `is`, `has` или `can`, но не ограничены этими словами. Примеры: -Любая операция — это выражение, поэтому единственной строчкой функции пишем «вернуть то значение, которое получится в результате сравнения `age < 1`». В зависимости от того, какой аргумент пришел, сравнение будет истинным (`True`) или ложным (`False`), а `return` вернет этот результат: +* `isInfant()` — «младенец ли?» +* `hasChildren()` — «есть ли дети?» +* `isEmpty()` — «пустой ли?» +* `hasErrors()` — «есть ли ошибки?» + +Вот функция, проверяющая, является ли число отрицательным: ```php bool(false) -var_dump(isInfant(0.5)); // => bool(true) - +var_dump(isNegative(-5)); // => bool(true) +var_dump(isNegative(7)); // => bool(false) ``` diff --git a/modules/45-logic/10-bool-type/ru/data.yml b/modules/45-logic/10-bool-type/ru/data.yml index f5764e1b..61fc5342 100644 --- a/modules/45-logic/10-bool-type/ru/data.yml +++ b/modules/45-logic/10-bool-type/ru/data.yml @@ -1,5 +1,13 @@ --- name: Логический тип +tips: + - | + [Тип bool в PHP](https://www.php.net/manual/ru/language.types.boolean.php) + - > + [Именование в + программировании](https://ru.hexlet.io/blog/posts/naming-in-programming?utm_source=code-basics&utm_medium=referral&utm_campaign=blog&utm_content=lesson) definitions: - name: Логический тип (bool) - description: 'тип данных с двумя возможными значениями: true (истина) и false (ложь).' + description: 'тип данных с двумя возможными значениями: `true` (истина) и `false` (ложь).' + - name: Предикат + description: выражение, отвечающее на вопрос «да» или «нет» с помощью типа bool. diff --git a/modules/50-loops/28-build-strings/Makefile b/modules/45-logic/15-bool-strings/Makefile similarity index 100% rename from modules/50-loops/28-build-strings/Makefile rename to modules/45-logic/15-bool-strings/Makefile diff --git a/modules/45-logic/15-bool-strings/Solution.php b/modules/45-logic/15-bool-strings/Solution.php new file mode 100644 index 00000000..d0fca7f2 --- /dev/null +++ b/modules/45-logic/15-bool-strings/Solution.php @@ -0,0 +1,10 @@ + 5; +} +// END diff --git a/modules/45-logic/15-bool-strings/SolutionTest.php b/modules/45-logic/15-bool-strings/SolutionTest.php new file mode 100644 index 00000000..410ec753 --- /dev/null +++ b/modules/45-logic/15-bool-strings/SolutionTest.php @@ -0,0 +1,15 @@ +assertFalse(isLongWord('apple')); + $this->assertTrue(isLongWord('banana')); + $this->assertTrue(isLongWord('pineapple')); + } +} diff --git a/modules/45-logic/15-bool-strings/description.es.yml b/modules/45-logic/15-bool-strings/description.es.yml new file mode 100644 index 00000000..87d1bea6 --- /dev/null +++ b/modules/45-logic/15-bool-strings/description.es.yml @@ -0,0 +1,49 @@ +--- + +name: Comparación de cadenas +theory: | + Las operaciones de comparación funcionan tanto con números como con cadenas. En PHP las cadenas se comparan lexicográficamente: carácter por carácter, de izquierda a derecha, según los códigos de los caracteres. + + ```php + bool(true) + var_dump('cat' > 'dog'); // => bool(false) + ``` + + Aquí `'apple' < 'banana'` porque el código de `a` (97) es menor que el código de `b` (98). El código de un carácter se puede consultar con la función `ord()`. La comparación distingue entre mayúsculas y minúsculas: el código de `'Z'` (90) es menor que el de `'a'` (97). + + Las comparaciones son expresiones, por lo que se pueden combinar con otras expresiones, por ejemplo con la función `strlen()`, que devuelve la longitud de una cadena: + + ```php + 3); // => bool(true) + var_dump(strlen('hi') > 3); // => bool(false) + ``` + + PHP también tiene muchas funciones predicado integradas para cadenas, por ejemplo: + + ```php + bool(true) + var_dump(str_ends_with('hello', 'lo')); // => bool(true) + var_dump(str_contains('hello', 'ell')); // => bool(true) + ``` + +instructions: | + Al registrarse en un sitio web, el programa comprueba que la contraseña sea lo suficientemente larga: más de 5 caracteres. Escribe una función `isLongWord()` que devuelva `true` si la longitud de la palabra dada es mayor que 5 caracteres, y `false` en caso contrario. + + Ejemplo: + + ```php + bool(false) + var_dump(isLongWord('banana')); // => bool(true) + ``` + +tips: + - | + [Operadores de comparación en PHP](https://www.php.net/manual/es/language.operators.comparison.php) diff --git a/modules/45-logic/15-bool-strings/en/EXERCISE.md b/modules/45-logic/15-bool-strings/en/EXERCISE.md new file mode 100644 index 00000000..f3f3414d --- /dev/null +++ b/modules/45-logic/15-bool-strings/en/EXERCISE.md @@ -0,0 +1,10 @@ +When registering on a website, the program checks that the password is long enough — more than 5 characters. Write a function `isLongWord()` that returns `true` if the length of the given word is more than 5 characters, and `false` otherwise. + +Example: + +```php + bool(false) +var_dump(isLongWord('banana')); // => bool(true) +``` diff --git a/modules/45-logic/15-bool-strings/en/README.md b/modules/45-logic/15-bool-strings/en/README.md new file mode 100644 index 00000000..331c8bd5 --- /dev/null +++ b/modules/45-logic/15-bool-strings/en/README.md @@ -0,0 +1,29 @@ +Comparison operations work with strings as well as numbers. In PHP, strings are compared lexicographically: character by character, left to right, using character codes. + +```php + bool(true) +var_dump('cat' > 'dog'); // => bool(false) +``` + +Here `'apple' < 'banana'` because the code of `a` (97) is less than the code of `b` (98). You can check a character code with the `ord()` function. The comparison is case-sensitive: the code of `'Z'` (90) is less than the code of `'a'` (97). + +Comparisons are expressions, so you can combine them with other expressions, for example with the `strlen()` function that returns the length of a string: + +```php + 3); // => bool(true) +var_dump(strlen('hi') > 3); // => bool(false) +``` + +PHP also has many built-in predicate functions for strings, for example: + +```php + bool(true) +var_dump(str_ends_with('hello', 'lo')); // => bool(true) +var_dump(str_contains('hello', 'ell')); // => bool(true) +``` diff --git a/modules/45-logic/15-bool-strings/en/data.yml b/modules/45-logic/15-bool-strings/en/data.yml new file mode 100644 index 00000000..15841c55 --- /dev/null +++ b/modules/45-logic/15-bool-strings/en/data.yml @@ -0,0 +1,5 @@ +--- +name: Comparing strings +tips: + - | + [Comparison operators in PHP](https://www.php.net/manual/en/language.operators.comparison.php) diff --git a/modules/45-logic/15-bool-strings/es/EXERCISE.md b/modules/45-logic/15-bool-strings/es/EXERCISE.md new file mode 100644 index 00000000..a24be8f4 --- /dev/null +++ b/modules/45-logic/15-bool-strings/es/EXERCISE.md @@ -0,0 +1,10 @@ +Al registrarse en un sitio web, el programa comprueba que la contraseña sea lo suficientemente larga: más de 5 caracteres. Escribe una función `isLongWord()` que devuelva `true` si la longitud de la palabra dada es mayor que 5 caracteres, y `false` en caso contrario. + +Ejemplo: + +```php + bool(false) +var_dump(isLongWord('banana')); // => bool(true) +``` diff --git a/modules/45-logic/15-bool-strings/es/README.md b/modules/45-logic/15-bool-strings/es/README.md new file mode 100644 index 00000000..ba3af525 --- /dev/null +++ b/modules/45-logic/15-bool-strings/es/README.md @@ -0,0 +1,29 @@ +Las operaciones de comparación funcionan tanto con números como con cadenas. En PHP las cadenas se comparan lexicográficamente: carácter por carácter, de izquierda a derecha, según los códigos de los caracteres. + +```php + bool(true) +var_dump('cat' > 'dog'); // => bool(false) +``` + +Aquí `'apple' < 'banana'` porque el código de `a` (97) es menor que el código de `b` (98). El código de un carácter se puede consultar con la función `ord()`. La comparación distingue entre mayúsculas y minúsculas: el código de `'Z'` (90) es menor que el de `'a'` (97). + +Las comparaciones son expresiones, por lo que se pueden combinar con otras expresiones, por ejemplo con la función `strlen()`, que devuelve la longitud de una cadena: + +```php + 3); // => bool(true) +var_dump(strlen('hi') > 3); // => bool(false) +``` + +PHP también tiene muchas funciones predicado integradas para cadenas, por ejemplo: + +```php + bool(true) +var_dump(str_ends_with('hello', 'lo')); // => bool(true) +var_dump(str_contains('hello', 'ell')); // => bool(true) +``` diff --git a/modules/45-logic/15-bool-strings/es/data.yml b/modules/45-logic/15-bool-strings/es/data.yml new file mode 100644 index 00000000..fd59b4fa --- /dev/null +++ b/modules/45-logic/15-bool-strings/es/data.yml @@ -0,0 +1,5 @@ +--- +name: Comparación de cadenas +tips: + - | + [Operadores de comparación en PHP](https://www.php.net/manual/es/language.operators.comparison.php) diff --git a/modules/45-logic/15-bool-strings/ru/EXERCISE.md b/modules/45-logic/15-bool-strings/ru/EXERCISE.md new file mode 100644 index 00000000..3180190a --- /dev/null +++ b/modules/45-logic/15-bool-strings/ru/EXERCISE.md @@ -0,0 +1,10 @@ +При регистрации на сайте программа проверяет, что пароль достаточно длинный — больше 5 символов. Напишите функцию `isLongWord()`, которая возвращает `true`, если длина переданного слова больше 5 символов, и `false` в противном случае. + +Пример работы: + +```php + bool(false) +var_dump(isLongWord('banana')); // => bool(true) +``` diff --git a/modules/45-logic/15-bool-strings/ru/README.md b/modules/45-logic/15-bool-strings/ru/README.md new file mode 100644 index 00000000..38877ddc --- /dev/null +++ b/modules/45-logic/15-bool-strings/ru/README.md @@ -0,0 +1,70 @@ +Операции сравнения работают с числами и со строками. В PHP строки сравниваются лексикографически: посимвольно слева направо по числовым кодам символов. + +```php + bool(true) +var_dump('cat' > 'dog'); // => bool(false) +var_dump('abc' === 'abc'); // => bool(true) +var_dump('hello' !== 'world'); // => bool(true) +``` + +Здесь `'apple' < 'banana'`, потому что код `a` (97) меньше кода `b` (98), и именно первый символ решает исход сравнения. Код символа можно посмотреть с помощью функции `ord()`: + +```php + 97 +print_r(ord('b')); // => 98 +``` + +Сравнение чувствительно к регистру: код `'Z'` (90) меньше кода `'a'` (97). Пример сравнения, где первые буквы разного регистра: + +```php + bool(true) — 'Z'(90) < 'a'(97) +var_dump('apple' < 'Banana'); // => bool(false) — 'a'(97) > 'B'(66) +var_dump('Apple' < 'apple'); // => bool(true) — 'A'(65) < 'a'(97) +``` + +Напишем функцию, которая проверяет, начинается ли слово с заданной буквы. Для этого возьмем первый символ строки и сравним его с нужной буквой: + +```php + bool(true) +var_dump(startsWithLetter('banana', 'a')); // => bool(false) +``` + +Операции сравнения представляют собой такие же выражения, как и арифметические. В них можно подставлять готовые значения и другие выражения, как в примере выше: `$word[0]`. Например, вместо числа можно использовать результат работы функции `strlen()`, которая возвращает длину строки: + +```php + 3); // => bool(true), потому что strlen('apple') — это 5 +var_dump(strlen('hi') > 3); // => bool(false), потому что strlen('hi') — это 2 +``` + +В примере выше сначала выполняется функция `strlen('apple')`, результатом будет число `5`. Потом это число сравнивается с `3`. Другими словами, сначала считаются аргументы выражения (например, длина строки), а потом выполняется операция сравнения. + +Так можно комбинировать разные операции, получая более сложные проверки. + +## Полезные предикаты + +В PHP есть много встроенных функций-предикатов для работы со строками. Они возвращают `true` или `false` и помогают проверять разные свойства строки. Ниже приведены самые часто используемые: + +```php + bool(true) — строка начинается с 'he' +var_dump(str_ends_with('hello', 'lo')); // => bool(true) — строка заканчивается на 'lo' +var_dump(str_contains('hello', 'ell')); // => bool(true) — строка содержит 'ell' +``` + +Такие функции позволяют проверять строки на нужные условия прямо в коде, без написания дополнительных функций. diff --git a/modules/45-logic/15-bool-strings/ru/data.yml b/modules/45-logic/15-bool-strings/ru/data.yml new file mode 100644 index 00000000..6124b194 --- /dev/null +++ b/modules/45-logic/15-bool-strings/ru/data.yml @@ -0,0 +1,5 @@ +--- +name: Сравнение строк +tips: + - | + [Операторы сравнения в PHP](https://www.php.net/manual/ru/language.operators.comparison.php) diff --git a/modules/45-logic/15-predicates/SolutionTest.php b/modules/45-logic/15-predicates/SolutionTest.php deleted file mode 100644 index 032dbf69..00000000 --- a/modules/45-logic/15-predicates/SolutionTest.php +++ /dev/null @@ -1,17 +0,0 @@ -assertFalse(isMister('8234782')); - $this->assertFalse(isMister('Joker')); - $this->assertTrue(isMister('Mister')); - } -} diff --git a/modules/45-logic/15-predicates/description.es.yml b/modules/45-logic/15-predicates/description.es.yml deleted file mode 100644 index fa0a0558..00000000 --- a/modules/45-logic/15-predicates/description.es.yml +++ /dev/null @@ -1,45 +0,0 @@ ---- - -name: Predicados -theory: | - - Recordemos la función `isInfant()` del tema anterior: - - ```php - - [Naming in - programming](https://hexlet.io/blog/posts/code-complete-naming-in-programming) -definitions: - - name: A predicate - description: >- - is an expression that answers a yes or no question using the bool data - type. diff --git a/modules/45-logic/15-predicates/es/EXERCISE.md b/modules/45-logic/15-predicates/es/EXERCISE.md deleted file mode 100644 index 2be62fa3..00000000 --- a/modules/45-logic/15-predicates/es/EXERCISE.md +++ /dev/null @@ -1,9 +0,0 @@ - -Escribe una función `isMister()` que tome una cadena de texto y verifique si es la palabra `'Mister'`. - -```php -- - una expresión que responde a una pregunta "sí" o "no" utilizando el tipo - bool. diff --git a/modules/45-logic/15-predicates/index.php b/modules/45-logic/15-predicates/index.php deleted file mode 100644 index 042c3da1..00000000 --- a/modules/45-logic/15-predicates/index.php +++ /dev/null @@ -1,10 +0,0 @@ - - [Именование в - программировании](https://ru.hexlet.io/blog/posts/naming-in-programming?utm_source=code-basics&utm_medium=referral&utm_campaign=blog&utm_content=lesson) -definitions: - - name: Предикат - description: выражение, отвечающее на вопрос «да» или «нет» с помощью типа bool. diff --git a/modules/45-logic/20-logic-combine-expressions/index.php b/modules/45-logic/20-logic-combine-expressions/Solution.php similarity index 67% rename from modules/45-logic/20-logic-combine-expressions/index.php rename to modules/45-logic/20-logic-combine-expressions/Solution.php index ba0434ee..3311690e 100644 --- a/modules/45-logic/20-logic-combine-expressions/index.php +++ b/modules/45-logic/20-logic-combine-expressions/Solution.php @@ -3,7 +3,7 @@ namespace HexletBasics\Logic\CombineExpressions; // BEGIN -function isInternationalPhone($phone) +function isInternationalPhone(string $phone): bool { return $phone[0] === '+'; } diff --git a/modules/45-logic/20-logic-combine-expressions/SolutionTest.php b/modules/45-logic/20-logic-combine-expressions/SolutionTest.php index 28b950a9..d47c6117 100644 --- a/modules/45-logic/20-logic-combine-expressions/SolutionTest.php +++ b/modules/45-logic/20-logic-combine-expressions/SolutionTest.php @@ -2,13 +2,12 @@ namespace HexletBasics\Logic\CombineExpressions; -use PHPUnit\Framework\TestCase; +use HexletBasics\Exercise\TestCase; class SolutionTest extends TestCase { public function test() { - require 'index.php'; $this->assertFalse(isInternationalPhone('89602223423')); $this->assertTrue(isInternationalPhone('+79602223423')); } diff --git a/modules/45-logic/20-logic-combine-expressions/ru/README.md b/modules/45-logic/20-logic-combine-expressions/ru/README.md index f6e77052..4c04af53 100644 --- a/modules/45-logic/20-logic-combine-expressions/ru/README.md +++ b/modules/45-logic/20-logic-combine-expressions/ru/README.md @@ -1,52 +1,58 @@ -**Логические операции** — это выражения, значит, их можно комбинировать с другими выражениями. Например, мы хотим проверить четность числа — кратность двум. В программировании используют такой подход: проверяют остаток от деления на два: +**Логические операции** являются выражениями, поэтому их можно комбинировать с другими выражениями. Например, мы хотим проверить четность числа, то есть его кратность двум. В программировании для этого проверяют остаток от деления на два. Если остаток равен `0`, число четное. Если остаток не равен `0`, число нечетное. -* если остаток `0` — число четное -* если остаток не `0` — число нечетное +![even-or-odd](./assets/even-or-odd.jpg) -Остаток от деления — простая, но важная концепция в арифметике, алгебре, в теории чисел и криптографии. Нужно разделить число на несколько равных групп, и если в конце что-то останется — это остаток от деления. +Остаток от деления является простой, но важной концепцией в арифметике, алгебре, в теории чисел и криптографии. Нужно разделить число на несколько равных групп, и если в конце что-то останется, это и есть остаток от деления. Делим конфеты поровну между людьми: -* 7 конфет, 2 человека: 2 x 3 + остаток 1 — 7 не кратно 2 -* 21 конфету, 3 человека: 3 x 7 + остаток 0 — 21 кратно 3 -* 19 конфет, 5 человек: 5 x 3 + остаток 4 — 19 не кратно 5 +* 7 конфет, 2 человека: 2 x 3 + остаток 1 (7 не кратно 2) +* 21 конфету, 3 человека: 3 x 7 + остаток 0 (21 кратно 3) +* 19 конфет, 5 человек: 5 x 3 + остаток 4 (19 не кратно 5) -Оператор `%` вычисляет **остаток от деления**: +Оператор `%` вычисляет остаток от деления: * `7 % 2` → `1` * `21 % 3` → `0` * `19 % 5` → `4` -С помощью него напишем функцию проверки четности: +Скомбинируем в одном выражении логический оператор «проверка равенства» `===` и арифметический оператор `%` и напишем функцию проверки четности: ```php bool(true) +var_dump(isEven(3)); // => bool(false) ``` -В одном выражении мы скомбинировали логический оператор проверки равенства `===` и арифметический оператор `%`. +Приоритет арифметических операций выше логических. Значит, сначала вычисляется арифметическое выражение `$number % 2`, а затем результат сравнивается с нулем и возвращается результат проверки равенства. -Приоритет арифметических операций выше логических. Значит, сначала вычисляется арифметическое выражение `$number % 2`, затем результат участвует в логическом сравнении. +Теперь напишем функцию, которая принимает строку и проверяет, начинается ли эта строка с латинской буквы `a`. -Это можно расшифровать так: +Алгоритм: ->«Вычислить остаток от деления числа `$number` на 2 и сравнить, равен ли остаток нулю; затем вернуть результат проверки равенства»* - ---- - -*Напомним об извлечении символов из строки с помощью квадратных скобок:* +1. Получим и запишем в переменную первый символ из строки-аргумента +2. Сравним, равен ли символ латинской букве `a` +3. Вернем результат ```php bool(false) +var_dump(isFirstLetterAnA('apple')); // => bool(true) ``` + +Чтобы было понятно, что тут происходит, попробуйте проговорить происходящее аналогично тому, как мы расшифровывали процесс в примере с `isEven()`. + +Теперь вы знаете, что операции сравнения применяются в программировании наравне с арифметическими. Но помните, что равенство обозначается `===`. Так вы не спутаете эту операцию с присваиванием значения переменной. diff --git a/modules/45-logic/20-logic-combine-expressions/ru/assets/even-or-odd.jpg b/modules/45-logic/20-logic-combine-expressions/ru/assets/even-or-odd.jpg new file mode 100644 index 00000000..6c3197c8 Binary files /dev/null and b/modules/45-logic/20-logic-combine-expressions/ru/assets/even-or-odd.jpg differ diff --git a/modules/45-logic/20-logic-combine-expressions/ru/data.yml b/modules/45-logic/20-logic-combine-expressions/ru/data.yml index 1d1a5262..c01f64c5 100644 --- a/modules/45-logic/20-logic-combine-expressions/ru/data.yml +++ b/modules/45-logic/20-logic-combine-expressions/ru/data.yml @@ -1,2 +1,10 @@ --- name: Комбинирование операций и функций +tips: + - | + [Выражение](https://ru.wikipedia.org/wiki/Выражение_(информатика)) +definitions: + - name: Выражение + description: > + последовательность действий над данными, приводящая к каком-то результату, + который можно использовать. diff --git a/modules/45-logic/25-logical-operators/Solution.php b/modules/45-logic/25-logical-operators/Solution.php new file mode 100644 index 00000000..a03320fa --- /dev/null +++ b/modules/45-logic/25-logical-operators/Solution.php @@ -0,0 +1,10 @@ +assertTrue(isLeapYear(2016)); $this->assertTrue(isLeapYear(2000)); $this->assertFalse(isLeapYear(2017)); diff --git a/modules/45-logic/25-logical-operators/assets/lannisters.jpg b/modules/45-logic/25-logical-operators/assets/lannisters.jpg deleted file mode 100644 index feeac49e..00000000 Binary files a/modules/45-logic/25-logical-operators/assets/lannisters.jpg and /dev/null differ diff --git a/modules/45-logic/25-logical-operators/index.php b/modules/45-logic/25-logical-operators/index.php deleted file mode 100644 index 626755c8..00000000 --- a/modules/45-logic/25-logical-operators/index.php +++ /dev/null @@ -1,12 +0,0 @@ -= x <= 20`, где `x` — это длина конкретного пароля. Но в PHP такой трюк не пройдет. +> Пароль длиннее 8 символов **И** пароль содержит хотя бы одну заглавную букву -Нам придется сделать два отдельных логических выражения и соединить их специальным оператором «И»: +Вот функция, которая принимает пароль и говорит, соответствует ли он условиям (`true`) или не соответствует (`false`): ```php = 8 && $length <= 20) && hasSpecialChars($password); + return $length > 8 && hasCapitalLetter($password); +} + +var_dump(isCorrectPassword('Qwerty')); // => bool(false) +var_dump(isCorrectPassword('Qwerty1234')); // => bool(true) +var_dump(isCorrectPassword('qwerty1234')); // => bool(false) +``` + +Оператор `&&` означает «И». В математической логике это называют конъюнкцией. Все выражение считается истинным, если истинен каждый **операнд**, то есть каждое из составных выражений. Иными словами, `&&` означает «и то, и другое». Приоритет этого оператора ниже, чем приоритет операторов сравнения. Поэтому выражение `hasCapitalLetter($password) && $length > 8` тоже правильно отрабатывает без скобок. + +Кроме `&&` часто используется оператор `||`, обозначающий «ИЛИ» (дизъюнкция). Он означает «или то, или другое, или оба». Выражение `$a || $b` считается истинным, если хотя бы один из операндов истинен или когда оба операнда истинны. В другом случае выражение ложное. + +```php + bool(true) (младше 18) +var_dump(hasDiscount(25, true)); // => bool(true) (студент) +var_dump(hasDiscount(15, true)); // => bool(true) (оба условия) +var_dump(hasDiscount(25, false)); // => bool(false) +``` + +Операторы можно комбинировать в любом количестве и в любой последовательности. Если в коде одновременно встречаются `&&` и `||`, то приоритет лучше задавать скобками. Ниже пример расширенной функции, которая определяет корректность пароля: + +```php + 8 && hasCapitalLetter($password)) && hasSpecialChars($password); +} ``` -Оператор `&&` означает «И» — в математической логике это называют **конъюнкцией**. Все выражение считается истинным только в том случае, когда истинен каждый операнд — каждое из составных выражений. Иными словами, `&&` означает «и то, и другое». Приоритет этого оператора ниже, чем приоритет операторов сравнения, поэтому выражение отрабатывает правильно без скобок. +Теперь представим, что мы хотим купить квартиру, которая удовлетворяет таким условиям: площадь от 100 квадратных метров и больше на любой улице **ИЛИ** площадь от 80 квадратных метров и больше, но на центральной улице `Main Street`. -Кроме `&&`, часто используется оператор `||` — «ИЛИ» (**дизъюнкция**). Он означает «или то, или другое, или оба». Операторы можно комбинировать в любом количестве и любой последовательности, но когда одновременно встречаются `&&` и `||`, то приоритет лучше задавать скобками. +Напишем функцию, которая проверит квартиру. Она принимает два аргумента: площадь (число) и название улицы (строку): + +```php += 100 || ($area >= 80 && $street === 'Main Street'); +} + +var_dump(isGoodApartment(91, 'Queens Street')); // => bool(false) +var_dump(isGoodApartment(78, 'Queens Street')); // => bool(false) +var_dump(isGoodApartment(70, 'Main Street')); // => bool(false) + +var_dump(isGoodApartment(120, 'Queens Street')); // => bool(true) +var_dump(isGoodApartment(120, 'Main Street')); // => bool(true) +var_dump(isGoodApartment(80, 'Main Street')); // => bool(true) +``` -Область математики, в которой изучаются логические операторы, называется булевой алгеброй. Ниже увидите **таблицы истинности** — по ним можно определить, каким будет результат, если применить оператора: +Область математики, в которой изучаются логические операторы, называется булевой алгеброй. **Таблицы истинности** показывают, каким будет результат при применении каждого оператора. -### И `&&` +#### И `&&` | A | B | A `&&` B | | ----- | ----- | -------- | -| TRUE | TRUE | **TRUE** | -| TRUE | FALSE | FALSE | -| FALSE | TRUE | FALSE | -| FALSE | FALSE | FALSE | +| true | true | **true** | +| true | false | false | +| false | true | false | +| false | false | false | -### ИЛИ `||` +#### ИЛИ `||` | A | B | A `‖` B | | ----- | ----- | -------- | -| TRUE | TRUE | **TRUE** | -| TRUE | FALSE | **TRUE** | -| FALSE | TRUE | **TRUE** | -| FALSE | FALSE | FALSE | +| true | true | **true** | +| true | false | **true** | +| false | true | **true** | +| false | false | false | diff --git a/modules/45-logic/25-logical-operators/ru/data.yml b/modules/45-logic/25-logical-operators/ru/data.yml index efa8ff0b..c4ee669a 100644 --- a/modules/45-logic/25-logical-operators/ru/data.yml +++ b/modules/45-logic/25-logical-operators/ru/data.yml @@ -4,9 +4,9 @@ tips: - | [Булева алгебра](https://ru.wikipedia.org/wiki/Булева_алгебра) - | - [Конъюнкция](https://ru.wikipedia.org/wiki/Конъюнкция) + [Логическое «И»](https://ru.wikipedia.org/wiki/Конъюнкция) - | - [Дизъюнкция](https://ru.wikipedia.org/wiki/Дизъюнкция) + [Логическое «ИЛИ»](https://ru.wikipedia.org/wiki/Дизъюнкция) definitions: - name: Логические операторы description: >- diff --git a/modules/45-logic/28-logical-negation/index.php b/modules/45-logic/28-logical-negation/Solution.php similarity index 64% rename from modules/45-logic/28-logical-negation/index.php rename to modules/45-logic/28-logical-negation/Solution.php index 91ca0da0..83c55578 100644 --- a/modules/45-logic/28-logical-negation/index.php +++ b/modules/45-logic/28-logical-negation/Solution.php @@ -2,16 +2,14 @@ namespace HexletBasics\Logic\LogicalNegation; -use function HexletBasics\Functions\mb_strrev; - // BEGIN -function isPalindrome($word) +function isPalindrome(string $word): bool { $lowerWord = strtolower($word); return $lowerWord === strrev($lowerWord); } -function isNotPalindrome($word) +function isNotPalindrome(string $word): bool { return !isPalindrome($word); } diff --git a/modules/45-logic/28-logical-negation/SolutionTest.php b/modules/45-logic/28-logical-negation/SolutionTest.php index 14ea9b29..4c5971f8 100644 --- a/modules/45-logic/28-logical-negation/SolutionTest.php +++ b/modules/45-logic/28-logical-negation/SolutionTest.php @@ -2,14 +2,12 @@ namespace HexletBasics\Logic\LogicalNegation; -use PHPUnit\Framework\TestCase; +use HexletBasics\Exercise\TestCase; class SolutionTest extends TestCase { public function test() { - require 'index.php'; - $this->assertFalse(isNotPalindrome('wow')); $this->assertFalse(isNotPalindrome('asdffdsa')); $this->assertFalse(isNotPalindrome('Wow')); diff --git a/modules/45-logic/28-logical-negation/ru/EXERCISE.md b/modules/45-logic/28-logical-negation/ru/EXERCISE.md index 3cdfab51..b3b7da4e 100644 --- a/modules/45-logic/28-logical-negation/ru/EXERCISE.md +++ b/modules/45-logic/28-logical-negation/ru/EXERCISE.md @@ -1,7 +1,7 @@ -В этом уроке вам нужно будет реализовать две функции `isPalindrome()` и `isNotPalindrome()` +В игре со словами участники проверяют, является ли слово палиндромом. Реализуйте две функции `isPalindrome()` и `isNotPalindrome()`, принимающие строку на вход -1. Функция `isPalindrome()` определяет, является ли слово палиндромом или нет. Палиндром это слово, которое читается одинаково в обоих направлениях. +1. Функция `isPalindrome()` определяет, является ли слово палиндромом или нет. Палиндром — это слово, которое читается одинаково в обоих направлениях. ```php bool(true) +var_dump(!isEven(10)); // => bool(false) +``` + +В примере выше мы добавили `!` слева от вызова функции и получили обратное действие. + +Отрицание позволяет выражать задуманные правила в коде без написания новых функций. Если написать `!!isEven(10)`, то код сработает даже в таком случае: + +```php + bool(true) +``` + +В логике двойное отрицание равносильно отсутствию отрицания: + +```php + bool(true) +var_dump(!!isEven(11)); // => bool(false) +``` + +`!` можно комбинировать с `&&` и `||`. Среди логических операторов у него наивысший приоритет, поэтому он применяется первым: + +```php + false || true => true +!true && false; // (!true) && false => false && false => false +``` + +Скобки меняют порядок вычисления: + +```php + false +!(true && false); // !false => true +``` + +Практический пример — функция проверяет, может ли водитель сесть за руль: нужны права и трезвость: + +```php + bool(true) (есть права, трезвый) +var_dump(canDrive(true, true)); // => bool(false) (есть права, но пьяный) +var_dump(canDrive(false, false)); // => bool(false) (нет прав) +``` + +Теперь вы знаете, что означают операторы **И**, **ИЛИ** и `!`. С их помощью вы сможете задавать составные условия из двух и более логических выражений. + +## Законы де Моргана + +При работе со сложными логическими выражениями бывает нужно их инвертировать или переписать в эквивалентную форму, которую легче читать. Для этого существуют **законы де Моргана** — два правила, которые описывают, как отрицание распределяется по составному выражению: + +```text +!(A && B) эквивалентно !A || !B +!(A || B) эквивалентно !A && !B +``` + +Первый закон: отрицание конъюнкции равно дизъюнкции отрицаний. Проверим: + +```php + true +!true || !false; // false || true => true +``` + +Второй закон: отрицание дизъюнкции равно конъюнкции отрицаний: + +```php + false +!true && !false; // false && true => false ``` -Мы просто добавили `!` слева от вызова функции и получили обратное действие. Отрицание — мощный инструмент, который позволяет лаконично выражать задуманные правила в коде без необходимости писать новые функции. +На практике законы де Моргана помогают упрощать условия. Например, вместо `!($isAdmin || $isModerator)` можно написать `!$isAdmin && !$isModerator` — читается как «не администратор и не модератор». diff --git a/modules/45-logic/28-logical-negation/ru/data.yml b/modules/45-logic/28-logical-negation/ru/data.yml index dd24f7f1..b8232201 100644 --- a/modules/45-logic/28-logical-negation/ru/data.yml +++ b/modules/45-logic/28-logical-negation/ru/data.yml @@ -3,3 +3,8 @@ name: Отрицание tips: - | [Законы Де Моргана](https://ru.wikipedia.org/wiki/Законы_де_Моргана) +definitions: + - name: Отрицание + description: > + логическая операция, которая меняет логическое значение на + противоположное. diff --git a/modules/45-logic/29-logical-operators-2/SolutionTest.php b/modules/45-logic/29-logical-operators-2/SolutionTest.php deleted file mode 100644 index 892e568b..00000000 --- a/modules/45-logic/29-logical-operators-2/SolutionTest.php +++ /dev/null @@ -1,20 +0,0 @@ -assertTrue(isNeutralSoldier('yellow', 'black')); - $this->assertFalse(isNeutralSoldier('red', 'yellow')); - $this->assertFalse(isNeutralSoldier('red', 'red')); - $this->assertFalse(isNeutralSoldier('red', 'black')); - $this->assertFalse(isNeutralSoldier('yellow', 'red')); - $this->assertTrue(isNeutralSoldier('black', 'black')); - } -} diff --git a/modules/45-logic/29-logical-operators-2/description.es.yml b/modules/45-logic/29-logical-operators-2/description.es.yml deleted file mode 100644 index 08f7c1c8..00000000 --- a/modules/45-logic/29-logical-operators-2/description.es.yml +++ /dev/null @@ -1,49 +0,0 @@ ---- - -name: Operadores lógicos 2 -theory: | - - Los operadores lógicos son un tema importante, por lo que es necesario reforzarlo con un ejemplo y un ejercicio adicional. - - Intentemos implementar una función que verifique si un año es bisiesto. Un año es bisiesto si es divisible por 400 o si es divisible por 4 y no es divisible por 100. Como puedes ver, toda la lógica necesaria ya está definida, solo falta trasladarla al código: - - ```php - 1 - print_r(false); // => (se muestra una cadena vacía en la pantalla) - print_r(0 || 1); // => 1 - ``` - - El operador **OR** solo funciona con el tipo *bool*, pero se le dan los números `1` y `0`: - - 1. `0` se convierte en `false` y `1` se convierte en `true` - 2. El resultado de `false || true` es `true` - 3. Ahora `print_r()` recibe `true`, pero solo funciona con cadenas - 4. `true` se convierte en `1` - 5. Y se muestra `1` en la pantalla - - Aquí es importante destacar la diferencia entre los operadores `===` y `==`. La diferencia radica en la conversión de tipos. - - La cadena vacía y `false` son valores diferentes, por lo que el operador `===` dice "¡Falso! ¡No son iguales!". - - Pero el operador `==` convierte los tipos. Desde su punto de vista, la cadena vacía y `false` son iguales. Esta conversión es implícita, por lo que se recomienda evitar los operadores `==` y `!=` siempre que sea posible: - - ```php - false - var_dump('' == false); // => true - ``` - - Recordemos la operación de negación. Con una doble negación `!!`, el valor final es igual al valor inicial: - - ```php - false - var_dump(!!$respuesta); // => true - ``` - - Aquí también se producen conversiones de tipo adicionales. Por lo tanto, el resultado de una doble negación siempre será de tipo _bool_. Se utiliza este truco para cambiar el tipo de datos. - - En diferentes lenguajes de programación, hay diferentes reglas de conversión. Algunos lenguajes no realizan conversiones de tipos por sí mismos. - -instructions: | - - Escribe una función `isFalsy()` que verifique si el valor pasado se interpreta como falso en PHP. Para realizar esta verificación, deberás comparar `false` con el valor pasado utilizando `==`. - - ```php - false -var_dump('' == false); // => true -``` - -An empty string and `false` are different values, so the `===` operator says "false! they're not equal! - -But the `==` operator converts types, making an empty string and `false` equivalent from its point of view. This conversion is implicit, so avoid the `==` and `!=` operators whenever possible. - ---- - -Remember the negation operator: - -```php - false -``` - -When you use double negation `!!` the result value is equal to the initial value: - -```php - true -``` - -However, this is where type conversions also take place. Therefore, the result of a double negation will always be a _bool_. This trick is used to change the data type. - ---- - -Different programming languages have different transformation rules. Some languages don't convert types themselves at all. Many features of PHP aren't really the best, but this is the historical legacy of the language. If it were created from scratch today, many of the rules and nuances would probably be quite different. diff --git a/modules/45-logic/70-logic-weak-typing/en/data.yml b/modules/45-logic/70-logic-weak-typing/en/data.yml deleted file mode 100644 index 4cce6ac6..00000000 --- a/modules/45-logic/70-logic-weak-typing/en/data.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -name: Weak Typing - 2 -tips: - - | - [Booleans](https://www.php.net/manual/en/language.types.boolean.php) diff --git a/modules/45-logic/70-logic-weak-typing/es/EXERCISE.md b/modules/45-logic/70-logic-weak-typing/es/EXERCISE.md deleted file mode 100644 index 6b622f37..00000000 --- a/modules/45-logic/70-logic-weak-typing/es/EXERCISE.md +++ /dev/null @@ -1,11 +0,0 @@ - -Escribe una función `isFalsy()` que verifique si el valor pasado se interpreta como falso en PHP. Para realizar esta verificación, deberás comparar `false` con el valor pasado utilizando `==`. - -```php - 1 -print_r(false); // => (se muestra una cadena vacía en la pantalla) -print_r(0 || 1); // => 1 -``` - -El operador **OR** solo funciona con el tipo *bool*, pero se le dan los números `1` y `0`: - -1. `0` se convierte en `false` y `1` se convierte en `true` -2. El resultado de `false || true` es `true` -3. Ahora `print_r()` recibe `true`, pero solo funciona con cadenas -4. `true` se convierte en `1` -5. Y se muestra `1` en la pantalla - -Aquí es importante destacar la diferencia entre los operadores `===` y `==`. La diferencia radica en la conversión de tipos. - -La cadena vacía y `false` son valores diferentes, por lo que el operador `===` dice "¡Falso! ¡No son iguales!". - -Pero el operador `==` convierte los tipos. Desde su punto de vista, la cadena vacía y `false` son iguales. Esta conversión es implícita, por lo que se recomienda evitar los operadores `==` y `!=` siempre que sea posible: - -```php - false -var_dump('' == false); // => true -``` - -Recordemos la operación de negación. Con una doble negación `!!`, el valor final es igual al valor inicial: - -```php - false -var_dump(!!$respuesta); // => true -``` - -Aquí también se producen conversiones de tipo adicionales. Por lo tanto, el resultado de una doble negación siempre será de tipo _bool_. Se utiliza este truco para cambiar el tipo de datos. - -En diferentes lenguajes de programación, hay diferentes reglas de conversión. Algunos lenguajes no realizan conversiones de tipos por sí mismos. diff --git a/modules/45-logic/70-logic-weak-typing/es/data.yml b/modules/45-logic/70-logic-weak-typing/es/data.yml deleted file mode 100644 index e6788258..00000000 --- a/modules/45-logic/70-logic-weak-typing/es/data.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -name: Tipado débil - 2 -tips: - - | - [Booleanos](https://php.net/manual/es/language.types.boolean.php) diff --git a/modules/45-logic/70-logic-weak-typing/index.php b/modules/45-logic/70-logic-weak-typing/index.php deleted file mode 100644 index 0e6f104f..00000000 --- a/modules/45-logic/70-logic-weak-typing/index.php +++ /dev/null @@ -1,10 +0,0 @@ - 1 -print_r(false); // => (на экран выводится пустая строка) -print_r(0 || 1); // => 1 -``` - -Оператор **ИЛИ** работает только с типом *bool*, но ему даны числа `1` и `0`: - -1. `0` преобразуется в `false`, а `1` преобразуется в `true` -2. Результат `false || true` — это `true` -3. Теперь `print_r()` получает `true`, но он работает только со строками -4. `true` преобразуется в `1` -5. И на экран выводится `1` - -Здесь важно отметить также отличие операторов `===` и `==`. Оно как раз заключается в преобразовании типов. - -Пустая строка и `false` — это разные значения, поэтому оператор `===` говорит «Ложь! Они не равны!». - -Но оператор `==` преобразует типы. С его точки зрения, пустая строка и `false` равны. Это преобразование неявное, поэтому по возможности избегайте операторов `==` и `!=`: - -```php - false -var_dump('' == false); // => true -``` - -Вспомним операцию отрицания. При двойном отрицании `!!` итоговое значение равно начальному: - -```php - false -var_dump(!!$answer); // => true -``` - -Здесь также дополнительно происходят преобразования типа. Поэтому результатом двойного отрицания всегда будет _bool_. Этим приемом пользуются, чтобы поменять тип данных. - -В разных языках программирования разные правила преобразований. Некоторые языки вообще не преобразовывают типы сами. diff --git a/modules/45-logic/70-logic-weak-typing/ru/data.yml b/modules/45-logic/70-logic-weak-typing/ru/data.yml deleted file mode 100644 index ace54acc..00000000 --- a/modules/45-logic/70-logic-weak-typing/ru/data.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -name: Слабая типизация - 2 -tips: - - | - [Booleans](https://php.net/manual/ru/language.types.boolean.php) diff --git a/modules/50-loops/29-edge-cases/Makefile b/modules/45-logic/90-logical-expressions/Makefile similarity index 100% rename from modules/50-loops/29-edge-cases/Makefile rename to modules/45-logic/90-logical-expressions/Makefile diff --git a/modules/45-logic/90-logical-expressions/Solution.php b/modules/45-logic/90-logical-expressions/Solution.php new file mode 100644 index 00000000..6a82af89 --- /dev/null +++ b/modules/45-logic/90-logical-expressions/Solution.php @@ -0,0 +1,10 @@ +assertTrue(isFalsy('')); $this->assertFalse(isFalsy(' ')); $this->assertTrue(isFalsy(null)); $this->assertTrue(isFalsy(false)); + $this->assertTrue(isFalsy('0')); $this->assertFalse(isFalsy(true)); $this->assertFalse(isFalsy(3)); + $this->assertFalse(isFalsy('help')); } } diff --git a/modules/45-logic/90-logical-expressions/description.es.yml b/modules/45-logic/90-logical-expressions/description.es.yml new file mode 100644 index 00000000..ddff25ca --- /dev/null +++ b/modules/45-logic/90-logical-expressions/description.es.yml @@ -0,0 +1,57 @@ +--- + +name: Resultado de expresiones lógicas +theory: | + En las expresiones lógicas se pueden usar no solo valores de tipo `bool`. Cuando un valor entra en un contexto lógico, PHP lo convierte en `true` o `false`. + + Hay un conjunto fijo de valores **falsy**: `false`, `0` (y `0.0`), la cadena vacía `''`, la cadena `'0'` y `null`. Todo lo demás es **truthy**. Se puede comprobar con la doble negación `!!`, que convierte cualquier valor a `bool`: + + ```php + bool(true) + var_dump(!!''); // => bool(false) + var_dump(!!'0'); // => bool(false) — una particularidad de PHP + ``` + + A diferencia de muchos lenguajes donde `&&` y `||` devuelven uno de sus operandos, en PHP los operadores lógicos siempre devuelven un `bool`: + + ```php + bool(true) + var_dump(0 || 1); // => bool(true) + ``` + + La conversión de tipos también ocurre con la comparación no estricta. El operador `==` convierte los operandos antes de comparar, por lo que una cadena vacía es igual a `false` desde su punto de vista. Esta conversión es implícita, así que evita `==` y `!=` siempre que sea posible: + + ```php + bool(false) + var_dump('' == false); // => bool(true) + ``` + + Un error común de principiante es escribir `$value === ('first' || 'second')`. Primero se evalúan los paréntesis: ambas cadenas son truthy, el resultado es `true`, y toda la expresión se convierte en `$value === true` — siempre falsa para cadenas. La comprobación correcta es: + + ```php + bool(true) +var_dump(!!''); // => bool(false) +var_dump(!!'0'); // => bool(false) — a PHP peculiarity +``` + +Unlike many languages where `&&` and `||` return one of their operands, in PHP logical operators always return a `bool`: + +```php + bool(true) +var_dump(0 || 1); // => bool(true) +``` + +Type conversion also happens with loose comparison. The `==` operator converts operands before comparing, so an empty string equals `false` from its point of view. This conversion is implicit, so avoid `==` and `!=` whenever possible: + +```php + bool(false) +var_dump('' == false); // => bool(true) +``` + +A common beginner mistake is writing `$value === ('first' || 'second')`. The parentheses evaluate first: both strings are truthy, so the result is `true`, and the whole expression becomes `$value === true` — always false for strings. The correct check is: + +```php + bool(true) +var_dump(!!''); // => bool(false) +var_dump(!!'0'); // => bool(false) — una particularidad de PHP +``` + +A diferencia de muchos lenguajes donde `&&` y `||` devuelven uno de sus operandos, en PHP los operadores lógicos siempre devuelven un `bool`: + +```php + bool(true) +var_dump(0 || 1); // => bool(true) +``` + +La conversión de tipos también ocurre con la comparación no estricta. El operador `==` convierte los operandos antes de comparar, por lo que una cadena vacía es igual a `false` desde su punto de vista. Esta conversión es implícita, así que evita `==` y `!=` siempre que sea posible: + +```php + bool(false) +var_dump('' == false); // => bool(true) +``` + +Un error común de principiante es escribir `$value === ('first' || 'second')`. Primero se evalúan los paréntesis: ambas cadenas son truthy, el resultado es `true`, y toda la expresión se convierte en `$value === true` — siempre falsa para cadenas. La comprobación correcta es: + +```php + bool(true) — непустая строка — truthy +var_dump(!!''); // => bool(false) — пустая строка — falsy +var_dump(!!0); // => bool(false) — ноль — falsy +var_dump(!!-3.5); // => bool(true) — ненулевое число — truthy +var_dump(!!'0'); // => bool(false) — строка '0' — falsy, особенность PHP +``` + +Этим приемом пользуются, чтобы явно поменять тип данных: результатом двойного отрицания всегда будет значение типа `bool`. + +## Как работают логические выражения + +В некоторых языках операторы «И» и «ИЛИ» возвращают один из своих операндов, поэтому результатом может быть строка или число. PHP устроен иначе: логические операторы `&&` и `||` всегда возвращают значение типа `bool` — `true` или `false`: + +```php + bool(true) — оба операнда truthy +var_dump('' && 'world'); // => bool(false) — первый операнд falsy +var_dump(0 || 1); // => bool(true) — второй операнд truthy +var_dump('' || 0); // => bool(false) — оба операнда falsy +``` + +Порядок вычисления зависит от приоритета операторов: + +```text +Приоритет (от высокого к низкому): + + () скобки + ↓ + ! отрицание + ↓ + && логическое И + ↓ + || логическое ИЛИ +``` + +## Нестрогое сравнение + +Преобразование типов происходит и при нестрогом сравнении. Вспомните операторы `==` и `!=` из урока про логический тип: они сравнивают значения, предварительно преобразовав типы. Поэтому, с точки зрения `==`, пустая строка и `false` равны: + +```php + bool(false) +var_dump('' == false); // => bool(true) +``` + +Пустая строка и `false` — это разные значения, поэтому строгий оператор `===` говорит «Ложь! Они не равны!». Но оператор `==` преобразует операнды и считает их равными. Это преобразование неявное, поэтому по возможности избегайте операторов `==` и `!=`. + +## Ошибка выбора + +Представим задачу, в которой нужно проверить, что значение равно либо одному, либо другому. Например, переменная `$value` должна содержать одно из двух значений: `'first'` или `'second'`. Начинающие разработчики иногда записывают это выражение так: + +```php +assertEquals('Try again!', guessNumber(100500)); $this->assertEquals('You win!', guessNumber(42)); } diff --git a/modules/48-conditionals/30-if/ru/EXERCISE.md b/modules/48-conditionals/30-if/ru/EXERCISE.md index b3fc91e3..0617bbd3 100644 --- a/modules/48-conditionals/30-if/ru/EXERCISE.md +++ b/modules/48-conditionals/30-if/ru/EXERCISE.md @@ -1,9 +1,9 @@ -Реализуйте функцию `guessNumber()`, которая принимает число и проверяет, равно ли число заданному (пусть это будет 42). Если равно, то функция должна вернуть строку `'You win!'`, в противном случае нужно вернуть строку `'Try again!'`. +В викторине загадано число 42. Участник называет число, и программа сразу говорит — угадал он или нет. Реализуйте функцию `guessNumber()`, которая принимает число и проверяет, равно ли оно 42. Если равно — возвращает `'You win!'`, иначе — `'Try again!'`. ```php 3) { + print_r('Yes, it is true'); +} +``` + +Здесь строка `'Yes, it is true'` напечатается, потому что условие `5 > 3` истинно. + +```text +┌───────────┐ +│ условие? │ +└─────┬─────┘ + true │ + ↓ +┌───────────┐ +│ тело if │ +└───────────┘ +``` + +## Блоки кода + +После слова `if` в круглых скобках пишется условие, а затем в фигурных скобках описывается блок кода. Все инструкции внутри фигурных скобок входят в один блок: ```php normal +print_r(getTypeOfSentence('Hodor?') . "\n"); // => question ``` -`if` — это инструкция. В скобках ей передается выражение-предикат, а затем описывается блок кода в фигурных скобках. Этот блок кода будет выполнен, только если предикат — истина. Если предикат — ложь, то блок кода в фигурных скобках пропускается, и функция продолжает свое выполнение дальше. +Здесь используется сразу два `return`. Если условие внутри `if` выполняется, срабатывает `return 'question';` и функция завершается. Если условие не выполняется, управление переходит на следующую строку с `return 'normal';`. + +Таким образом, у функции есть несколько возможных точек выхода. Это частая практика. В зависимости от условий функция может завершаться по-разному. + +Несмотря на то, что функция `getTypeOfSentence()` использует `if`, она возвращает строки, а значит, предикатом не является. В качестве предиката рассмотрим функцию, которая проверяет, достаточно ли денег для покупки: + +```php += $price) { + return true; + } + + return false; +} + +var_dump(hasEnoughMoney(100, 50)); // => bool(true) +var_dump(hasEnoughMoney(30, 50)); // => bool(false) +``` + +## if и логические выражения + +Функцию `hasEnoughMoney()` мы написали через `if`. Но в таком виде она могла бы обойтись и без него, потому что результат сравнения сам по себе уже является логическим выражением: + +```php += $price; +} +``` -В нашем случае следующая строчка кода — `return 'normal';`. Она заставит функцию вернуть строку и завершиться. Как видите, `return` может находиться где угодно в функции, в том числе — внутри блока кода с условием. +В простых случаях лучше сразу возвращать такое выражение. `if` нужен там, где внутри блока выполняются дополнительные действия помимо возврата результата. Чем более сложные программы мы будем писать, тем чаще такие ситуации начнут встречаться. diff --git a/modules/48-conditionals/40-if-else/Solution.php b/modules/48-conditionals/40-if-else/Solution.php new file mode 100644 index 00000000..d38d8adc --- /dev/null +++ b/modules/48-conditionals/40-if-else/Solution.php @@ -0,0 +1,22 @@ +assertEquals($expected1, $actual1); - - $expected2 = 'https://yandex.ru'; - $actual2 = normalizeUrl('http://yandex.ru'); - $this->assertEquals($expected2, $actual2); + $this->assertEquals('https://yandex.ru', normalizeUrl('yandex.ru')); + $this->assertEquals('https://yandex.ru', normalizeUrl('http://yandex.ru')); + $this->assertEquals('https://yandex.ru', normalizeUrl('https://yandex.ru')); + $this->assertEquals('https://httpsecurity.com', normalizeUrl('httpsecurity.com')); + $this->assertEquals( + 'https://httpbin.org/redirect-to?url=http://google.com', + normalizeUrl('https://httpbin.org/redirect-to?url=http://google.com') + ); + $this->assertEquals( + 'https://httpbin.org/redirect-to?url=https://google.com', + normalizeUrl('httpbin.org/redirect-to?url=https://google.com') + ); + $this->assertEquals( + 'https://httpbin.org/redirect-to?url=http://google.com', + normalizeUrl('httpbin.org/redirect-to?url=http://google.com') + ); } } diff --git a/modules/48-conditionals/40-if-else/index.php b/modules/48-conditionals/40-if-else/index.php deleted file mode 100644 index 2bb7ff20..00000000 --- a/modules/48-conditionals/40-if-else/index.php +++ /dev/null @@ -1,21 +0,0 @@ - py +``` + +Так вот, с помощью `substr()` можно также отбросить определенное количество символов: ```php thon ``` diff --git a/modules/48-conditionals/40-if-else/ru/README.md b/modules/48-conditionals/40-if-else/ru/README.md index 6ccd6caf..2507f708 100644 --- a/modules/48-conditionals/40-if-else/ru/README.md +++ b/modules/48-conditionals/40-if-else/ru/README.md @@ -1,9 +1,9 @@ -Попробуем изменить функцию из предыдущего примера так, чтобы она возвращала не просто тип предложения, а целую строку *Sentence is normal* или *Sentence is question*: +Посмотрите на функцию ниже. Она определяет тип предложения по последнему символу: если предложение заканчивается вопросительным знаком, функция вернет `Sentence is question`, иначе — `Sentence is normal`: ```php Sentence is normal +print_r(getTypeOfSentence('Hodor?') . "\n"); // => Sentence is question ``` -Мы добавили `else` и новый блок с фигурными скобками. Этот блок выполнится, только если условие в `if` — ложь. +Мы добавили `else` и новый блок в фигурных скобках. Он выполнится, если условие в `if` окажется ложным. Еще в блок `else` можно вкладывать другие условия `if`. Else переводится «иначе», «в ином случае». -Существует два способа оформления конструкции *if-else*. С помощью отрицания `!==` можно изменить порядок блоков: +```text + ┌───────────┐ + │ условие? │ + └─────┬─────┘ + true │ │ false + ↓ ↓ +┌──────────┐ ┌──────────┐ +│ тело if │ │ тело else│ +└──────────┘ └──────────┘ +``` + +Пример вложенных блоков: ```php 10) { + print_r('Number is greater than 10'); +} else { + if ($number === 10) { + print_r('Number is exactly 10'); + } else { + print_r('Number is less than 10'); + } +} +``` + +Оформить конструкцию `if-else` можно двумя способами. С помощью отрицания `!==` можно изменить порядок блоков: + +```php + 0) { + print_r("Число положительное\n"); + } + + if ($number > 10) { + print_r("Число больше 10\n"); + } else { + print_r("Число не положительное\n"); + } +} + +checkNumber(3); +// => Число положительное +// => Число не положительное +``` + +В примере выше мы забыли вложить второй `if` внутрь первого, поэтому `else` теперь относится ко второму `if`. Программа сообщает, что число одновременно положительное и не положительное. + +```php + 0) { + print_r("Число положительное\n"); + + if ($number > 10) { + print_r("Число больше 10\n"); + } + } else { + print_r("Число не положительное\n"); + } +} + +checkNumber(3); +// => Число положительное +``` + +Теперь второй `if` вложен в первый, а `else` на одном уровне с первым и противопоставляется ему. diff --git a/modules/48-conditionals/50-else-if/Solution.php b/modules/48-conditionals/50-else-if/Solution.php new file mode 100644 index 00000000..06e82989 --- /dev/null +++ b/modules/48-conditionals/50-else-if/Solution.php @@ -0,0 +1,18 @@ +assertEquals('friend', whoIsThisHouseToStarks('Tully')); - $this->assertEquals('friend', whoIsThisHouseToStarks('Karstark')); - $this->assertEquals('enemy', whoIsThisHouseToStarks('Lannister')); - $this->assertEquals('neutral', whoIsThisHouseToStarks('Martell')); - $this->assertEquals('neutral', whoIsThisHouseToStarks('undefined')); + $this->assertEquals('go', getTrafficLightAction('green')); + $this->assertEquals('slow down', getTrafficLightAction('yellow')); + $this->assertEquals('stop', getTrafficLightAction('red')); + $this->assertEquals('unknown', getTrafficLightAction('blue')); + $this->assertEquals('unknown', getTrafficLightAction('purple')); } } diff --git a/modules/48-conditionals/50-else-if/index.php b/modules/48-conditionals/50-else-if/index.php deleted file mode 100644 index 1d4cab63..00000000 --- a/modules/48-conditionals/50-else-if/index.php +++ /dev/null @@ -1,16 +0,0 @@ - Sentence is normal +print_r(getTypeOfSentence('No') . "\n"); // => Sentence is normal +print_r(getTypeOfSentence('No!') . "\n"); // => Sentence is exclamation ``` -Мы добавили еще одну проверку (_exclamation_ переводится «восклицание»). Технически функция работает, но с точки зрения семантики есть проблемы: +Мы добавили проверку восклицательных предложений (_exclamation_ переводится «восклицание»). Технически эта функция работает, но вопросительные предложения трактует неверно. Еще в ней есть проблемы с точки зрения семантики. Наличие восклицательного знака проверяется в любом случае, даже если уже обнаружился вопросительный знак. Ветка `else` описана для второго условия, но не для первого. Поэтому вопросительное предложение становится `normal`. -* Проверка на наличие вопросительного знака происходит в любом случае, даже если уже был обнаружен восклицательный знак -* Ветка `else` описана именно для первого условия, но не для второго - -Правильнее будет воспользоваться еще одной возможностью условной конструкции: +Чтобы исправить ситуацию, воспользуемся еще одной возможностью условной конструкции: ```php Sentence is question +print_r(getTypeOfSentence('No') . "\n"); // => Sentence is normal +print_r(getTypeOfSentence('No!') . "\n"); // => Sentence is exclamation +``` -Конструкция `elseif` — это «если не выполнено предыдущее условие, но выполнено текущее». Получается такая схема: +Теперь все условия выстроились в единую конструкцию. Ключевое слово `elseif` означает «если не выполнено предыдущее условие, но выполнено текущее». + +```text + ┌─────────────────┐ + │ условие 1? │ + └────┬────────┬───┘ + true │ │ false + ↓ ↓ +┌──────────┐ ┌─────────────────┐ +│ тело if │ │ условие 2? │ +└──────────┘ └────┬────────┬───┘ + true │ │ false + ↓ ↓ + ┌────────────┐ ┌──────────┐ + │тело elseif │ │ тело else│ + └────────────┘ └──────────┘ +``` -* Если последний символ `?`, то `'question'` -* Иначе, если последний символ `!`, то `'exclamation'` -* Иначе `'normal'` +Логика функции устроена так. Если последний символ `?`, возвращается `'question'`. Если последний символ `!`, возвращается `'exclamation'`. Во всех остальных случаях возвращается `'normal'`. -Выполнится только один из блоков кода, относящихся ко всей конструкции `if`. +Выполнится только один из блоков кода, который относится ко всей конструкции `if`. diff --git a/modules/48-conditionals/60-ternary-operator/Solution.php b/modules/48-conditionals/60-ternary-operator/Solution.php new file mode 100644 index 00000000..16a2ca1e --- /dev/null +++ b/modules/48-conditionals/60-ternary-operator/Solution.php @@ -0,0 +1,10 @@ +assertEquals('flop', flipFlop('flip')); $this->assertEquals('flip', flipFlop('flop')); $this->assertEquals('flip', flipFlop('')); diff --git a/modules/48-conditionals/60-ternary-operator/index.php b/modules/48-conditionals/60-ternary-operator/index.php deleted file mode 100644 index cc9e2b8a..00000000 --- a/modules/48-conditionals/60-ternary-operator/index.php +++ /dev/null @@ -1,10 +0,0 @@ -= 0) { return $number; @@ -12,20 +12,16 @@ function abs($number) return -$number; } -abs(10); // 10 -abs(-10); // 10 +print_r(abs(10) . "\n"); // => 10 +print_r(abs(-10) . "\n"); // => 10 ``` -Можно ли записать ее лаконичнее? Что-то вроде `return ОТВЕТ В ЗАВИСИМОСТИ ОТ УСЛОВИЯ`? Для этого справа от `return` должно быть выражение. Но есть проблема: `if` — это инструкция, а не выражение. - -В PHP существует конструкция, которая по своему действию аналогична конструкции *if-else*, но при этом является выражением. Она называется **тернарный оператор**, и именно его мы изучим в этом уроке. - -**Тернарный оператор** — единственный в своем роде оператор, требующий три операнда: +Но можно записать более лаконично. В PHP есть конструкция, которая работает как *if-else*, но при этом является выражением — ее результат можно сразу вернуть из функции. Она называется **тернарный оператор** и является единственным оператором в PHP, который требует три операнда: ```php = 0 ? $number : -$number; } @@ -41,35 +37,35 @@ function abs($number) Давайте перепишем начальный вариант `getTypeOfSentence()` аналогично. Посмотрим, как было: - ```php - normal +print_r(getTypeOfSentence('Hodor?') . "\n"); // => question +``` Вы уже могли догадаться, что тернарный оператор можно вкладывать в тернарный оператор. Это возможно, но лучше так не делать. Такой код тяжело читать и отлаживать, поэтому вложенные тернарные операторы считаются очень плохой практикой. diff --git a/modules/48-conditionals/65-switch/index.php b/modules/48-conditionals/65-switch/Solution.php similarity index 86% rename from modules/48-conditionals/65-switch/index.php rename to modules/48-conditionals/65-switch/Solution.php index c4333cef..8f3968ab 100644 --- a/modules/48-conditionals/65-switch/index.php +++ b/modules/48-conditionals/65-switch/Solution.php @@ -3,7 +3,7 @@ namespace HexletBasics\Conditionals\SwitchStatement; // BEGIN -function getNumberExplanation($number) +function getNumberExplanation(int $number): string { switch ($number) { case 666: diff --git a/modules/48-conditionals/65-switch/SolutionTest.php b/modules/48-conditionals/65-switch/SolutionTest.php index 7902d170..3670dc52 100644 --- a/modules/48-conditionals/65-switch/SolutionTest.php +++ b/modules/48-conditionals/65-switch/SolutionTest.php @@ -2,14 +2,12 @@ namespace HexletBasics\Conditionals\SwitchStatement; -use PHPUnit\Framework\TestCase; +use HexletBasics\Exercise\TestCase; class SolutionTest extends TestCase { public function test() { - require 'index.php'; - $this->assertEquals('just a number', getNumberExplanation(0)); $this->assertEquals('devil number', getNumberExplanation(666)); $this->assertEquals('answer for everything', getNumberExplanation(42)); diff --git a/modules/48-conditionals/65-switch/description.es.yml b/modules/48-conditionals/65-switch/description.es.yml index f382272c..5738e0a9 100644 --- a/modules/48-conditionals/65-switch/description.es.yml +++ b/modules/48-conditionals/65-switch/description.es.yml @@ -70,7 +70,7 @@ theory: | ```php $weight <= 1 ? 600 : 900, + 'usa' => $weight <= 1 ? 800 : 1200, + 'germany' => $weight <= 1 ? 700 : 1000, + default => null, + }; +} +// END diff --git a/modules/48-conditionals/70-match/SolutionTest.php b/modules/48-conditionals/70-match/SolutionTest.php new file mode 100644 index 00000000..6b8525e5 --- /dev/null +++ b/modules/48-conditionals/70-match/SolutionTest.php @@ -0,0 +1,20 @@ +assertEquals(600, calculateDeliveryCost('canada', 0.5)); + $this->assertEquals(600, calculateDeliveryCost('canada', 1)); + $this->assertEquals(900, calculateDeliveryCost('canada', 2)); + $this->assertEquals(800, calculateDeliveryCost('usa', 1)); + $this->assertEquals(1200, calculateDeliveryCost('usa', 3)); + $this->assertEquals(700, calculateDeliveryCost('germany', 0.3)); + $this->assertEquals(1000, calculateDeliveryCost('germany', 1.5)); + $this->assertNull(calculateDeliveryCost('france', 1)); + } +} diff --git a/modules/48-conditionals/70-match/description.es.yml b/modules/48-conditionals/70-match/description.es.yml new file mode 100644 index 00000000..85fb9f02 --- /dev/null +++ b/modules/48-conditionals/70-match/description.es.yml @@ -0,0 +1,111 @@ +--- + +name: Expresión match +theory: | + La expresión `match` apareció en PHP 8 y resuelve la misma tarea que `switch`: elige un resultado según el valor de una variable. Las construcciones son similares, pero `match` es más corta y funciona como una expresión. Comparémoslas con un ejemplo. Así se selecciona un texto según el estado del pedido con `switch`: + + ```php + 'El pedido está en proceso', + 'paid' => 'El pedido está pagado', + 'new' => 'Pedido nuevo', + default => 'Estado desconocido', + }; + ``` + + ```text + match (valor) { + │ + ├── 'a' → resultado 1 + ├── 'b' → resultado 2 + ├── 'c' → resultado 3 + └── default → resultado por defecto + } + ``` + + A la izquierda de la flecha `=>` está el valor a comparar, y a la derecha, cualquier expresión que se convertirá en el resultado. La rama `default` se activa cuando ningún valor coincide y cumple el papel de `else`. Si varios valores llevan al mismo resultado, se enumeran separados por comas: + + ```php + 'small', + 'm' => 'medium', + 'l', 'xl' => 'large', + }; + ``` + + La principal diferencia con `switch` es que `match` es una **expresión**. Toda la construcción se evalúa a un valor, por lo que el resultado se puede asignar a una variable o devolver desde una función de inmediato. `switch` no puede hacer esto; necesita una variable aparte o un `return` dentro de un `case`. Hay otras diferencias: + + * `match` compara los valores de forma estricta, como el operador `===`, sin conversión automática de tipos. `switch` compara de forma no estricta, con `==`. + * `match` ejecuta exactamente una rama, por lo que no se necesita `break`. En `switch`, sin `break`, el control cae en cascada al siguiente `case`. + * Si nada coincide en `match` y no hay `default`, el programa termina con un error `UnhandledMatchError`. En el mismo caso, `switch` no hace nada. + + Como `match` devuelve un valor, su resultado a menudo se devuelve directamente desde la función con `return`: + + ```php + 'one', + 2 => 'two', + default => null, + }; + } + + print_r(countItems(2)); // => two + ``` + + Técnicamente siempre se puede prescindir de `match`, igual que de `switch`. Pero cuando hay que elegir un resultado según valores concretos de una variable, `match` expresa esa intención con la mayor claridad, y ese código es más fácil de leer que una cadena de `elseif`. + +instructions: | + Implementa una función `calculateDeliveryCost()` que reciba el país de entrega y el peso del paquete en kilogramos. La función debe devolver el costo de la entrega. + + Cada país tiene dos tarifas: una para paquetes de hasta 1 kg inclusive y otra para paquetes más pesados: + + * `'canada'`: 600 para paquetes de hasta 1 kg, 900 para el resto + * `'usa'`: 800 para paquetes de hasta 1 kg, 1200 para el resto + * `'germany'`: 700 para paquetes de hasta 1 kg, 1000 para el resto + + Si el país es desconocido, la función debe devolver `null`. + + Ejemplos de llamada de la función: + + ```php + ` puede ir cualquier expresión, incluido el operador ternario. + +tips: + - | + [match](https://www.php.net/manual/es/control-structures.match.php) diff --git a/modules/48-conditionals/70-match/en/EXERCISE.md b/modules/48-conditionals/70-match/en/EXERCISE.md new file mode 100644 index 00000000..1e35a5fe --- /dev/null +++ b/modules/48-conditionals/70-match/en/EXERCISE.md @@ -0,0 +1,23 @@ + +Implement a function `calculateDeliveryCost()` that takes a delivery country and a parcel weight in kilograms. The function should return the delivery cost. + +Each country has two rates: one for parcels weighing up to and including 1 kg, and another for heavier parcels: + +* `'canada'`: 600 for parcels up to 1 kg, 900 for the rest +* `'usa'`: 800 for parcels up to 1 kg, 1200 for the rest +* `'germany'`: 700 for parcels up to 1 kg, 1000 for the rest + +If the country is unknown, the function should return `null`. + +Function call examples: + +```php +` arrow, including the ternary operator. diff --git a/modules/48-conditionals/70-match/en/README.md b/modules/48-conditionals/70-match/en/README.md new file mode 100644 index 00000000..31bc4329 --- /dev/null +++ b/modules/48-conditionals/70-match/en/README.md @@ -0,0 +1,79 @@ +The `match` expression appeared in PHP 8 and solves the same task as `switch`: it picks a result based on a variable's value. The constructs are similar, but `match` is shorter and works as an expression. Let's compare them on one example. Here is how you select a text by an order status with `switch`: + +```php + 'Order is being processed', + 'paid' => 'Order is paid', + 'new' => 'New order', + default => 'Unknown status', +}; +``` + +```text +match (value) { + │ + ├── 'a' → result 1 + ├── 'b' → result 2 + ├── 'c' → result 3 + └── default → default result +} +``` + +To the left of the `=>` arrow is the value to compare, and to the right is any expression that becomes the result. The `default` arm fires when no value matches and plays the role of `else`. If several values lead to the same result, they are listed separated by commas: + +```php + 'small', + 'm' => 'medium', + 'l', 'xl' => 'large', +}; +``` + +The main difference from `switch` is that `match` is an **expression**. The whole construct evaluates to a value, so the result can be assigned to a variable or returned from a function right away. `switch` cannot do this; it needs a separate variable or a `return` inside a `case`. There are other differences too: + +* `match` compares values strictly, like the `===` operator, with no automatic type conversion. `switch` compares loosely, with `==`. +* `match` executes exactly one arm, so no `break` is needed. In `switch`, without `break`, control falls through to the next `case`. +* If nothing matches in `match` and there is no `default`, the program terminates with an `UnhandledMatchError`. In the same case, `switch` does nothing. + +Since `match` returns a value, its result is often returned straight from the function with `return`: + +```php + 'one', + 2 => 'two', + default => null, + }; +} + +print_r(countItems(2)); // => two +``` + +Technically you can always do without `match`, just as without `switch`. But when you need to pick a result by specific values of a variable, `match` expresses that intent most clearly, and such code is easier to read than a chain of `elseif`. diff --git a/modules/48-conditionals/70-match/en/data.yml b/modules/48-conditionals/70-match/en/data.yml new file mode 100644 index 00000000..05b81e0f --- /dev/null +++ b/modules/48-conditionals/70-match/en/data.yml @@ -0,0 +1,5 @@ +--- +name: Match expression +tips: + - | + [match](https://www.php.net/manual/en/control-structures.match.php) diff --git a/modules/48-conditionals/70-match/es/EXERCISE.md b/modules/48-conditionals/70-match/es/EXERCISE.md new file mode 100644 index 00000000..252b73c2 --- /dev/null +++ b/modules/48-conditionals/70-match/es/EXERCISE.md @@ -0,0 +1,23 @@ + +Implementa una función `calculateDeliveryCost()` que reciba el país de entrega y el peso del paquete en kilogramos. La función debe devolver el costo de la entrega. + +Cada país tiene dos tarifas: una para paquetes de hasta 1 kg inclusive y otra para paquetes más pesados: + +* `'canada'`: 600 para paquetes de hasta 1 kg, 900 para el resto +* `'usa'`: 800 para paquetes de hasta 1 kg, 1200 para el resto +* `'germany'`: 700 para paquetes de hasta 1 kg, 1000 para el resto + +Si el país es desconocido, la función debe devolver `null`. + +Ejemplos de llamada de la función: + +```php +` puede ir cualquier expresión, incluido el operador ternario. diff --git a/modules/48-conditionals/70-match/es/README.md b/modules/48-conditionals/70-match/es/README.md new file mode 100644 index 00000000..81abe7b8 --- /dev/null +++ b/modules/48-conditionals/70-match/es/README.md @@ -0,0 +1,79 @@ +La expresión `match` apareció en PHP 8 y resuelve la misma tarea que `switch`: elige un resultado según el valor de una variable. Las construcciones son similares, pero `match` es más corta y funciona como una expresión. Comparémoslas con un ejemplo. Así se selecciona un texto según el estado del pedido con `switch`: + +```php + 'El pedido está en proceso', + 'paid' => 'El pedido está pagado', + 'new' => 'Pedido nuevo', + default => 'Estado desconocido', +}; +``` + +```text +match (valor) { + │ + ├── 'a' → resultado 1 + ├── 'b' → resultado 2 + ├── 'c' → resultado 3 + └── default → resultado por defecto +} +``` + +A la izquierda de la flecha `=>` está el valor a comparar, y a la derecha, cualquier expresión que se convertirá en el resultado. La rama `default` se activa cuando ningún valor coincide y cumple el papel de `else`. Si varios valores llevan al mismo resultado, se enumeran separados por comas: + +```php + 'small', + 'm' => 'medium', + 'l', 'xl' => 'large', +}; +``` + +La principal diferencia con `switch` es que `match` es una **expresión**. Toda la construcción se evalúa a un valor, por lo que el resultado se puede asignar a una variable o devolver desde una función de inmediato. `switch` no puede hacer esto; necesita una variable aparte o un `return` dentro de un `case`. Hay otras diferencias: + +* `match` compara los valores de forma estricta, como el operador `===`, sin conversión automática de tipos. `switch` compara de forma no estricta, con `==`. +* `match` ejecuta exactamente una rama, por lo que no se necesita `break`. En `switch`, sin `break`, el control cae en cascada al siguiente `case`. +* Si nada coincide en `match` y no hay `default`, el programa termina con un error `UnhandledMatchError`. En el mismo caso, `switch` no hace nada. + +Como `match` devuelve un valor, su resultado a menudo se devuelve directamente desde la función con `return`: + +```php + 'one', + 2 => 'two', + default => null, + }; +} + +print_r(countItems(2)); // => two +``` + +Técnicamente siempre se puede prescindir de `match`, igual que de `switch`. Pero cuando hay que elegir un resultado según valores concretos de una variable, `match` expresa esa intención con la mayor claridad, y ese código es más fácil de leer que una cadena de `elseif`. diff --git a/modules/48-conditionals/70-match/es/data.yml b/modules/48-conditionals/70-match/es/data.yml new file mode 100644 index 00000000..a0497120 --- /dev/null +++ b/modules/48-conditionals/70-match/es/data.yml @@ -0,0 +1,5 @@ +--- +name: Expresión match +tips: + - | + [match](https://www.php.net/manual/es/control-structures.match.php) diff --git a/modules/48-conditionals/70-match/ru/EXERCISE.md b/modules/48-conditionals/70-match/ru/EXERCISE.md new file mode 100644 index 00000000..068cf120 --- /dev/null +++ b/modules/48-conditionals/70-match/ru/EXERCISE.md @@ -0,0 +1,23 @@ + +Реализуйте функцию `calculateDeliveryCost()`, которая принимает страну доставки и вес посылки в килограммах. Функция должна вернуть стоимость доставки. + +Для каждой страны есть два тарифа: для посылок весом до 1 кг включительно и для более тяжелых посылок: + +* `'canada'`: 600 для посылок до 1 кг, 900 для остальных +* `'usa'`: 800 для посылок до 1 кг, 1200 для остальных +* `'germany'`: 700 для посылок до 1 кг, 1000 для остальных + +Если страна неизвестна, функция должна вернуть `null`. + +Примеры вызова функции: + +```php +` может стоять любое выражение, в том числе тернарный оператор. diff --git a/modules/48-conditionals/70-match/ru/README.md b/modules/48-conditionals/70-match/ru/README.md new file mode 100644 index 00000000..434937ac --- /dev/null +++ b/modules/48-conditionals/70-match/ru/README.md @@ -0,0 +1,79 @@ +Выражение `match` появилось в PHP 8 и решает ту же задачу, что и `switch`: выбирает результат по значению переменной. Конструкции похожи, но `match` записывается короче и работает как выражение. Сравним их на одном примере. Вот выбор текста по статусу заказа через `switch`: + +```php + 'Заказ в обработке', + 'paid' => 'Заказ оплачен', + 'new' => 'Новый заказ', + default => 'Неизвестный статус', +}; +``` + +```text +match (значение) { + │ + ├── 'a' → результат 1 + ├── 'b' → результат 2 + ├── 'c' → результат 3 + └── default → результат по умолчанию +} +``` + +Слева от стрелки `=>` стоит значение для сравнения, справа — любое выражение, которое станет результатом. Ветка `default` срабатывает, когда не подошло ни одно значение, и играет роль `else`. Если одному результату соответствует несколько значений, их перечисляют через запятую: + +```php + 'small', + 'm' => 'medium', + 'l', 'xl' => 'large', +}; +``` + +Главное отличие от `switch` в том, что `match` — это **выражение**. Вся конструкция вычисляется в значение, поэтому результат сразу присваивают переменной или возвращают из функции. У `switch` так не получится, для результата нужна отдельная переменная или `return` внутри `case`. Есть и другие различия: + +* `match` сравнивает значения строго, как оператор `===`, без автоматического преобразования типов. `switch` сравнивает нестрого, через `==`. +* В `match` выполняется ровно одна ветка, поэтому `break` не нужен. В `switch` без `break` управление "проваливается" в следующий `case`. +* Если в `match` ничего не совпало и нет `default`, программа завершится с ошибкой `UnhandledMatchError`. `switch` в этом случае ничего не делает. + +Раз `match` возвращает значение, его результат часто отдают прямо из функции через `return`: + +```php + 'one', + 2 => 'two', + default => null, + }; +} + +print_r(countItems(2)); // => two +``` + +Технически без `match` всегда можно обойтись, как и без `switch`. Но когда нужно выбрать результат по конкретным значениям переменной, `match` выражает это намерение яснее всего, и читать такой код легче, чем цепочку `elseif`. diff --git a/modules/48-conditionals/70-match/ru/data.yml b/modules/48-conditionals/70-match/ru/data.yml new file mode 100644 index 00000000..b3972cc5 --- /dev/null +++ b/modules/48-conditionals/70-match/ru/data.yml @@ -0,0 +1,6 @@ +--- +name: Выражение match +tips: + - | + [match](https://www.php.net/manual/ru/control-structures.match.php) +definitions: [] diff --git a/modules/48-conditionals/75-elvis/index.php b/modules/48-conditionals/75-elvis/Solution.php similarity index 70% rename from modules/48-conditionals/75-elvis/index.php rename to modules/48-conditionals/75-elvis/Solution.php index 5b2562ed..f8cd1b8c 100644 --- a/modules/48-conditionals/75-elvis/index.php +++ b/modules/48-conditionals/75-elvis/Solution.php @@ -3,7 +3,7 @@ namespace HexletBasics\Conditionals\Elvis; // BEGIN -function generateAmount($amount, $price) +function generateAmount(int $amount, int $price): int { $result = $amount ?: $price * 3; diff --git a/modules/48-conditionals/75-elvis/SolutionTest.php b/modules/48-conditionals/75-elvis/SolutionTest.php index e49dc302..f019ac96 100644 --- a/modules/48-conditionals/75-elvis/SolutionTest.php +++ b/modules/48-conditionals/75-elvis/SolutionTest.php @@ -2,14 +2,12 @@ namespace HexletBasics\Conditionals\Elvis; -use PHPUnit\Framework\TestCase; +use HexletBasics\Exercise\TestCase; class SolutionTest extends TestCase { public function test() { - require 'index.php'; - $this->assertEquals(6, generateAmount(0, 2)); $this->assertEquals(15, generateAmount(0, 5)); $this->assertEquals(1, generateAmount(1, 2)); diff --git a/modules/48-conditionals/75-elvis/description.es.yml b/modules/48-conditionals/75-elvis/description.es.yml index 36e1db41..6e000e10 100644 --- a/modules/48-conditionals/75-elvis/description.es.yml +++ b/modules/48-conditionals/75-elvis/description.es.yml @@ -7,7 +7,7 @@ theory: | ```php = 1) { print_r("{$i}\n"); $i = $i - 1; } - print_r('finished!'); + print_r('Go!'); // END } diff --git a/modules/50-loops/10-while/SolutionTest.php b/modules/50-loops/10-while/SolutionTest.php index 5d790409..e92c2077 100644 --- a/modules/50-loops/10-while/SolutionTest.php +++ b/modules/50-loops/10-while/SolutionTest.php @@ -2,16 +2,14 @@ namespace HexletBasics\Loops\WhileLoop; -use PHPUnit\Framework\TestCase; +use HexletBasics\Exercise\TestCase; class SolutionTest extends TestCase { public function test() { - require 'index.php'; - - $expected = "3\n2\n1\nfinished!"; + $expected = "4\n3\n2\n1\nGo!"; $this->expectOutputString($expected); - printNumbers(3); + printCountdown(4); } } diff --git a/modules/50-loops/10-while/ru/EXERCISE.md b/modules/50-loops/10-while/ru/EXERCISE.md index 17badff6..1ffeda83 100644 --- a/modules/50-loops/10-while/ru/EXERCISE.md +++ b/modules/50-loops/10-while/ru/EXERCISE.md @@ -1,16 +1,14 @@ -Модифицируйте функцию `printNumbers()` так, чтобы она выводила числа в обратном порядке. Для этого нужно идти от верхней границы к нижней. То есть, счетчик должен быть инициализирован максимальным значением, а в теле цикла его нужно уменьшать до нижней границы. +Напишите функцию `printCountdown()`, которая имитирует обратный отсчет перед стартом. Функция принимает количество секунд и печатает числа от этого значения до `1`. +После завершения отсчета функция должна вывести на экран строку `Go!`. ```php 4 +// => 3 +// => 2 +// => 1 +// => Go! ``` diff --git a/modules/50-loops/10-while/ru/README.md b/modules/50-loops/10-while/ru/README.md index bca12c38..dcdf5aed 100644 --- a/modules/50-loops/10-while/ru/README.md +++ b/modules/50-loops/10-while/ru/README.md @@ -1,121 +1,106 @@ -Программы, которые мы пишем, становятся все сложнее и объемнее. Они все еще очень далеки от реальных программ, где количество строк кода измеряется десятками и сотнями тысяч. Текущая сложность уже способна заставить напрячься людей без опыта. Начиная с этого урока, мы переходим к одной из самых сложных базовых тем в программировании – **циклам**. +Помимо условных конструкций, в программировании невозможно обойтись без циклов. Это специальный механизм, позволяющий выполнять любое действие многократно. На его базе строятся практически любые вычисления — от подсчета среднего балла в группе до обработки входящих запросов на сайтах. -Любые прикладные программы служат прагматичным целям. Они помогают управлять сотрудниками и финансами, развлекают, в конце концов. Несмотря на различия, все эти программы выполняют заложенные в них алгоритмы, которые похожи между собой. Что это такое? **Алгоритм** — это последовательность действий или инструкций, которая приводит нас к некоему ожидаемому результату. Это описание подходит под любую программу, но под алгоритмами обычно понимается что-то более специфичное. +Цикл хранит повторяющееся действие в одном месте и запускает его снова, пока условие остается истинным. -Представьте себе, что у нас есть книга, и мы хотим найти внутри нее какую-то конкретную фразу. Саму фразу мы помним, но не знаем, на какой она странице. Как найти нужную страницу? Самый простой и долгий способ — последовательно просматривать страницы до тех пор, пока мы не найдем нужную фразу. В худшем случае придется просмотреть все страницы, но результат мы все равно получим. Именно этот процесс и называется **алгоритмом**. Он включает в себя перебор страниц и логические проверки, нашли мы фразу или нет. +## Первый пример -Заранее неизвестно количество страниц, которое придется посмотреть, но сам процесс просмотра повторяется из раза в раз совершенно одинаково. Для выполнения таких повторяющихся действий как раз и нужны **циклы**. Каждый такой повтор называется **итерацией**. +Пусть программа должна пять раз вывести строку `Hello!`. Чтобы остановить повторение в нужный момент, программе нужна переменная, которая хранит номер текущего шага. Такую переменную обычно называют счетчиком. -Допустим, мы хотим написать функцию, которая выводит на экран все числа от единицы до указанного (через аргументы): +В примере счетчик называется `$counter`. Перед циклом он равен `0`. После каждого вывода строки мы увеличиваем его на единицу. ```php 1 -// => 2 -// => 3 +$counter = 0; +while ($counter < 5) { + print_r("Hello!\n"); + $counter = $counter + 1; +} + +// => Hello! +// => Hello! +// => Hello! +// => Hello! +// => Hello! ``` -Эту функцию невозможно реализовать уже изученными средствами, так как количество выводов на экран заранее не известно. А с циклами это не составит никаких проблем: +Теперь цикл может проверять значение счетчика перед каждым повтором. Пока `$counter < 5`, выполняется код в фигурных скобках после `while`. Такой блок называют телом цикла. -```php - 1 -// => 2 -// => 3 -// => finished! -``` +## Работа цикла по шагам +Перед первым повтором `$counter` равен `0`. -В коде функции использован цикл `while`. Он состоит из трех элементов: +**Шаг 1.** Интерпретатор проверяет `$counter < 5`. Значение `0` меньше `5`, поэтому выполняется тело цикла. +На экран выводится `Hello!`, а `$counter` увеличивается до `1`. -* Ключевое слово `while` — несмотря на схожесть с вызовом функций, это не вызов функции -* Предикат — условие, которое указывается в скобках после `while` и вычисляется на каждой итерации -* Тело цикла — блок кода в фигурных скобках +**Шаг 2.** Интерпретатор снова проверяет условие. Значение `1` все еще меньше `5`, поэтому тело цикла выполняется еще раз. +На экран снова выводится `Hello!`, а `$counter` увеличивается до `2`. -Конструкция читается так: «делать то, что указано в теле цикла, пока истинно условие `$i <= $lastNumber`». +Так продолжается, пока `$counter` не станет равен `5`. При следующей проверке условие `$counter < 5` будет ложным, поэтому цикл завершится. Дальше программа выполнит код после цикла. -Разберем работу этого кода для вызова `printNumbers(3)`: +Та же последовательность на схеме. -```php - 1 +// => 2 +// => 3 +// => Finished! ``` -Подведем итог. Когда все же нужны циклы, а когда можно обойтись без них? Физически невозможно обойтись без циклов, когда алгоритм решения задачи требует повторения каких-то действий и количество этих операций заранее неизвестно — как в нашем примере с книгой. +Цикл `while` печатает числа, пока `$i` не станет больше `$n`. После этого программа выходит из цикла и выполняет `print_r("Finished!\n")`. + +Условие и изменение счетчика зависят от задачи. Счетчик можно увеличивать на `1`, на `2` или сразу на `10`. Его можно уменьшать, если цикл идет от большего значения к меньшему. Можно менять счетчик не на каждом повторе, а через один или после выполнения дополнительной проверки. Главное, чтобы условие когда-нибудь стало ложным. Иначе цикл будет работать бесконечно. diff --git a/modules/50-loops/55-return-from-loop/Makefile b/modules/50-loops/15-conditions-inside-loops/Makefile similarity index 100% rename from modules/50-loops/55-return-from-loop/Makefile rename to modules/50-loops/15-conditions-inside-loops/Makefile diff --git a/modules/50-loops/26-conditions-inside-loops/index.php b/modules/50-loops/15-conditions-inside-loops/Solution.php similarity index 50% rename from modules/50-loops/26-conditions-inside-loops/index.php rename to modules/50-loops/15-conditions-inside-loops/Solution.php index 5caffcba..20333f44 100644 --- a/modules/50-loops/26-conditions-inside-loops/index.php +++ b/modules/50-loops/15-conditions-inside-loops/Solution.php @@ -3,15 +3,15 @@ namespace HexletBasics\Loops\ConditionsInsideLoops; // BEGIN -function countChars($str, $char) +function countHashtags(string $text): int { - $i = 0; + $index = 0; $count = 0; - while ($i < strlen($str)) { - if (strtoupper($str[$i]) === strtoupper($char)) { + while ($index < strlen($text)) { + if ($text[$index] === '#') { $count = $count + 1; } - $i = $i + 1; + $index = $index + 1; } return $count; diff --git a/modules/50-loops/15-conditions-inside-loops/SolutionTest.php b/modules/50-loops/15-conditions-inside-loops/SolutionTest.php new file mode 100644 index 00000000..29969960 --- /dev/null +++ b/modules/50-loops/15-conditions-inside-loops/SolutionTest.php @@ -0,0 +1,16 @@ +assertEquals(2, countHashtags('New post #php #code')); + $this->assertEquals(0, countHashtags('No tags here')); + $this->assertEquals(2, countHashtags('#start and #finish')); + $this->assertEquals(0, countHashtags('')); + } +} diff --git a/modules/50-loops/26-conditions-inside-loops/description.es.yml b/modules/50-loops/15-conditions-inside-loops/description.es.yml similarity index 100% rename from modules/50-loops/26-conditions-inside-loops/description.es.yml rename to modules/50-loops/15-conditions-inside-loops/description.es.yml diff --git a/modules/50-loops/26-conditions-inside-loops/en/EXERCISE.md b/modules/50-loops/15-conditions-inside-loops/en/EXERCISE.md similarity index 100% rename from modules/50-loops/26-conditions-inside-loops/en/EXERCISE.md rename to modules/50-loops/15-conditions-inside-loops/en/EXERCISE.md diff --git a/modules/50-loops/26-conditions-inside-loops/en/README.md b/modules/50-loops/15-conditions-inside-loops/en/README.md similarity index 100% rename from modules/50-loops/26-conditions-inside-loops/en/README.md rename to modules/50-loops/15-conditions-inside-loops/en/README.md diff --git a/modules/50-loops/26-conditions-inside-loops/en/data.yml b/modules/50-loops/15-conditions-inside-loops/en/data.yml similarity index 100% rename from modules/50-loops/26-conditions-inside-loops/en/data.yml rename to modules/50-loops/15-conditions-inside-loops/en/data.yml diff --git a/modules/50-loops/26-conditions-inside-loops/es/EXERCISE.md b/modules/50-loops/15-conditions-inside-loops/es/EXERCISE.md similarity index 100% rename from modules/50-loops/26-conditions-inside-loops/es/EXERCISE.md rename to modules/50-loops/15-conditions-inside-loops/es/EXERCISE.md diff --git a/modules/50-loops/26-conditions-inside-loops/es/README.md b/modules/50-loops/15-conditions-inside-loops/es/README.md similarity index 100% rename from modules/50-loops/26-conditions-inside-loops/es/README.md rename to modules/50-loops/15-conditions-inside-loops/es/README.md diff --git a/modules/50-loops/26-conditions-inside-loops/es/data.yml b/modules/50-loops/15-conditions-inside-loops/es/data.yml similarity index 100% rename from modules/50-loops/26-conditions-inside-loops/es/data.yml rename to modules/50-loops/15-conditions-inside-loops/es/data.yml diff --git a/modules/50-loops/15-conditions-inside-loops/ru/EXERCISE.md b/modules/50-loops/15-conditions-inside-loops/ru/EXERCISE.md new file mode 100644 index 00000000..4f84dab9 --- /dev/null +++ b/modules/50-loops/15-conditions-inside-loops/ru/EXERCISE.md @@ -0,0 +1,9 @@ +Реализуйте функцию `countHashtags()`, которая принимает текст публикации и считает, сколько раз в нем встречается символ `#`. + +```php + 2 +// => 4 +// => 6 +// => 8 +// => 10 +``` + +Цикл `while` перебирает числа от `1` до `10`. Условие внутри цикла проверяет текущее число. Если `$number % 2 === 0`, число делится на `2` без остатка, и программа выводит его на экран. + +Счетчик увеличивается после проверки в любом случае. Это важно. Если увеличивать `$number` только внутри `if`, цикл остановится на первом нечетном числе и будет работать бесконечно. + +## Работа по шагам + +Перед первым повтором `$number` равен `1`. + +**Шаг 1.** Условие цикла `$number <= 10` истинно, поэтому программа входит в тело цикла. Число `1` нечетное, блок `if` не выполняется. Затем `$number` увеличивается до `2`. + +**Шаг 2.** Условие цикла снова истинно. Число `2` четное, поэтому программа печатает `2`. Затем `$number` увеличивается до `3`. + +Дальше цикл продолжает проверять каждое число. Нечетные числа он пропускает, а четные выводит на экран. Когда `$number` станет равен `11`, условие `$number <= 10` станет ложным, и цикл завершится. + +## Условия меняют действие, а не движение + +В таких циклах удобно разделять две части. Счетчик переводит программу к следующему значению, а `if` решает, что делать с текущим значением. + +```php + 5) { + print_r("{$number}\n"); + } + $number = $number + 1; +} +``` + +Здесь цикл проходит тот же диапазон от `1` до `10`, но условие внутри другое. Поэтому программа печатает только числа больше `5`. + +Условие внутри цикла может проверять что угодно. Например, четность числа, совпадение символа, длину строки или значение переменной. Главное, чтобы счетчик продолжал меняться, и цикл мог завершиться. diff --git a/modules/50-loops/15-conditions-inside-loops/ru/assets/conditions-inside-loops.png b/modules/50-loops/15-conditions-inside-loops/ru/assets/conditions-inside-loops.png new file mode 100644 index 00000000..e016c272 Binary files /dev/null and b/modules/50-loops/15-conditions-inside-loops/ru/assets/conditions-inside-loops.png differ diff --git a/modules/50-loops/26-conditions-inside-loops/ru/data.yml b/modules/50-loops/15-conditions-inside-loops/ru/data.yml similarity index 100% rename from modules/50-loops/26-conditions-inside-loops/ru/data.yml rename to modules/50-loops/15-conditions-inside-loops/ru/data.yml diff --git a/modules/50-loops/20-aggregation-numbers/Solution.php b/modules/50-loops/20-aggregation-numbers/Solution.php new file mode 100644 index 00000000..673a3d20 --- /dev/null +++ b/modules/50-loops/20-aggregation-numbers/Solution.php @@ -0,0 +1,24 @@ +assertEquals(2, multiplyNumbersFromRange(2, 2)); - $this->assertEquals(6, multiplyNumbersFromRange(1, 3)); - $this->assertEquals(120, multiplyNumbersFromRange(1, 5)); + $this->assertEquals(0, calculateElectricityBill(0)); + $this->assertEquals(400, calculateElectricityBill(80)); + $this->assertEquals(500, calculateElectricityBill(100)); + $this->assertEquals(850, calculateElectricityBill(150)); + $this->assertEquals(1700, calculateElectricityBill(250)); } } diff --git a/modules/50-loops/20-aggregation-numbers/index.php b/modules/50-loops/20-aggregation-numbers/index.php deleted file mode 100644 index e6ce3b10..00000000 --- a/modules/50-loops/20-aggregation-numbers/index.php +++ /dev/null @@ -1,18 +0,0 @@ -assertEquals('2', joinNumbersFromRange(2, 2)); - $this->assertEquals('12345', joinNumbersFromRange(1, 5)); - $this->assertEquals('101112', joinNumbersFromRange(10, 12)); + $this->assertEquals('+79991234567', sanitizePhoneNumber('+7 (999) 123-45-67')); + $this->assertEquals('88005553535', sanitizePhoneNumber('8 800 555 35 35')); + $this->assertEquals('1234567890', sanitizePhoneNumber('(123) 456-7890')); } } diff --git a/modules/50-loops/23-aggregation-strings/index.php b/modules/50-loops/23-aggregation-strings/index.php deleted file mode 100644 index c1ce835b..00000000 --- a/modules/50-loops/23-aggregation-strings/index.php +++ /dev/null @@ -1,18 +0,0 @@ - abc +print_r('abc' . ''); // => abc +``` + +Поэтому именно пустая строка всегда используется как начальное значение при агрегации строк. diff --git a/modules/50-loops/25-iteration-over-string/Solution.php b/modules/50-loops/25-iteration-over-string/Solution.php new file mode 100644 index 00000000..512aa008 --- /dev/null +++ b/modules/50-loops/25-iteration-over-string/Solution.php @@ -0,0 +1,23 @@ +expectOutputString($expected); - printReversedWordBySymbol($str); + $this->assertEquals('************5678', maskCardNumber('1234567812345678')); + $this->assertEquals('****5678', maskCardNumber('12345678')); + $this->assertEquals('************3333', maskCardNumber('0000111122223333')); } } diff --git a/modules/50-loops/25-iteration-over-string/index.php b/modules/50-loops/25-iteration-over-string/index.php deleted file mode 100644 index 13bd7ef1..00000000 --- a/modules/50-loops/25-iteration-over-string/index.php +++ /dev/null @@ -1,14 +0,0 @@ -= 0) { - print_r("$word[$i]\n"); - $i = $i - 1; - } -} -// END diff --git a/modules/50-loops/25-iteration-over-string/ru/EXERCISE.md b/modules/50-loops/25-iteration-over-string/ru/EXERCISE.md index 3bdf7ffd..52c06d5e 100644 --- a/modules/50-loops/25-iteration-over-string/ru/EXERCISE.md +++ b/modules/50-loops/25-iteration-over-string/ru/EXERCISE.md @@ -1,16 +1,10 @@ +Напишите функцию `maskCardNumber()`, которая скрывает номер банковской карты. Функция должна заменить все символы строки на `*`, кроме последних четырех. -Реализуйте функцию `printReversedWordBySymbol()`, которая печатает переданное слово посимвольно, как в примере из теории, но делает это в обратном порядке. +Пример работы: ```php 't' -// => 'e' -// => 'l' -// => 'x' -// => 'e' -// => 'H' +maskCardNumber('1234567812345678'); // '************5678' +maskCardNumber('12345678'); // '****5678' ``` diff --git a/modules/50-loops/25-iteration-over-string/ru/README.md b/modules/50-loops/25-iteration-over-string/ru/README.md index 40e5237c..cd207491 100644 --- a/modules/50-loops/25-iteration-over-string/ru/README.md +++ b/modules/50-loops/25-iteration-over-string/ru/README.md @@ -3,7 +3,7 @@ ```php 'a' ``` +Цикл проходит по каждому символу строки по очереди: + +```text +'Arya' + │ │ │ │ + A r y a + ↓ ↓ ↓ ↓ +каждый символ обрабатывается по очереди +``` Самое главное в этом коде — поставить правильное условие в `while`. Это можно сделать сразу двумя способами: @@ -31,3 +40,29 @@ printNameBySymbol($name); * `$i <= strlen($name) - 1` Оба способа приводят к одному результату. + +## Переворот строки + +Вместо печати можно собирать новую строку. Например, напишем функцию, которая переворачивает строку: + +```php += 0) { + $result = $result . $text[$i]; + $i = $i - 1; + } + + return $result; +} + +print_r(reverseString('Arya') . "\n"); // => ayrA +print_r(reverseString('hexlet') . "\n"); // => telxeh +``` + +Переменная `$result` инициализируется пустой строкой как нейтральным элементом для конкатенации. Цикл начинается с последнего индекса (`strlen($text) - 1`), двигается к нулю и завершается, когда индекс становится меньше нуля. На каждом шаге к результату добавляется текущий символ. В итоге строка строится в обратном порядке. diff --git a/modules/50-loops/26-conditions-inside-loops/SolutionTest.php b/modules/50-loops/26-conditions-inside-loops/SolutionTest.php deleted file mode 100644 index 8acb9898..00000000 --- a/modules/50-loops/26-conditions-inside-loops/SolutionTest.php +++ /dev/null @@ -1,18 +0,0 @@ -assertEquals(1, countChars('axe', 'a')); - $this->assertEquals(0, countChars('', 'a')); - $this->assertEquals(2, countChars('OpPa', 'p')); - $this->assertEquals(2, countChars('OpPa', 'P')); - } -} diff --git a/modules/50-loops/26-conditions-inside-loops/ru/EXERCISE.md b/modules/50-loops/26-conditions-inside-loops/ru/EXERCISE.md deleted file mode 100644 index c156af1d..00000000 --- a/modules/50-loops/26-conditions-inside-loops/ru/EXERCISE.md +++ /dev/null @@ -1,9 +0,0 @@ - -Функция из теории учитывает регистр букв. То есть `A` и `a` с её точки зрения разные символы. Реализуйте вариант этой же функции, так чтобы регистр букв был не важен: - -```php -assertEquals('got', mysubstr('got', 3)); - $this->assertEquals('go', mysubstr('got', 2)); - $this->assertEquals('g', mysubstr('got', 1)); - } -} diff --git a/modules/50-loops/28-build-strings/description.es.yml b/modules/50-loops/28-build-strings/description.es.yml deleted file mode 100644 index 6db91722..00000000 --- a/modules/50-loops/28-build-strings/description.es.yml +++ /dev/null @@ -1,65 +0,0 @@ ---- - -name: Formación de cadenas en bucles -theory: | - Otro uso de los bucles es la formación de cadenas. Este tipo de tarea es común en la programación web. Se reduce a una simple agregación utilizando interpolación o concatenación. - - Hay una tarea muy popular en las entrevistas: **invertir una cadena**. Se puede resolver de muchas formas diferentes, pero el enfoque más básico es recorrerla carácter por carácter. - - Veamos un ejemplo de cómo funciona esta función: - - ```php - assertFalse(isArgumentsForSubstrCorrect($str, -1, 3), ); - $this->assertFalse(isArgumentsForSubstrCorrect($str, 4, 100), ); - $this->assertFalse(isArgumentsForSubstrCorrect($str, 10, 10), ); - $this->assertFalse(isArgumentsForSubstrCorrect($str, 11, 1), ); - $this->assertFalse(isArgumentsForSubstrCorrect($str, 11, 0), ); - $this->assertTrue(isArgumentsForSubstrCorrect($str, 3, 3)); - $this->assertTrue(isArgumentsForSubstrCorrect($str, 10, 1)); - } -} diff --git a/modules/50-loops/29-edge-cases/description.es.yml b/modules/50-loops/29-edge-cases/description.es.yml deleted file mode 100644 index 5348c233..00000000 --- a/modules/50-loops/29-edge-cases/description.es.yml +++ /dev/null @@ -1,110 +0,0 @@ ---- - -name: Casos límite -theory: | - En esta lección implementaremos la función `mysubstr()`, que extrae una subcadena de una cadena de longitud especificada. - - Recibe dos argumentos: - - * La cadena - * La longitud - - Esta función devuelve la subcadena comenzando desde el primer carácter: - - ```php - = $stringLength) { - return false; - } elseif ($index + $length > $stringLength) { - return false; - } - - return true; -} -// END diff --git a/modules/50-loops/29-edge-cases/ru/EXERCISE.md b/modules/50-loops/29-edge-cases/ru/EXERCISE.md deleted file mode 100644 index 4c851cdc..00000000 --- a/modules/50-loops/29-edge-cases/ru/EXERCISE.md +++ /dev/null @@ -1,30 +0,0 @@ -Реализуйте функцию-предикат `isArgumentsForSubstrCorrect`, которая принимает три аргумента: - -1. строку -2. индекс, с которого начинать извлечение -3. длину извлекаемой подстроки - -Функция возвращает `false`, если хотя бы одно из условий истинно: - -* Отрицательная длина извлекаемой подстроки -* Отрицательный заданный индекс -* Заданный индекс выходит за границу всей строки -* Длина подстроки в сумме с заданным индексом выходит за границу всей строки - -В ином случае функция возвращает `true`. - -Не забывайте, что индексы начинаются с `0`, поэтому индекс последнего элемента — это «длина строки минус 1». - -Пример вызова: - -```php -assertEquals('-----', buildProgressBar(0, 5)); + $this->assertEquals('###--', buildProgressBar(3, 5)); + $this->assertEquals('#####', buildProgressBar(5, 5)); + } +} diff --git a/modules/50-loops/30-syntax-sugar/description.es.yml b/modules/50-loops/30-syntactic-sugar/description.es.yml similarity index 100% rename from modules/50-loops/30-syntax-sugar/description.es.yml rename to modules/50-loops/30-syntactic-sugar/description.es.yml diff --git a/modules/50-loops/30-syntax-sugar/en/EXERCISE.md b/modules/50-loops/30-syntactic-sugar/en/EXERCISE.md similarity index 100% rename from modules/50-loops/30-syntax-sugar/en/EXERCISE.md rename to modules/50-loops/30-syntactic-sugar/en/EXERCISE.md diff --git a/modules/50-loops/30-syntax-sugar/en/README.md b/modules/50-loops/30-syntactic-sugar/en/README.md similarity index 100% rename from modules/50-loops/30-syntax-sugar/en/README.md rename to modules/50-loops/30-syntactic-sugar/en/README.md diff --git a/modules/50-loops/30-syntax-sugar/en/data.yml b/modules/50-loops/30-syntactic-sugar/en/data.yml similarity index 100% rename from modules/50-loops/30-syntax-sugar/en/data.yml rename to modules/50-loops/30-syntactic-sugar/en/data.yml diff --git a/modules/50-loops/30-syntax-sugar/es/EXERCISE.md b/modules/50-loops/30-syntactic-sugar/es/EXERCISE.md similarity index 100% rename from modules/50-loops/30-syntax-sugar/es/EXERCISE.md rename to modules/50-loops/30-syntactic-sugar/es/EXERCISE.md diff --git a/modules/50-loops/30-syntax-sugar/es/README.md b/modules/50-loops/30-syntactic-sugar/es/README.md similarity index 100% rename from modules/50-loops/30-syntax-sugar/es/README.md rename to modules/50-loops/30-syntactic-sugar/es/README.md diff --git a/modules/50-loops/30-syntax-sugar/es/data.yml b/modules/50-loops/30-syntactic-sugar/es/data.yml similarity index 100% rename from modules/50-loops/30-syntax-sugar/es/data.yml rename to modules/50-loops/30-syntactic-sugar/es/data.yml diff --git a/modules/50-loops/30-syntactic-sugar/ru/EXERCISE.md b/modules/50-loops/30-syntactic-sugar/ru/EXERCISE.md new file mode 100644 index 00000000..1787413e --- /dev/null +++ b/modules/50-loops/30-syntactic-sugar/ru/EXERCISE.md @@ -0,0 +1,16 @@ + +Операторы синтаксического сахара особенно удобны, когда нужно постепенно собрать итоговое значение. + +Реализуйте функцию `buildProgressBar()`, которая принимает количество выполненных шагов и общее количество шагов, а затем возвращает строку-индикатор прогресса. + +Выполненные шаги обозначаются символом `#`, а оставшиеся — символом `-`. Старайтесь не использовать встроенные функции работы со строкой в своем решении. + +```php + 15 +``` + +Без сокращений тело цикла было бы длиннее: + +```php +assertEquals('f look back am lost', $result1); - - $result2 = filterString('zz zorro', 'z'); - $this->assertEquals(' orro', $result2); - } -} diff --git a/modules/50-loops/30-syntax-sugar/index.php b/modules/50-loops/30-syntax-sugar/index.php deleted file mode 100644 index 7063b878..00000000 --- a/modules/50-loops/30-syntax-sugar/index.php +++ /dev/null @@ -1,22 +0,0 @@ -assertEquals('I NevEr LooK bAck', makeItFunny($text, 3)); $this->assertEquals('hElLo', makeItFunny('hello', 2)); diff --git a/modules/50-loops/55-return-from-loop/SolutionTest.php b/modules/50-loops/55-return-from-loop/SolutionTest.php deleted file mode 100644 index 3cbcfb3e..00000000 --- a/modules/50-loops/55-return-from-loop/SolutionTest.php +++ /dev/null @@ -1,17 +0,0 @@ -assertTrue(hasChar('Hexlet', 'H')); - $this->assertFalse(hasChar('Hexlet', 'h')); - $this->assertTrue(hasChar('Awesomeness', 'm')); - $this->assertFalse(hasChar('Awesomeness', 'd')); - } -} diff --git a/modules/50-loops/55-return-from-loop/index.php b/modules/50-loops/55-return-from-loop/index.php deleted file mode 100644 index 6f27833a..00000000 --- a/modules/50-loops/55-return-from-loop/index.php +++ /dev/null @@ -1,21 +0,0 @@ -assertTrue(hasAtSymbol('support@example.com')); + $this->assertFalse(hasAtSymbol('wrong-email')); + $this->assertTrue(hasAtSymbol('@admin')); + $this->assertTrue(hasAtSymbol('admin@')); + } +} diff --git a/modules/50-loops/55-return-from-loop/description.es.yml b/modules/50-loops/55-return-from-loops/description.es.yml similarity index 100% rename from modules/50-loops/55-return-from-loop/description.es.yml rename to modules/50-loops/55-return-from-loops/description.es.yml diff --git a/modules/50-loops/55-return-from-loop/en/EXERCISE.md b/modules/50-loops/55-return-from-loops/en/EXERCISE.md similarity index 100% rename from modules/50-loops/55-return-from-loop/en/EXERCISE.md rename to modules/50-loops/55-return-from-loops/en/EXERCISE.md diff --git a/modules/50-loops/55-return-from-loop/en/README.md b/modules/50-loops/55-return-from-loops/en/README.md similarity index 100% rename from modules/50-loops/55-return-from-loop/en/README.md rename to modules/50-loops/55-return-from-loops/en/README.md diff --git a/modules/50-loops/55-return-from-loop/en/data.yml b/modules/50-loops/55-return-from-loops/en/data.yml similarity index 100% rename from modules/50-loops/55-return-from-loop/en/data.yml rename to modules/50-loops/55-return-from-loops/en/data.yml diff --git a/modules/50-loops/55-return-from-loop/es/EXERCISE.md b/modules/50-loops/55-return-from-loops/es/EXERCISE.md similarity index 100% rename from modules/50-loops/55-return-from-loop/es/EXERCISE.md rename to modules/50-loops/55-return-from-loops/es/EXERCISE.md diff --git a/modules/50-loops/55-return-from-loop/es/README.md b/modules/50-loops/55-return-from-loops/es/README.md similarity index 100% rename from modules/50-loops/55-return-from-loop/es/README.md rename to modules/50-loops/55-return-from-loops/es/README.md diff --git a/modules/50-loops/55-return-from-loop/es/data.yml b/modules/50-loops/55-return-from-loops/es/data.yml similarity index 100% rename from modules/50-loops/55-return-from-loop/es/data.yml rename to modules/50-loops/55-return-from-loops/es/data.yml diff --git a/modules/50-loops/55-return-from-loops/ru/EXERCISE.md b/modules/50-loops/55-return-from-loops/ru/EXERCISE.md new file mode 100644 index 00000000..e419e9fa --- /dev/null +++ b/modules/50-loops/55-return-from-loops/ru/EXERCISE.md @@ -0,0 +1,12 @@ + +Реализуйте функцию `hasAtSymbol()`, которая проверяет, есть ли в email символ `@`. + +Функция должна вернуть `true`, как только найдет `@`. Если цикл дошел до конца строки и символ не найден, функция должна вернуть `false`. + +```php + bool(false) +var_dump(isPrime(2)); // => bool(true) +var_dump(isPrime(3)); // => bool(true) +var_dump(isPrime(4)); // => bool(false) +``` + +*Если быть честными до конца, то для решения задачи хватит проверки чисел до значения квадратного корня `$number`, но в нашем случае важно сосредоточиться на понимании работы с условиями внутри цикла.* + +```text +while (...) { + if (условие) { + return значение; ← выход из функции (и из цикла) + } + ... +} +───────────────────────── +Без return цикл продолжается до конца ``` Алгоритм построен таким образом, что если во время последовательного деления на числа до `x / 2` находится хоть одно, которое делит без остатка, то переданный аргумент — не простое число, а значит дальнейшие вычисления не имеют смысла. В этом месте стоит возврат `false`. diff --git a/modules/50-loops/55-return-from-loop/ru/data.yml b/modules/50-loops/55-return-from-loops/ru/data.yml similarity index 100% rename from modules/50-loops/55-return-from-loop/ru/data.yml rename to modules/50-loops/55-return-from-loops/ru/data.yml diff --git a/modules/50-loops/70-for/Solution.php b/modules/50-loops/70-for/Solution.php new file mode 100644 index 00000000..2890e4e3 --- /dev/null +++ b/modules/50-loops/70-for/Solution.php @@ -0,0 +1,22 @@ +assertEquals(1, sumOfSeries(1, 1)); - $this->assertEquals(3, sumOfSeries(1, 2)); - $this->assertEquals(24, sumOfSeries(7, 9)); + $this->assertEquals('my_photo.png', normalizeFilename('my photo.png')); + $this->assertEquals('final_report.pdf', normalizeFilename('final report.pdf')); + $this->assertEquals('already_ready.txt', normalizeFilename('already_ready.txt')); + $this->assertEquals('two__spaces.txt', normalizeFilename('two spaces.txt')); } } diff --git a/modules/50-loops/70-for/index.php b/modules/50-loops/70-for/index.php deleted file mode 100644 index 50eafea6..00000000 --- a/modules/50-loops/70-for/index.php +++ /dev/null @@ -1,22 +0,0 @@ - !og ``` Этот код можно прочитать так: > Цикл с индексом `$i` повторяется, пока соблюдается условие `$i < strlen($str)`, и после каждого шага `$i` увеличивается на 1 -Посмотрим, что находится в круглых скобках: +Разберем подробно, как отрабатывает цикл в примере выше на каждом шаге итераций: -1. Начальное значение счетчика — этот код выполняется ровно один раз перед первой итерацией -2. Предикат (условие повторения циклов) — выполняется на каждой итерации, как и в `while` -3. Описание изменения счетчика — этот код выполняется в конце каждой итерации +```text +reverseString('go!') -В остальном принцип работы точно такой же, как у цикла `while`. +до цикла: result = '' + +1 итерация: currentChar = 'g' +result = currentChar . result + = 'g' . '' + = 'g' + +2 итерация: currentChar = 'o' +result = currentChar . result + = 'o' . 'g' + = 'og' + +3 итерация: currentChar = '!' +result = currentChar . result + = '!' . 'og' + = '!og' +``` + +Теперь посчитаем количество упоминаний символа в строке без учета регистра: + +```php +assertEquals('1', fizzbuzz(1)); + $this->assertEquals('1 2 Fizz', fizzbuzz(3)); + $this->assertEquals('1 2 Fizz 4 Buzz', fizzbuzz(5)); + $this->assertEquals('1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz', fizzbuzz(15)); + } +} diff --git a/modules/50-loops/80-for-in-range/description.es.yml b/modules/50-loops/80-for-in-range/description.es.yml new file mode 100644 index 00000000..984b7f24 --- /dev/null +++ b/modules/50-loops/80-for-in-range/description.es.yml @@ -0,0 +1,111 @@ +--- + +name: Bucle foreach y función range +theory: | + Imagina que tenemos una serie de números del 0 al 9. Queremos sumar estos números. Podríamos hacerlo así: + + ```php + 45 + ``` + + Podemos reescribir este código usando el bucle `foreach` y la función `range()`: + + ```php + 45 + ``` + + La función `range()` crea una secuencia de números dentro de un rango determinado. La llamada `range(0, 9)` devuelve un conjunto de números del 0 al 9. El bucle `foreach` recorre este conjunto: en cada iteración escribe el siguiente número en la variable indicada después de la palabra clave `as` y ejecuta el cuerpo del bucle. + + No se necesita ningún contador. El bucle `foreach` sabe por sí mismo cuándo detenerse: cuando se acaban los números del conjunto. Por eso aquí es imposible olvidarse de cambiar el contador y obtener un bucle infinito. + + La función `range()` admite varias formas de llamada. La forma `range(start, end)` crea una secuencia desde `start` hasta `end`. Ten en cuenta que en PHP el valor final está **incluido** en el rango — en muchos otros lenguajes no es así. La forma `range(start, end, step)` crea una secuencia con el paso `step`. + + Las variantes de `range()` se ven así: + + ```text + range(1, 5) → 1, 2, 3, 4, 5 + range(0, 3) → 0, 1, 2, 3 + range(0, 10, 2) → 0, 2, 4, 6, 8, 10 + └── ambos extremos incluidos + ``` + + El ejemplo de la suma lo vimos arriba. Veamos otro: imprimir los números del 1 al 3: + + ```php + 1 + // => 2 + // => 3 + ``` + + Ahora intentemos mostrar los números en orden inverso. Si el inicio del rango es mayor que el final, `range()` construye por sí mismo una secuencia descendente: + + ```php + 3 + // => 2 + // => 1 + ``` + + La estructura `foreach` con la función `range()` es la forma más corta de recorrer un rango de números. Cuando se necesita control total sobre el contador, por ejemplo para cambiarlo según una regla compleja, los bucles `for` y `while` acuden al rescate. + +instructions: | + FizzBuzz es una de las tareas de entrevista más famosas para programadores principiantes. Se utiliza para comprobar la habilidad de trabajar con bucles y condiciones. Implementa una función `fizzbuzz()` que devuelva una cadena con los números del 1 a `$n`. + + Las reglas: + + - si un número es divisible por 3, se sustituye por la palabra `Fizz`, + - si un número es divisible por 5 — por la palabra `Buzz`, + - si es divisible por 3 y por 5 a la vez — por la palabra `FizzBuzz`. + + Todos los elementos deben unirse con un espacio. + + Esta tarea aparece a menudo en entrevistas de programación, por lo que es útil saber resolverla. + + Ejemplo de llamada de la función: + + ```php + 45 +``` + +We can rewrite this code using the `foreach` loop and the `range()` function: + +```php + 45 +``` + +The `range()` function creates a sequence of numbers within a specific range. The call `range(0, 9)` returns a set of numbers from 0 to 9. The `foreach` loop iterates over this set: on each iteration, it writes the next number into the variable specified after the `as` keyword and executes the loop body. + +No counter is needed. The `foreach` loop knows when to stop by itself — when the numbers in the set run out. So it is impossible to forget to change the counter and get an infinite loop here. + +The `range()` function supports several call variants. The form `range(start, end)` creates a sequence from `start` to `end`. Note that in PHP the end value is **included** in the range — in many other languages it is not. The form `range(start, end, step)` creates a sequence with the step `step`. + +The `range()` variants look like this: + +```text +range(1, 5) → 1, 2, 3, 4, 5 +range(0, 3) → 0, 1, 2, 3 +range(0, 10, 2) → 0, 2, 4, 6, 8, 10 + └── both ends are included +``` + +We covered the sum example above. Let's look at another one — printing the numbers from 1 to 3: + +```php + 1 +// => 2 +// => 3 +``` + +Now let's try to print the numbers in reverse order. If the start of the range is greater than the end, `range()` builds a descending sequence on its own: + +```php + 3 +// => 2 +// => 1 +``` + +The `foreach` construct with the `range()` function is the shortest way to walk over a range of numbers. When full control over the counter is needed, for example changing it by a complex rule, the `for` and `while` loops come to the rescue. diff --git a/modules/50-loops/80-for-in-range/en/data.yml b/modules/50-loops/80-for-in-range/en/data.yml new file mode 100644 index 00000000..779c31ac --- /dev/null +++ b/modules/50-loops/80-for-in-range/en/data.yml @@ -0,0 +1,5 @@ +--- +name: Foreach loop and range function +tips: + - | + [range](https://www.php.net/manual/en/function.range.php) diff --git a/modules/50-loops/80-for-in-range/es/EXERCISE.md b/modules/50-loops/80-for-in-range/es/EXERCISE.md new file mode 100644 index 00000000..8c836617 --- /dev/null +++ b/modules/50-loops/80-for-in-range/es/EXERCISE.md @@ -0,0 +1,28 @@ + +FizzBuzz es una de las tareas de entrevista más famosas para programadores principiantes. Se utiliza para comprobar la habilidad de trabajar con bucles y condiciones. Implementa una función `fizzbuzz()` que devuelva una cadena con los números del 1 a `$n`. + +Las reglas: + +- si un número es divisible por 3, se sustituye por la palabra `Fizz`, +- si un número es divisible por 5 — por la palabra `Buzz`, +- si es divisible por 3 y por 5 a la vez — por la palabra `FizzBuzz`. + +Todos los elementos deben unirse con un espacio. + +Esta tarea aparece a menudo en entrevistas de programación, por lo que es útil saber resolverla. + +Ejemplo de llamada de la función: + +```php + 45 +``` + +Podemos reescribir este código usando el bucle `foreach` y la función `range()`: + +```php + 45 +``` + +La función `range()` crea una secuencia de números dentro de un rango determinado. La llamada `range(0, 9)` devuelve un conjunto de números del 0 al 9. El bucle `foreach` recorre este conjunto: en cada iteración escribe el siguiente número en la variable indicada después de la palabra clave `as` y ejecuta el cuerpo del bucle. + +No se necesita ningún contador. El bucle `foreach` sabe por sí mismo cuándo detenerse: cuando se acaban los números del conjunto. Por eso aquí es imposible olvidarse de cambiar el contador y obtener un bucle infinito. + +La función `range()` admite varias formas de llamada. La forma `range(start, end)` crea una secuencia desde `start` hasta `end`. Ten en cuenta que en PHP el valor final está **incluido** en el rango — en muchos otros lenguajes no es así. La forma `range(start, end, step)` crea una secuencia con el paso `step`. + +Las variantes de `range()` se ven así: + +```text +range(1, 5) → 1, 2, 3, 4, 5 +range(0, 3) → 0, 1, 2, 3 +range(0, 10, 2) → 0, 2, 4, 6, 8, 10 + └── ambos extremos incluidos +``` + +El ejemplo de la suma lo vimos arriba. Veamos otro: imprimir los números del 1 al 3: + +```php + 1 +// => 2 +// => 3 +``` + +Ahora intentemos mostrar los números en orden inverso. Si el inicio del rango es mayor que el final, `range()` construye por sí mismo una secuencia descendente: + +```php + 3 +// => 2 +// => 1 +``` + +La estructura `foreach` con la función `range()` es la forma más corta de recorrer un rango de números. Cuando se necesita control total sobre el contador, por ejemplo para cambiarlo según una regla compleja, los bucles `for` y `while` acuden al rescate. diff --git a/modules/50-loops/80-for-in-range/es/data.yml b/modules/50-loops/80-for-in-range/es/data.yml new file mode 100644 index 00000000..e358111d --- /dev/null +++ b/modules/50-loops/80-for-in-range/es/data.yml @@ -0,0 +1,5 @@ +--- +name: Bucle foreach y función range +tips: + - | + [range](https://www.php.net/manual/es/function.range.php) diff --git a/modules/50-loops/80-for-in-range/ru/EXERCISE.md b/modules/50-loops/80-for-in-range/ru/EXERCISE.md new file mode 100644 index 00000000..f7c7e534 --- /dev/null +++ b/modules/50-loops/80-for-in-range/ru/EXERCISE.md @@ -0,0 +1,28 @@ + +FizzBuzz — одно из самых известных заданий на собеседованиях для начинающих программистов. Его дают, чтобы проверить умение работать с циклами и условиями. Реализуйте функцию `fizzbuzz()`, которая возвращает строку с числами от 1 до `$n`. + +При этом: + +- если число делится на 3, вместо него подставляется слово `Fizz`, +- если число делится на 5 — слово `Buzz`, +- если делится и на 3, и на 5 — слово `FizzBuzz`. + +Все элементы должны соединяться пробелом. + +Это задание нередко встречается на собеседованиях для программистов, поэтому полезно уметь его решать. + +Пример вызова функции: + +```php + 45 +``` + +Такой код мы можем переписать с помощью цикла `foreach` и функции `range()`: + +```php + 45 +``` + +Функция `range()` создает последовательность чисел внутри определенного диапазона. Вызов `range(0, 9)` возвращает набор чисел от 0 до 9. А цикл `foreach` перебирает этот набор: на каждой итерации он записывает очередное число в переменную, указанную после ключевого слова `as`, и выполняет тело цикла. + +Счетчик при этом не нужен. Цикл `foreach` сам знает, когда нужно остановиться — когда числа в наборе закончатся. Поэтому забыть изменить счетчик и получить бесконечный цикл здесь невозможно. + +Функция `range()` поддерживает несколько вариантов вызова. Форма `range(start, end)` создает последовательность от `start` до `end`. Обратите внимание: в PHP конечное значение **входит** в диапазон — во многих других языках это не так. Форма `range(start, end, step)` создает последовательность с шагом `step`. + +Наглядно варианты `range()` выглядят так: + +```text +range(1, 5) → 1, 2, 3, 4, 5 +range(0, 3) → 0, 1, 2, 3 +range(0, 10, 2) → 0, 2, 4, 6, 8, 10 + └── обе границы включены +``` + +Пример с суммой мы рассмотрели выше. Рассмотрим другой — распечатаем на экран числа от 1 до 3: + +```php + 1 +// => 2 +// => 3 +``` + +Теперь попробуем вывести числа в обратном порядке. Если начало диапазона больше конца, `range()` сам построит убывающую последовательность: + +```php + 3 +// => 2 +// => 1 +``` + +Конструкция `foreach` с функцией `range()` — самый короткий способ пройти по диапазону чисел. Когда же нужен полный контроль над счетчиком, например изменение по сложному правилу, на помощь приходят циклы `for` и `while`. diff --git a/modules/50-loops/80-for-in-range/ru/data.yml b/modules/50-loops/80-for-in-range/ru/data.yml new file mode 100644 index 00000000..5bfd10a0 --- /dev/null +++ b/modules/50-loops/80-for-in-range/ru/data.yml @@ -0,0 +1,6 @@ +--- +name: Цикл foreach и функция range +tips: + - | + [range](https://www.php.net/manual/ru/function.range.php) +definitions: [] diff --git a/modules/70-dates/10-timestamp/Makefile b/modules/50-loops/90-debug/Makefile similarity index 100% rename from modules/70-dates/10-timestamp/Makefile rename to modules/50-loops/90-debug/Makefile diff --git a/modules/50-loops/90-debug/Solution.php b/modules/50-loops/90-debug/Solution.php new file mode 100644 index 00000000..dd334e80 --- /dev/null +++ b/modules/50-loops/90-debug/Solution.php @@ -0,0 +1,34 @@ + 1) { + $result .= $count; + } + $count = 1; + } + } + + $result .= $string[-1]; + if ($count > 1) { + $result .= $count; + } + + return $result; +} +// END diff --git a/modules/50-loops/90-debug/SolutionTest.php b/modules/50-loops/90-debug/SolutionTest.php new file mode 100644 index 00000000..e56f2a32 --- /dev/null +++ b/modules/50-loops/90-debug/SolutionTest.php @@ -0,0 +1,18 @@ +assertEquals('a3bc4', compress('aaabcccc')); + $this->assertEquals('abcd', compress('abcd')); + $this->assertEquals('a2b2a2', compress('aabbaa')); + $this->assertEquals('a', compress('a')); + $this->assertEquals('', compress('')); + $this->assertEquals('z3', compress('zzz')); + } +} diff --git a/modules/50-loops/90-debug/description.es.yml b/modules/50-loops/90-debug/description.es.yml new file mode 100644 index 00000000..e795ae89 --- /dev/null +++ b/modules/50-loops/90-debug/description.es.yml @@ -0,0 +1,153 @@ +--- + +name: Depuración +theory: | + Incluso los desarrolladores más experimentados rara vez escriben código que funcione perfectamente a la primera. Cuanto más experimentado es un desarrollador, con más confianza lo **depura**, es decir, analiza los errores y los corrige. + + La habilidad de depurar no aparece por sí sola. Hay que desarrollarla, y cuanto antes mejor. A lo largo del aprendizaje realizarás tareas y practicarás, y con el tiempo el análisis de errores se convertirá en un hábito. + + ## Cómo encontrar un error en el código + + Depurar a base de prueba y error lleva mucho tiempo. Es mucho más productivo entender primero qué fue exactamente lo que salió mal y luego eliminar la causa. Todo trabajo con errores comienza con la comprensión. + + En primer lugar, estudia el **mensaje de error**. PHP siempre indica en él el archivo y la línea donde surgió el problema. Por ejemplo: + + ```bash + Error: Call to undefined function create() in /code/users.php:5 + ``` + + El mensaje dice que la función `create()` no está definida. Este error suele significar una errata en el nombre. Si tu inglés todavía no es muy bueno, un traductor te ayudará. + + Junto con el mensaje, PHP muestra la **pila de llamadas** (stack trace). Contiene la lista de todas las llamadas a funciones desde el inicio del programa hasta el lugar del error. En ella se ve qué funciones se ejecutaron con éxito y dónde surgieron los problemas. Cada entrada indica el archivo, la línea y la función en ejecución. + + Imagina que escribiste código en el archivo `users.php`: la función `main()` llama a la función `create()`, y la propia llamada a `main()` está en la octava línea. La salida completa del error se verá así: + + ```bash + PHP Fatal error: Uncaught Error: Call to undefined function create() in /code/users.php:5 + Stack trace: + #0 /code/users.php(8): main() + #1 {main} + thrown in /code/users.php on line 5 + ``` + + Toda la cadena de eventos se ve de inmediato. El programa arrancó (`{main}`), llegó con éxito a `main()` en la octava línea y aquí se topó con un error de nombre en la quinta. + + ## Tipos de errores + + Los errores más comprensibles en PHP se llaman **errores de sintaxis**. Surgen cuando el código está mal formado, por ejemplo por una comilla equivocada o un paréntesis omitido. En la salida siempre aparece `Parse error:`. + + Veamos un ejemplo. Aquí hay un error de sintaxis porque la comilla de apertura `"` no coincide con la de cierre `'`: + + ```bash + PHP Parse error: Unclosed '(' on line 3 in /code/users.php on line 4 + ``` + + El intérprete ni siquiera empieza a ejecutar un programa así: no puede analizarlo. + + Los más difíciles de corregir son los **errores de programación**. Aquí entran la llamada a una función inexistente, el uso de una variable no declarada o el paso de argumentos de tipo incorrecto. Normalmente surgen en un lugar distinto al de la causa real, lo que complica el diagnóstico. + + Contra los que más cuesta luchar es contra los **errores lógicos**. El programa funciona sin fallos, pero produce un resultado incorrecto con algunos datos de entrada. No hay ningún mensaje de error, solo una salida inesperada. Por ejemplo, una función debe calcular la suma, pero calcula la diferencia: + + ```php + new iteration !!!! + // => 3 + // => 3 + // => new iteration !!!! + // => 4 + // => 7 + ``` + + La salida muestra que hay una iteración menos de las necesarias. El cinco (`$finish`) no entró en la suma. En la condición está `$n < $finish` en lugar de `$n <= $finish`. Hay que sustituir el signo `<` por `<=`. + + Los desarrolladores principiantes a menudo se disgustan por los errores y se consideran descuidados. Todos cometemos errores, tanto los juniors como los seniors. La diferencia está en con cuánta confianza los encuentras. + + Los principiantes piensan que un buen desarrollador mira el código y entiende de inmediato qué está mal. En la práctica esto rara vez funciona. Un fragmento de código sin contexto dice poco. **Si quieres pedir consejo a un desarrollador experimentado, muéstrale primero el mensaje de error.** + +instructions: | + Implementa una función `compress()` que comprima una cadena con el método RLE (Run-Length Encoding). + + El algoritmo: si un carácter se repite varias veces seguidas, se sustituye por el carácter y el número de repeticiones. Los caracteres únicos se escriben sin cifra. + + Ejemplos: + + ```php + new iteration !!!! +// => 3 +// => 3 +// => new iteration !!!! +// => 4 +// => 7 +``` + +The output shows that there is one iteration fewer than needed. The five (`$finish`) did not make it into the addition. The condition uses `$n < $finish` instead of `$n <= $finish`. The `<` sign needs to be replaced with `<=`. + +Beginner developers often get upset about errors and consider themselves careless. Everyone makes mistakes, both juniors and seniors. The difference is how confidently you find them. + +Beginners think that a good developer looks at code and immediately understands what is wrong. This rarely works in practice. A code fragment without context says little. **If you want to ask an experienced developer for advice, show them the error message first.** diff --git a/modules/50-loops/90-debug/en/data.yml b/modules/50-loops/90-debug/en/data.yml new file mode 100644 index 00000000..02c70e9e --- /dev/null +++ b/modules/50-loops/90-debug/en/data.yml @@ -0,0 +1,3 @@ +--- +name: Debugging +tips: [] diff --git a/modules/50-loops/90-debug/es/EXERCISE.md b/modules/50-loops/90-debug/es/EXERCISE.md new file mode 100644 index 00000000..e0c6567e --- /dev/null +++ b/modules/50-loops/90-debug/es/EXERCISE.md @@ -0,0 +1,23 @@ + +Implementa una función `compress()` que comprima una cadena con el método RLE (Run-Length Encoding). + +El algoritmo: si un carácter se repite varias veces seguidas, se sustituye por el carácter y el número de repeticiones. Los caracteres únicos se escriben sin cifra. + +Ejemplos: + +```php + new iteration !!!! +// => 3 +// => 3 +// => new iteration !!!! +// => 4 +// => 7 +``` + +La salida muestra que hay una iteración menos de las necesarias. El cinco (`$finish`) no entró en la suma. En la condición está `$n < $finish` en lugar de `$n <= $finish`. Hay que sustituir el signo `<` por `<=`. + +Los desarrolladores principiantes a menudo se disgustan por los errores y se consideran descuidados. Todos cometemos errores, tanto los juniors como los seniors. La diferencia está en con cuánta confianza los encuentras. + +Los principiantes piensan que un buen desarrollador mira el código y entiende de inmediato qué está mal. En la práctica esto rara vez funciona. Un fragmento de código sin contexto dice poco. **Si quieres pedir consejo a un desarrollador experimentado, muéstrale primero el mensaje de error.** diff --git a/modules/50-loops/90-debug/es/data.yml b/modules/50-loops/90-debug/es/data.yml new file mode 100644 index 00000000..090be8be --- /dev/null +++ b/modules/50-loops/90-debug/es/data.yml @@ -0,0 +1,3 @@ +--- +name: Depuración +tips: [] diff --git a/modules/50-loops/90-debug/ru/EXERCISE.md b/modules/50-loops/90-debug/ru/EXERCISE.md new file mode 100644 index 00000000..4fc41b3f --- /dev/null +++ b/modules/50-loops/90-debug/ru/EXERCISE.md @@ -0,0 +1,23 @@ + +Реализуйте функцию `compress()`, которая сжимает строку методом RLE (Run-Length Encoding). + +Алгоритм: если символ повторяется несколько раз подряд, он заменяется на символ и количество повторений. Одиночные символы записываются без цифры. + +Примеры: + +```php + new iteration !!!! +// => 3 +// => 3 +// => new iteration !!!! +// => 4 +// => 7 +``` + +Вывод показывает, что итераций на одну меньше, чем нужно. Пятерка (`$finish`) в сложение не попала. В условии стоит `$n < $finish` вместо `$n <= $finish`. Нужно заменить знак `<` на `<=`. + +Начинающие разработчики часто расстраиваются из-за ошибок и считают себя невнимательными. Ошибки есть у всех, и у джунов, и у сеньоров. Разница в том, насколько уверенно ты их находишь. + +Начинающие думают, что хороший разработчик смотрит на код и сразу понимает, что не так. Это редко работает на практике. Фрагмент кода без контекста мало что говорит. **Если хотите попросить совет у опытного разработчика, первым делом покажите сообщение об ошибке.** diff --git a/modules/70-dates/10-timestamp/es/data.yml b/modules/50-loops/90-debug/ru/data.yml similarity index 58% rename from modules/70-dates/10-timestamp/es/data.yml rename to modules/50-loops/90-debug/ru/data.yml index e9c93f1e..32222bd2 100644 --- a/modules/70-dates/10-timestamp/es/data.yml +++ b/modules/50-loops/90-debug/ru/data.yml @@ -1,4 +1,4 @@ --- -name: Tiempo +name: Отладка tips: [] definitions: [] diff --git a/modules/60-deep-into-strings/10-unicode/SolutionTest.php b/modules/60-deep-into-strings/10-unicode/SolutionTest.php deleted file mode 100644 index 93e8d94b..00000000 --- a/modules/60-deep-into-strings/10-unicode/SolutionTest.php +++ /dev/null @@ -1,17 +0,0 @@ -assertEquals('ONE', invertCase('one')); - $this->assertEquals('two', invertCase('TWO')); - $this->assertEquals('tHrEE', invertCase('ThRee')); - $this->assertEquals('пРиВеТ!', invertCase('ПрИвЕт!')); - } -} diff --git a/modules/60-deep-into-strings/10-unicode/index.php b/modules/60-deep-into-strings/10-unicode/index.php deleted file mode 100644 index 6bdada65..00000000 --- a/modules/60-deep-into-strings/10-unicode/index.php +++ /dev/null @@ -1,22 +0,0 @@ -assertTrue(startsWith('one', 'o')); - $this->assertFalse(startsWith('one', 'ne')); - $this->assertTrue(startsWith('one', 'on')); - $this->assertTrue(startsWith('one', 'one')); - } -} diff --git a/modules/60-deep-into-strings/40-startwith/index.php b/modules/60-deep-into-strings/40-startwith/index.php deleted file mode 100644 index de0d888c..00000000 --- a/modules/60-deep-into-strings/40-startwith/index.php +++ /dev/null @@ -1,10 +0,0 @@ -assertEquals(2018, getYear(1532435204)); - $this->assertEquals(1986, getYear(532435204)); - $this->assertEquals(1970, getYear(5324352)); - } -} diff --git a/modules/70-dates/10-timestamp/description.es.yml b/modules/70-dates/10-timestamp/description.es.yml deleted file mode 100644 index 31192b3f..00000000 --- a/modules/70-dates/10-timestamp/description.es.yml +++ /dev/null @@ -1,43 +0,0 @@ ---- - -name: Tiempo -theory: | - ¿Alguna vez te has preguntado cómo se almacena el tiempo en una computadora? En esta lección discutiremos cómo funcionan el tiempo y la fecha, y dónde se almacenan. - - ## Tiempo - - Como sabes, encender y apagar la computadora no afecta los relojes. Podemos concluir que los relojes en la computadora funcionan por sí mismos. - - Esto es realmente cierto. Los relojes principales de la computadora son **hardware**. Viven una vida independiente y tienen su propia batería. Al encender la computadora, lee los datos de estos relojes, los guarda en la memoria y comienza a contar el tiempo de forma independiente. Estos relojes se llaman **sistema**. Cualquier cambio en los relojes del sistema también afecta a los relojes de hardware. - - En Linux, Unix, MacOS y la mayoría de otros sistemas operativos, el tiempo del sistema se representa en formato _Unix Time_. Se define como la cantidad de segundos transcurridos desde este momento: - - > 00:00:00 UTC 1 de enero de 1970 (jueves) - - El tiempo desde este momento se llama "época de Unix" (_Unix Epoch_). El tiempo Unix se representa como un número entero que aumenta con cada segundo transcurrido, sin necesidad de cálculos para determinar el año, mes, día, hora o minuto. - - Una fecha específica en formato Unix Time se llama **timestamp** - sello de tiempo. Por ejemplo, para obtener el _timestamp_ actual en PHP, se utiliza la función `time()`: - - ```php - 00:00:00 UTC 1 de enero de 1970 (jueves) - -El tiempo desde este momento se llama "época de Unix" (_Unix Epoch_). El tiempo Unix se representa como un número entero que aumenta con cada segundo transcurrido, sin necesidad de cálculos para determinar el año, mes, día, hora o minuto. - -Una fecha específica en formato Unix Time se llama **timestamp** - sello de tiempo. Por ejemplo, para obtener el _timestamp_ actual en PHP, se utiliza la función `time()`: - -```php - 00:00:00 UTC 1 января 1970 года (четверг) - -Время с этого момента называют «эрой Unix» (_Unix Epoch_). Unix-время представлено целым числом, которое увеличивается с каждой прошедшей секундой без необходимости вычислений для определения года, месяца, дня, часа или минуты. - -Конкретная дата в формате Unix Time называется **timestamp** — временной штамп. Например, для получения текущего _timestamp_ в PHP используется функция `time()`: - -```php -assertEquals('24/07/2018', getCustomDate(1532435204)); - $this->assertEquals('15/11/1986', getCustomDate(532435204)); - $this->assertEquals('03/03/1970', getCustomDate(5324352)); - } -} diff --git a/modules/70-dates/20-date/description.es.yml b/modules/70-dates/20-date/description.es.yml deleted file mode 100644 index ee6e6857..00000000 --- a/modules/70-dates/20-date/description.es.yml +++ /dev/null @@ -1,49 +0,0 @@ ---- - -name: Fecha -theory: | - Una de las principales funciones para trabajar con fechas en PHP es [date()](https://php.net/manual/ru/function.date.php). Convierte una marca de tiempo (_timestamp_) en un formato legible por humanos. - - El primer parámetro de esta función es una descripción del formato de fecha, similar a los formatos utilizados en la función [sprintf()](https://php.net/manual/ru/function.sprintf.php): - - ```php - - [Examples of date - formats](https://www.php.net/manual/en/datetime.format.php) diff --git a/modules/70-dates/20-date/es/EXERCISE.md b/modules/70-dates/20-date/es/EXERCISE.md deleted file mode 100644 index c0a40093..00000000 --- a/modules/70-dates/20-date/es/EXERCISE.md +++ /dev/null @@ -1,11 +0,0 @@ -Complete la implementación de la función `getCustomDate()`, que devuelve una fecha en el formato `15/03/1985` basada en el _timestamp_ proporcionado. - -Ejemplos de uso: - -```php - - [Ejemplos de formatos de - fecha](https://www.php.net/manual/ru/datetime.format.php) -definitions: [] diff --git a/modules/70-dates/20-date/index.php b/modules/70-dates/20-date/index.php deleted file mode 100644 index 9b7015b1..00000000 --- a/modules/70-dates/20-date/index.php +++ /dev/null @@ -1,10 +0,0 @@ -assertEquals(1325376000, getHexletBirthday()); - } -} diff --git a/modules/70-dates/30-mktime/description.es.yml b/modules/70-dates/30-mktime/description.es.yml deleted file mode 100644 index 9771811c..00000000 --- a/modules/70-dates/30-mktime/description.es.yml +++ /dev/null @@ -1,38 +0,0 @@ ---- - -name: mktime() -theory: | - La función [mktime()](https://php.net/manual/ru/function.mktime.php) genera una marca de tiempo (_timestamp_) a partir de la información de tiempo: segundos, horas, minutos y fecha: - - ```bash - mktime( - int $hora, - ?int $minuto = null, - ?int $segundo = null, - ?int $mes = null, - ?int $dia = null, - ?int $año = null - ): int|false - ``` - - `mktime()` es una función que acepta múltiples argumentos, donde cada parte de la fecha y el tiempo se pasa como un parámetro separado: - - ```php - - [List of supported time zones in - PHP](https://www.php.net/manual/en/timezones.php) diff --git a/modules/70-dates/40-timezone/es/EXERCISE.md b/modules/70-dates/40-timezone/es/EXERCISE.md deleted file mode 100644 index 8ada5e26..00000000 --- a/modules/70-dates/40-timezone/es/EXERCISE.md +++ /dev/null @@ -1,2 +0,0 @@ - -Muestre en pantalla la zona horaria actual. diff --git a/modules/70-dates/40-timezone/es/README.md b/modules/70-dates/40-timezone/es/README.md deleted file mode 100644 index 03407e19..00000000 --- a/modules/70-dates/40-timezone/es/README.md +++ /dev/null @@ -1,9 +0,0 @@ -Una de las partes más complicadas al trabajar con fechas son las zonas horarias (_time zones_). - -La Tierra se divide en 24 zonas horarias, por lo que en zonas adyacentes, la hora suele diferir en una hora. El tiempo universal coordinado (UTC) se considera el tiempo cero. Las zonas horarias alrededor del mundo se expresan como un desplazamiento positivo o negativo con respecto al UTC. Por ejemplo, en Moscú, la zona horaria es +3. - -Un detalle interesante de este mecanismo es el cambio de horario de verano e invierno. Mientras que las zonas horarias son fijas, el cambio de horario de verano e invierno es una prerrogativa de los países que periódicamente lo implementan o lo cancelan. El tiempo UTC nunca se cambia, los desplazamientos ocurren en relación a él. Además, hay mil y un problema más. - -La regla principal al trabajar con fechas es almacenar y comparar en formato UTC. Sin embargo, es mejor mostrar las fechas en la zona horaria del usuario. - -Si necesita verificar la zona horaria actual, puede utilizar la función `date_default_timezone_get()`. Para establecer la zona, utilice la función `date_default_timezone_set()`. diff --git a/modules/70-dates/40-timezone/es/data.yml b/modules/70-dates/40-timezone/es/data.yml deleted file mode 100644 index dd52d632..00000000 --- a/modules/70-dates/40-timezone/es/data.yml +++ /dev/null @@ -1,7 +0,0 @@ ---- -name: Zonas horarias -tips: - - > - [Lista de zonas horarias admitidas en - PHP](https://php.net/manual/es/timezones.php) -definitions: [] diff --git a/modules/70-dates/40-timezone/index.php b/modules/70-dates/40-timezone/index.php deleted file mode 100644 index 164d71f5..00000000 --- a/modules/70-dates/40-timezone/index.php +++ /dev/null @@ -1,5 +0,0 @@ - - [Список поддерживаемых временных зон в - PHP](https://php.net/manual/ru/timezones.php) -definitions: [] diff --git a/modules/70-dates/description.en.yml b/modules/70-dates/description.en.yml deleted file mode 100644 index 4a1a1b7c..00000000 --- a/modules/70-dates/description.en.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- - -name: Date and Time -description: | - ПThe concept of time in computers. Hardware Timer and System Timer. Functions for working with date and time in PHP. Timezones diff --git a/modules/70-dates/description.es.yml b/modules/70-dates/description.es.yml deleted file mode 100644 index cfd6fe77..00000000 --- a/modules/70-dates/description.es.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- - -name: Fecha y Hora -description: | - El concepto de tiempo en las computadoras. Temporizadores de hardware y de sistema. Funciones para trabajar con fechas y horas en PHP. Zonas horarias. diff --git a/modules/70-dates/description.ru.yml b/modules/70-dates/description.ru.yml deleted file mode 100644 index 5a611aaa..00000000 --- a/modules/70-dates/description.ru.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- - -name: Дата и Время -description: | - Понятие времени в компьютерах. Аппаратный и Системный таймеры. Функции для работы с датой и временем в PHP. Таймзоны diff --git a/spec.yml b/spec.yml index f3a492ea..0a3602a7 100644 --- a/spec.yml +++ b/spec.yml @@ -3,7 +3,7 @@ language: docker_image: "ghcr.io/hexlet-basics/exercises-php" extension: php - exercise_filename: index.php + exercise_filename: Solution.php exercise_test_filename: SolutionTest.php learn_as: first_language progress: completed diff --git a/src/Functions.php b/src/Functions.php deleted file mode 100644 index 2c1f6870..00000000 --- a/src/Functions.php +++ /dev/null @@ -1,9 +0,0 @@ -getFileName()) . '/Solution.php'; + require $solutionPath; + } +}