Меню

Първи стъпки в правене на сайтове

Влез Излез

Масиви в PHP (част 2) – custom ключове

В първа част на урока за работа с масиви говорихме за това как се създава нов, как можем да ги обхождаме с цикли (for и foreach) и това, че имат ключове.

Споменахме и, че във втора част ще говорим за това как ние сами да задаваме ключовете на елементите. Освен това ще огледаме и за някои предимства и недостатъци когато го правим.

PHP ни дава и възможност сами да определяме индексите на елементите в масива. Това става с една такава стрелкичка: =>.

Ако например искаме да използваме горния масив, но „неделя“ да е с най-малък индекс (както е по американски), тогава бихме могли да напишем:

// елементите от масива са всеки на нов ред за
// по-добра четимост; няма проблем да ги пишем така
// няма да възникнат грешки
$days_of_week = array(
    1 => 'Monday',
    2 => 'Tuesday',
    3 => 'Wednesday',
    4 => 'Thursday',
    5 => 'Friday',
    6 => 'Saturday',
    0 => 'Sunday'
);

Не забравяйте, че елементите са с нулево индексиране – затова „понеделник“ е 1, а „неделя“ е номер 0.

Ако при горния масив използваме for цикъл – „неделя“ ще бъде първият ден в изходния код (защото започваме с променлива със стойност 0), но ако използваме foreach цикъл, PHP ще ни представи елементите в реда, в който са били дефинирани, без да ги подрежда по индекс. Това е една от особеностите в PHP.

Тъй като в повечето случаи искаме елементите да бъдат обработени в реда, в който са били дефинирани е по-добре да използваме foreach цикъл за обхождането им.

Още повече, че при дефинирането на списък дори можем да прескочим някой елемент. Например, ако искаме да опишем само дните, в които ходим на фитнес, можем да използваме:

$gym_days = array(1 => 'Tuesday', 3 =>'Thursday');

В този пример имаме само два елемента – „вторник“ и „чeтвъртък“, но все пак сме запазили индексите, които отговарят на поредния им номер на ден от седмицата (ако тя започва в понеделник и е с нулево индексиране).

Така с foreach цикъл няма да имаме никакъв проблем, но с обикновен for цикъл още на елемент с номер 0 PHP ще ни изведе грешка, че се опитваме да достъпим недефиниран елемент. На всичкото отгоре и ако използваме count() за да определим до какъв максимален индекс трябва да увеличаваме променливата от for цикъла, това би ни върнало 2, тъй като има само 2 елемента в индекса, макар, че имаме елемент с индекс 3 и той дори няма да бъде достъпен.

Да речем, че все пак искаме да си усложним живота и не искаме да използваме foreach – какво можем да направим?

Като за начало – нека определим максималния ключ в масива, така че да знаем до колко да броим.

Също така, нека определим и минималния, така че да не започваме с 0 (което вече казахме, че ще доведе до грешка), а да си започнем от стойност 1, която си е началната в този случай.

Защо просто не направим:

for ($i = 1; $i < 3; $i += 2) {
    ...
}

Защото това ще работи само и единствено с горния масив, а идеята е цикълът ни да е независим от структурата на масива, така че след време, ако дните за фитнес се сменят, останалата част от кода да си остане същата (в противен случай – защо изобщо пишем програмен код – нека просто си направим каквото искаме да правим с тия двата дена и да се свършва).

Тези две стойности можем да намерим съответно с функциите max() и min(). На тези две функции можем или за пуснем неограничен брой аргументи и те ще ни върнат максималната/минималната стойност от него, или можем да пуснем един аргумент, който да е масив (който от своя страна може да има неограничен брой аргументи) и функцията пак да ни върне най-голямата / най-малката стойност.

Проблемът е, че ние в момента не търсим минимална и максимална стойност, а минимален и максимален ключ.

За щастие в PHP съществува функция, която използвайки един масив може да ни върне нов, който да съдържа като стойности ключове от първия. Разбирам, че това може да звучи объркващо, така че нека разгледаме един пример:

$gym_days = array(1 => 'Tuesday', 3 =>'Thursday');

$day_keys = array_keys($gym_days); // стойността на $day_keys ще е array(1, 3)

Надявам се така нещата да придобият някакъв елементарен смисъл.

След това вече можем да използваме функциите min() и max(), за да разберем коя е най-малката и коя е най-голямата стойност в този масив.

Сега вече можем да напишем:

$gym_days = array(1 => 'Tuesday', 3 =>'Thursday');

$day_keys = array_keys($gym_days);

$min = min($day_keys);
$max = max($day_keys);

echo '<ul>';

for ($i = $min; $i <= $max; $i++) {
    echo '<li>' . $gym_days[$i] . '</li>';
}

echo '</ul>';

Пак обаче остава проблемът с грешка в случая когато минем през стойността 2 (несъществуваща в този масив).

Това, което можем да напрвим е просто да проверим дали има такъв елемент и ако няма – да продължим с изпълнението на цикъла при следващата стойност:

$gym_days = array(1 => 'Tuesday', 3 =>'Thursday');

$day_keys = array_keys($gym_days);

$min = min($day_keys);
$max = max($day_keys);

echo '<ul>';

for ($i = $min; $i <= $max; $i++) {
    if (!isset($gym_days[$i])) {
        continue;
    }

    echo '<li>' . $gym_days[$i] . '</li>';
}

echo '</ul>';

Ключовата дума continue в цикъла казва на PHP да прискочи тялото на цикъла и да продължи направо с изпълнението от следващата итерация (това, което би се случило със следващата стойност).

Можем да напишем просто:

...

for ($i = $min; $i <= $max; $i++) {
    if (isset($gym_days[$i])) {
        echo '<li>' . $gym_days[$i] . '</li>';
    }
}

което в този случай е същото, но при по-дълго тяло и/или повече проверки, предходния израз може да е по-четим, тъй като влизаме няколко нива по-навътре в индентация (друг път ще говорим, че стигнете ли вложени повече от 3 нива – нещо вероятно не е както трябва да бъде).

Очаквайте скоро част 3, в която ще видим още какви други custom ключове можем да използваме в PHP.

Вашият коментар

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

To create code blocks or other preformatted text, indent by four spaces:

    This will be displayed in a monospaced font. The first four 
    spaces will be stripped off, but all other whitespace
    will be preserved.
    
    Markdown is turned off in code blocks:
     [This is not a link](http://example.com)

To create not a block, but an inline code span, use backticks:

Here is some inline `code`.

For more help see http://daringfireball.net/projects/markdown/syntax