Как работает foreach php
Перейти к содержимому

Как работает foreach php

  • автор:

# Array iteration

Sometimes two arrays of the same length need to be iterated together, for example:

array_map is the simplest way to accomplish this:

which will output:

This can be done through a common index:

If the two arrays don’t have the incremental keys, array_values($array)[$i] can be used to replace $array[$i] .

If both arrays have the same order of keys, you can also use a foreach-with-key loop on one of the arrays:

Separate arrays can only be looped through if they are the same length and also have the same key name. This means if you don’t supply a key and they are numbered, you will be fine, or if you name the keys and put them in the same order in each array.

You can also use array_combine .

Then you can loop through this by doing the same as before:

# Using an incremental index

This method works by incrementing an integer from 0 to the greatest index in the array.

This also allows iterating an array in reverse order without using array_reverse , which may result in overhead if the array is large.

You can skip or rewind the index easily using this method.

For arrays that do not have incremental indices (including arrays with indices in reverse order, e.g. [1 => "foo", 0 => "bar"] , ["foo" => "f", "bar" => "b"] ), this cannot be done directly. array_values or array_keys can be used instead:

# Using internal array pointers

Each array instance contains an internal pointer. By manipulating this pointer, different elements of an array can be retrieved from the same call at different times.

# Using each

Each call to each() returns the key and value of the current array element, and increments the internal array pointer.

# Using next

Note that this example assumes no elements in the array are identical to boolean false . To prevent such assumption, use key

(opens new window) to check if the internal pointer has reached the end of the array:

This also facilitates iterating an array without a direct loop:

# Using foreach

# Direct loop

# Loop with keys

# Loop by reference

In the foreach loops in the above examples, modifying the value ( $color or $food ) directly doesn’t change its value in the array. The & operator is required so that the value is a reference pointer to the element in the array.

This is similar to:

# Concurrency

PHP arrays can be modified in any ways during iteration without concurrency problems (unlike e.g. Java List s). If the array is iterated by reference, later iterations will be affected by changes to the array. Otherwise, the changes to the array will not affect later iterations (as if you are iterating a copy of the array instead). Compare looping by value:

But if the array is iterated with reference,

The key-value set of 4 => 5 is no longer iterated, and 6 => 7 is changed to 6 => 17 .

# Using ArrayObject Iterator

Php arrayiterator allows you to modify and unset the values while iterating over arrays and objects.

О тонкостях работы foreach в PHP

В недавнем дайджесте интересных ссылок о PHP я обнаружил ссылку на комментарий Никиты Попова на StackOverflow, где он подробно рассказывает о механизме «под капотом» управляющей конструкции foreach.
Поскольку foreach действительно иногда работает более, чем странным образом, я счел полезным сделать перевод этого ответа.

Внимание: этот текст подразумевает наличие базовых знаний о функциональности zval’ов в PHP, в частности вы должны знать что такое refcount и is_ref.
foreach работает с сущностями разных типов: с массивами, с простыми объектами (где перечисляются доступные свойства) и с Traversable-объектами (вернее, объектами, у которых определен внутренний обработчик get_iterator). Здесь мы, в основном, говорим о массивах, но я скажу и об остальных в самом конце.

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

Как работает обход массивов

Массивы в PHP являются упорядоченными хеш-таблицами (элементы хеша объединены в двусвязный список) и foreach обходит массив, следуя указанному порядку.

  • Первый способ — внутренний указатель массива. Этот указатель является частью структуры HashTable и представляет собой просто указатель на текущий элемент хеш-таблицы. Внутренний указатель массива можно безнаказанно изменять, то есть если текущий элемент удалён, внутренний указатель массива будет перемещен на следующий.
  • Второй механизм итерации — внешний указатель массива, под названием HashPosition. Это практически то же самое, что и внутренний указатель массива, но он не является частью HashTable. Этот внешний способ итерации не безопасен к изменениям. Если вы удалите элемент, на который указывает HashPosition, то останетесь с висячим указателем, что приведёт к ошибке сегментации.

Таким образом, внешние указатели массива могут быть использованы только когда вы полностью уверены, что при обходе никакого пользовательского кода выполняться не будет. А такой код может оказаться в самом неожиданном месте, типа обработчика ошибок или деструктора. Вот почему в большинстве случаев PHP приходится использовать внутренний указатель вместо внешнего. Если бы это было иначе, PHP мог бы упасть из-за segmentation fault, как только пользователь начнет делать что-нибудь необычное.

Проблема внутреннего указателя в том, что он является частью HashTable. Так что, когда вы изменяете его, HashTable меняется вместе с ним. И коль скоро обращение к массивам в PHP делается по значению (а не по ссылке), вы вынуждены копировать массив, чтобы в цикле обходить его элементы.

Простой пример, показывающий важность копирования (кстати, не такая большая редкость), это вложенная итерация:

Здесь вы хотите чтобы оба цикла были независимым, а не хитро перебрасывались одним указателем.

Итак, мы дошли до foreach.

Обход массива в foreach

Теперь вы знаете, для чего foreach приходится создавать копию массива, прежде чем обойти его. Но это явно не вся история. Сделает PHP копию или нет, зависит от нескольких факторов:

    Если итерируемый массив является ссылкой, копирования не произойдёт, вместо этого будет выполнен addref:

Итак, это первая часть тайны: функция копирования. Вторая часть это то, как текущая итерация выполняется, и она тоже довольно странная. «Обычный» образец итерации, который вы уже знаете (и который часто используется в PHP — отдельно от foreach) выглядит примерно так (псевдокод):

итерация foreach выглядит немного иначе:

Отличие в том, что move_forward() выполняется в начале, а не в конце цикла. Таким образом, когда код пользователя использует элемент $i, внутренний указатель массива уже указывает на элемент $i+1.

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

Последствия для кода

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

Второе следствие в том, что обычно не должно быть других следствий. Поведение foreach, в основном, вполне понятно пользователю и просто работает как следует. Вас не должно волновать, как происходит копирование (и происходит ли оно вообще), и в какой конкретно момент времени перемещается указатель.

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

Большую коллекцию поведения в пограничных случаях, которые появляются, когда вы модифицируете массив в ходе итерации, можно найти в тестах PHP. Вы можете начать с этого теста, после чего изменять 012 на 013 в адресе, и так далее. Вы увидите, как поведение foreach будет проявляться в разных ситуациях (всякие комбинации ссылок и.т.д.).

А сейчас вернёмся к вашим примерам:

Здесь $array имеет refcount=1 до цикла, так что он не будет копирован, но получит addref. Как только вы присвоите значение $array[], zval будет разделен, так что массив, к которому вы добавляете элементы и итерируемый массив будут двумя разными массивами.

Та же ситуация, что и в первом тесте.

Снова та же история. Во время цикла foreach, у вас refcount=1 и вы получаете только addref, внутренний указатель $array будет изменён. В конце цикла указатель становится NULL (это означает что итерация закончена). each демонстрирует это, возвращая false.

Функции each и reset обе обращаются по ссылке. $array имеет refcount=2 когда доходит до них, в результате чего он должен быть разделен. Снова foreach сработает на отдельном массиве.

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

Здесь вы должны иметь в виду, что current тоже обращается по ссылке, несмотря на то, что не изменяет массив. Это нужно, чтобы согласованно работать со всеми остальными функциями, вроде next, которые обращаются по ссылке (current, вообще-то, предпочтительно-ref функция; она может получить значение, но использует ссылку, если сможет). Ссылка означает, что массив должен быть отделён, следовательно, $array и копия $array, которую использует foreach, будут независимы. Почему вы получаете 2, а не 1, также упомянуто выше: foreach увеличивает указатель массива до начала кода пользователя, а не после. Так что, даже если код все еще работает с первым элементом, foreach уже переместил указатель ко второму.

Теперь попробуем сделать небольшое изменение:

https://amdy.su/wp-admin/options-general.php?page=ad-inserter.php#tab-8

Здесь у нас is_ref=1, так что массив не копирован (так как и выше). Но сейчас когда есть is_ref, массив больше не нужно разделять, передавая по ссылке к current. Теперь current и foreach работают с одним массивом. Вы видите массив сдвинутым на единицу как раз из-за того, как foreach обращается с указателем.

То же самое вы увидите, когда будете делать обход массива по ссылкам:

Здесь самое важное — то, что foreach назначит нашему $array is_ref=1, когда он будет обходить его в цикле по ссылке, так что получится то же, что и выше.

Еще одна небольшая вариация, здесь мы присвоим наш массив еще одной переменной:

Здесь refcount массива $array принимает значение 2, когда цикл начался, так что нужно сделать копию, прежде чем начинать. Таким образом, $array и массив используемый foreach будут разными с самого начала. Вот почему вы получаете ту позицию внутреннего указателя массива, которая была актуальна до начала цикла (в этом случае он был в первой позиции).

Итерация объектов

При итерации объектов имеет смысл рассмотреть два случая:

Объект не Traversable (вернее, не определен внутренний обработчик get_iterator)

В этом случае итерация происходит почти так же, как у массивов. Та же семантика копирования. Единственное отличие: foreach запустит некий дополнительный код, чтобы пропустить свойства, недоступные в текущей области видимости. Еще пара интересных фактов:

  • Для объявленных свойств PHP реоптимизирует хеш-таблицу свойств. Если вы все-таки итерируете объект, он должен реконструировать эту хеш-таблицу (что повышает использование памяти). Не то, чтобы вам следовало беспокоиться об этом, просто имейте в виду.
  • На каждой итерации хеш-таблица свойств будет получена заново, то есть PHP будет вызывать get_properties снова, и снова, и снова. Для «обычных» свойств это не так важно, но если свойства создаются динамически (это часто делают встроенные классы) — то таблица свойств будет пересчитываться каждый раз.
Объект Traversable

В этом случае всё, что сказано выше, не будет применяться никоим образом. Также PHP не будет копировать и не будет применять никакие трюки вроде увеличения указателя до прохода цикла. Я думаю что режим прохода по обходимому (Traversable) объекту куда более предсказуем и не требует дальнейшего описания.

Замена итерируемого объекта во время цикла

Другой необычный случай, который я не упомянул — PHP допускает возможность замены итерируемого объекта во время цикла. Вы можете начать с одним массивом и продолжить, заменив его на полдороге другим. Или начать с массивом, в затем заменить его объектом:

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

Изменение внутреннего указателя массива во время итерации

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

Тут вы можете получить не то, что ожидали: если вызывать next или prev в теле цикла (в случае передачи по ссылке), вы увидите, что внутренний указатель переместился, но это никак не повлияло на поведение итератора. Причина в том, что foreach делает бекап текущей позиции и хеша текущего элемента в HashPointer после каждого прохода цикла. На следующей проходе foreach проверит, не менялась ли позиция внутреннего указателя и попытается восстановить ее, используя этот хеш.

Давайте посмотрим что означает «попытается». Первый пример показывает, как изменение внутреннего указателя не меняет режим foreach:

Теперь давайте попробуем сделать unset элементу, к которому обратится foreach при первом проходе (ключ 1):

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

Имейте в виду, хеш — всего лишь хеш. Случаются коллизии. Попробуем теперь так:

Работает так, как мы и ожидали. Мы удалили ключ EzFY (тот, где как раз был foreach), так что был сделан сброс. Также мы добавили дополнительный ключ, поэтому в конце мы видим 4.

И вот тут приходит неведомое. Что произойдёт, если заменить ключ FYFY с FYFZ? Давайте попробуем:

Сейчас цикл перешёл непосредственно к новому элементу, пропуская всё остальное. Это потому что ключ FYFY имеет коллизию с EzFY (вообще-то, все ключи из этого массива тоже). Более этого, элемент FYFY находится по тому же адресу в памяти, что и элемент EzFY который только что был удален. Так что для PHP это будет та же самая позиция с тем же хешом. Позиция «восстановлена» и происходит переход к концу массива.

PHP Foreach Loop With Examples — PHP Loop Tutorial

Foreach is one of the advance loop feature provided by PHP. In this tutorial, we will explore in-depth of PHP foreach loop.

You should have the basic understanding of PHP to understand this chapter. Before reading this tutorial you should read the following topic in a little bit deeper.

foreach in php loop

The Foreach loop is just another type of advance loop in PHP which we can use with array and object datatype. PHP internally manage the increment counter and initialization in foreach loop so you do not need to take help of initialization and increment like For Loop. If it is used to iterate other than object and array then it will throw an error.

Foreach supports following two type of syntax:

Like other PHP loop construct, we can add multiple lines of the statement in foreach by clubbing the statement in curly braces.

For the better readability, we should always use curly braces with foreach. So that if you or someone else will debug your code after some time it will be readable.

Following is a basic foreach example
$names = array('Ankur', 'John', 'Joy');
foreach ($names as $name) < //foreach loop of name array
print $name . ' ';
>
The above code will print “Ankur John Joy” on the screen.

Now the same example with key value in foreach.
$names = array('Ankur', 'John', 'Joy');
foreach ($names as $key => $value) < //foreach with key value
print $key . '=>' . $value . ',';
>
The above code will print 0=>Ankur,1=>John,2=>Joy, on the screen.

So in the PHP Foreach to iterate we do not need any counter for initialization, increment and condition checking. It will iterate through ever element of collection internally and provide you the collection values for operation.

Below is a flowchart of PHP Foreach loop.

In above flowchart, you can see that the Foreach construct check the array or object expression for its count.

PHP Foreach Loop With Key and Value

You can both key and value of the array by the foreach loop. You need to pass $key => $value both in the second part of the foreach construct.

$array = array(2, 4, 6, 8);
foreach ($array as $key => $value) <
echo 'key is' . $key . ' & value is' . $value."\n";
>

It will print output:

Above example is printing key of the array which is 0,1,2,3.

You can also use the foreach loop to iterate through the unsequential and non-integer key value pair like below:
$array_complex = array(0=>'Ankur', 'fruit'=>'Orange', '5'=>'test', '9'=>'test2');
foreach ($array_complex as $key => $value) <
echo 'key is ' . $key . ' & value is ' . $value."\n";
>

The output of the above will:

PHP Foreach loop by colon syntax

PHP Foreach loop also supports the colon syntax.

Below is the simple example:
$data_names = array('Ankur', 'John', 'Joe');
foreach ($data_names as $key => $value):
echo 'key is ' . $key . ' & value is ' . $value."\n";
endforeach;

Normally we use the colon syntax foreach in HTML. Let us suppose there is an array contains country names. Now you want to list the country as ordered list into your page then you can use the colon syntax in foreach like below.

Above Code will print order list of country like below.

Nested Foreach and Multidimensional Array

We can use the nested foreach. Normally we used the nested foreach for operation on a multidimensional array. But nested foreach is not limited to used with multidimensional array only. Multidimensional Array and nested foreach:
$list_array = array( 1 => array('id' => '1010', 'name' => 'Ankur'), 2 => array('id' => '1020', 'name' => 'John'), 5 => array('id' => '1080', 'name' => 'Joe'), 9 => array('id' => '1007', 'name' => 'Test'), );
foreach ($list_array as $array) <
foreach ($array as $key => $value) <
print 'Key=>' . $key . ' value=>' . $value . "\n";
> print "\n";
>
Below is the output of above code.

So to operate on associative array we can use the nested foreach if required.

Foreach With PHP Objects

Foreach also works with object data type in PHP. It works on both stdClass objects as well as the normal PHP class object. In both stdClass and normal class objects, it iterates on the property of the object. In the normal class object, the foreach behavior works along with the visibility. If you will use foreach inside the class it will iterate to the public, private and protected properties. But if you will use foreach outside the class then it will iterate through only public properties. Standard Object with Foreach: $obj_standard = new stdClass(); $obj_standard->id = 1; $obj_standard->name = 'Ankur'; $obj_standard->country = 'India'; foreach ($obj_standard as $key => $value) < print $key . '=>' . $value . "\n"; >Output of the above code will be:

Normal PHP Class Object and Foreach:
As you know that the foreach will print all accessible property according to the context of the use of the foreach. Let us see the below example:
class test <
var $id;
var $name = 'Ankur';
var $country = 'India';
protected $phone = '12121';
private $email = 'test[at]test';
public function __construct($id) <
$this->id = $id;
>
public function inside_foreach() <
foreach ($this as $key => $value) <
print $key . '=>' . $value . "\n";
>
>
>
$obj_test = new test(3);
print "Outside View \n";
foreach ($obj_test as $key => $value) <
print $key . '=>' . $value . "\n";
>
print "Inside of The Class View \n";
$obj_test->inside_foreach();

The above code will give the following output:

Let us evaluate the reason. So the first foreach after the creation of an object of the class will not have private and protected properties because it is an object of the test class. However $this will always have all i.e. private, protected and public properties access.

We can use the mix of the array, object, single dimension, multidimensional and associative array together with the foreach.

Foreach and List in PHP

From PHP version 5.5.0 we can use list function into the foreach to iterate in the multidimensional array with unpacking the nodes. It helps to minimize the number of foreach nesting and make our code simplified.

Now let us consider the following array.
$mextrix = array(array(1,2),array(3,4),array(5,6));
Not to go till last node value i.e. 1,2,3,4 via foreach either we need to use two loops or after one loop we need to call array element directly like $value[1] or $value[2]. But from PHP 5.5.0 onwards we can use PHP list function inside the foreach loop like below:
$mextrix = array(array(1, 2), array(3, 4), array(5, 6));
foreach ($mextrix as list($a, $b)) <
print $a . ',' . $b . PHP_EOL;
>

The above code will produce the following output:

Because we have used list function with $a and $b.

List can be used to print one out of many in either way like
$mextrix = array(array(1, 2), array(3, 4), array(5, 6));
foreach ($mextrix as list($a)) <
print $a;//will print 1,3,5
>
foreach ($mextrix as list(,$a)) <
print $a;//will print 2,4,6
>

Foreach Pass by value or reference

Foreach works as pass by value methodology however you can pass the value as by reference using &value in the foreach function.

$test_foreach_array = array(2,4,6,8);
foreach($test_foreach_array as $value)<
$value = $value+5;
>
print_r($test_foreach_array);//will print Array ( [0] => 2 [1] => 4 [2] => 6 [3] => 8 )
foreach($test_foreach_array as &$value)<
$value = $value+5;
>
print_r($test_foreach_array);// Will Print Array ( [0] => 7 [1] => 9 [2] => 11 [3] => 13 )

Now let us take a surprising example:
$names = array('Ankur', 'Joe', 'Ajay');
foreach($names as &$value)<
//Do Nothing
>
foreach($names as $value)<
print $value;
>

How to Use PHP foreach Loops

In this tutorial, we will discuss how to use and write a foreach loop in PHP.

PHP foreach Loop

A foreach loop in PHP is perfect for looping through elements part of an indexed array or an associative array. The loop will start from the first element of the array and work through all the elements in order until it reaches the end. You can also iterate through objects.

There are a few reasons why you may pick a foreach loop over a regular for loop. For example, a foreach loop can be a bit easier to read and understand when dealing with arrays. You can also avoid using the count() function. But, of course, there are many other reasons why you may want to pick one over the other.

You will likely need to use nested foreach loops when handling multidimensional arrays. However, you will be writing a single depth foreach loop most of the time.

This tutorial will take you through a wide range of topics on using a foreach loop in PHP. We touch on topics such as arrays, associative arrays, multidimensional arrays, editing elements, using the break statement, and using the continue statement.

Table of Contents

foreach Loop Syntax

There are two different ways you can write a foreach loop in PHP.

Our first example iterates through an array assigning the current element’s value to the variable $value . You can use the $value variable anywhere within the foreach code block.

Our second example is for associative arrays, which will contain a range of keys. On every iteration, the current key will be stored in the $key variable and the element value in the $value variable.

You can write a foreach loop using the alternative syntax. The example below shows the alternative syntax for our first example, but you can use it on either type of foreach loop.

If you need to edit array elements while in the loop, you can precede the $value variable with & . Using & will ensure that the variable is assigned the reference to the value and not simply a copy of the value.

How to Use a foreach Loop in PHP

Foreach loops are the perfect way of iterating through data stored in an array. Unlike a regular for loop, you do not need to know the array’s length as the foreach loop will continue until it reaches the last element. You can use break or continue if you need to exit the loop early or skip an iteration.

Below we go through all the main features of handling a foreach loop, including writing a foreach statement for both a regular array and an associative array.

A foreach Loop for an Indexed Array

In this example, we create a simple PHP foreach loop that will iterate through an array containing a range of strings.

On every iteration, the value of the current element is copied to the $value variable. Inside the loop code block, you can use the value how you see fit by referencing the $value variable.

The code below simply iterates through our array and outputs each value using echo.

Below is the output from the above code. As you can see, each array element has been printed in order.

A foreach Loop for an Associative Array

If you are using an associative array, the method above will still work; however, you will only have access to the value of each element. To also have the key value available, you must specify it within the foreach statement.

The example below will have the key value available in the $key variable and the element value available in the $value variable. Each iteration will progress to the next element until it reaches the end of the array.

In the output below, you can see the key value followed by the element value for each element in the array.

A foreach Loop for a Multidimensional Array

If you have a multidimensional array, you will need to nest a foreach loop inside another foreach loop to access the elements of the inner arrays. The outer loop will iterate through each of the arrays, while the inner loop will iterate through each array’s elements.

You can use foreach on very deep multidimensional arrays, but keep in mind that performance and readability will begin to suffer. The most popular types are two-dimensional arrays and three-dimensional arrays. Anything deeper than three is not very common as they become hard to manage.

In our example below, our outer loop will cycle through each array stored in our $fruits array. The inner loop will cycle through each element of the current array.

The output showcases how our nested foreach loop works in the code example above. Each element is printed before it moves onto the next array. $value is the current array, and $value2 is the current element inside our $value array.

Editing Values within a foreach Loop

If you try editing values using a PHP foreach loop, you will need to add & to the start of the $value variable. Using & before the $value variable will tell PHP to assign $value a reference to the original value and not use a copy of the variable value.

We pass in the reference rather than the value in the example below. Using the reference will allow us to edit the array elements inside the foreach loop.

We also unset the $value after we exit the loop. If you do not unset the $value variable, it will still contain the reference to our last item. If you reuse $value without first using unset, you may end up with unexpected behavior.

In the output below, you can see that the array’s values have been altered.

In our example below, we do not use the reference and simply use a copy of the array’s element value. PHP will not keep any alterations if you use the element’s value.

As you can see in the output, none of our changes to the array are made, and the array appears untouched outside the foreach loop.

Breaking Out of a foreach Loop

Like most other PHP loops, you can use the break statement to end the loop early. You may want to end the loop for various reasons. For example, you found the data you were looking for and performed the required changes.

In our example below, we exit the foreach loop when our value equals “banana”.

Since banana was our second element in the array, we only output the value of the first element in the array.

Using continue in a foreach Loop

If you need to skip or end an iteration of the foreach loop early, you can use the continue statement. There are plenty of reasons why you may want to use continue. For example, skipping an iteration can be helpful if you do not need to process the data in that specific element.

In our code below, we end the current iteration early when the value equals “banana”.

As you can see in our output below, we skipped outputting the value when it was equal to “banana”. After “banana”, we continued to output the rest of the values.

Conclusion

By the end of this tutorial, I hope you have a good understanding of how to use a foreach loop within PHP. It is a standard loop that is great for handling data within arrays, so it is important that you understand how they work.

I suggest that you look into other loops if you are new to programming. Each loop has its use case, so I recommend learning about while loops, for loops, and do-while loops. Understanding and using them correctly can help improve the readability and performance of your code.

If we can improve this tutorial, please do not hesitate to let us know by leaving a comment below.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *