Lekcja 8: Tablice (Arrays) - Indeksowane, Asocjacyjne, Wielowymiarowe

Witaj w ósmej lekcji kursu PHP! Po opanowaniu podstawowych struktur kontrolnych, takich jak instrukcje warunkowe i pętle, nadszedł czas, aby zagłębić się w jeden z najważniejszych i najczęściej używanych typów danych w PHP: tablice (arrays). Tablice w PHP są niezwykle elastyczne i potężne; mogą przechowywać uporządkowany zbiór różnego rodzaju wartości, do których można się odwoływać za pomocą indeksu (numerycznego) lub klucza (ciągu znaków). W tej lekcji omówimy tablice indeksowane, asocjacyjne, wielowymiarowe oraz podstawowe operacje na nich.

Czym jest tablica w PHP?

Tablica w PHP to specjalna zmienna, która może przechowywać wiele wartości pod jedną nazwą. Można ją sobie wyobrazić jako mapę lub słownik, gdzie każda wartość jest powiązana z unikalnym kluczem. Klucze mogą być liczbami całkowitymi (co tworzy tablicę indeksowaną, podobną do tablic w innych językach programowania) lub ciągami znaków (co tworzy tablicę asocjacyjną).

Elementy tablicy mogą być dowolnego typu danych, w tym liczbami, ciągami znaków, wartościami logicznymi, obiektami, a nawet innymi tablicami (co prowadzi do tablic wielowymiarowych).

Tworzenie Tablic

W PHP tablice można tworzyć na kilka sposobów:

1. Konstrukcja array() (starszy sposób)

Tradycyjnie tablice tworzyło się za pomocą konstrukcji językowej array().

<?php
// Tablica indeksowana numerycznie
$owoce = array("jabłko", "banan", "pomarańcza");

// Tablica asocjacyjna
$osoba = array(
    "imie" => "Jan",
    "nazwisko" => "Kowalski",
    "wiek" => 30
);

// Pusta tablica
$pustaTablica = array();
?>

2. Skrócona składnia [] (od PHP 5.4, zalecana)

Od wersji PHP 5.4 wprowadzono krótszą i bardziej czytelną składnię tworzenia tablic za pomocą nawiasów kwadratowych []. Jest to obecnie preferowany sposób.

<?php
// Tablica indeksowana numerycznie
$kolory = ["czerwony", "zielony", "niebieski"];

// Tablica asocjacyjna
$samochod = [
    "marka" => "Toyota",
    "model" => "Corolla",
    "rok" => 2021
];

// Pusta tablica
$innaPustaTablica = [];

// Mieszana tablica (klucze numeryczne i stringowe)
$mieszana = ["tekst", 5, "klucz" => "wartość", 100];
?>

3. Tworzenie tablicy poprzez bezpośrednie przypisanie do kluczy

Można również tworzyć lub dodawać elementy do tablicy, przypisując wartości do określonych kluczy. Jeśli tablica jeszcze nie istnieje, zostanie utworzona.

<?php
$daneUzytkownika = []; // lub $daneUzytkownika = array();
$daneUzytkownika["login"] = "admin123";
$daneUzytkownika["email"] = "admin@example.com";
$daneUzytkownika["aktywny"] = true;

// Dodawanie elementów do tablicy indeksowanej bez podawania klucza
// PHP automatycznie przypisze kolejny dostępny indeks numeryczny (zaczynając od 0)
$liczby = [];
$liczby[] = 10; // Klucz 0
$liczby[] = 20; // Klucz 1
$liczby[] = 30; // Klucz 2

// Jeśli tablica już ma elementy, PHP znajdzie największy istniejący indeks całkowity
// i użyje następnej liczby całkowitej jako nowego klucza.
$testIndeksow = [10 => "a", 2 => "b"];
$testIndeksow[] = "c"; // Zostanie dodane pod kluczem 11 (max(10,2)+1)

print_r($daneUzytkownika);
echo "<br>";
print_r($liczby);
echo "<br>";
print_r($testIndeksow);
?>

Tablice Indeksowane (Numeryczne)

Tablice indeksowane używają liczb całkowitych jako kluczy. Domyślnie, jeśli nie podamy kluczy podczas tworzenia tablicy za pomocą array() lub [], PHP automatycznie przypisuje indeksy numeryczne, zaczynając od 0.

<?php
$dniTygodnia = ["Poniedziałek", "Wtorek", "Środa", "Czwartek", "Piątek", "Sobota", "Niedziela"];

// Dostęp do elementów tablicy
echo "Pierwszy dzień tygodnia: " . $dniTygodnia[0] . "<br>"; // Poniedziałek (indeks 0)
echo "Trzeci dzień tygodnia: " . $dniTygodnia[2] . "<br>"; // Środa (indeks 2)

// Modyfikacja elementu tablicy
$dniTygodnia[6] = "Słoneczna Niedziela";
echo "Ostatni dzień tygodnia (po modyfikacji): " . $dniTygodnia[6] . "<br>";

// Wyświetlanie całej tablicy (do celów debugowania)
// print_r() wyświetla informacje o zmiennej w czytelnej formie
echo "<pre>"; // Tag 
 dla lepszego formatowania w HTML
print_r($dniTygodnia);
echo "</pre>";

// var_dump() wyświetla bardziej szczegółowe informacje, w tym typy danych
echo "<pre>";
var_dump($dniTygodnia);
echo "</pre>";

// Iteracja po tablicy indeksowanej za pomocą pętli for
echo "<h3>Dni tygodnia (pętla for):</h3>";
// count() zwraca liczbę elementów w tablicy
for ($i = 0; $i < count($dniTygodnia); $i++) {
    echo "Dzień $i: " . $dniTygodnia[$i] . "<br>";
}

// Iteracja za pomocą pętli foreach (preferowany sposób)
echo "<h3>Dni tygodnia (pętla foreach):</h3>";
foreach ($dniTygodnia as $dzien) {
    echo $dzien . "<br>";
}
?>

Klucze w tablicach indeksowanych nie muszą być ciągłe ani zaczynać się od 0, jeśli zdefiniujemy je jawnie, np. $mojeNumery = [5 => 'pięć', 10 => 'dziesięć'];. Jednak przy automatycznym indeksowaniu (np. przez $tablica[] = wartosc;) PHP będzie starało się używać kolejnych liczb całkowitych.

Tablice Asocjacyjne

Tablice asocjacyjne używają nazwanych kluczy (ciągów znaków) do identyfikowania swoich elementów. Są one niezwykle przydatne do przechowywania danych o bardziej złożonej strukturze, gdzie nazwy kluczy mają semantyczne znaczenie.

<?php
$daneProduktu = [
    "nazwa" => "Laptop Super Wydajny",
    "cena" => 3999.99,
    "producent" => "TechCorp",
    "dostepny" => true,
    "specyfikacja" => [
        "procesor" => "Intel i7",
        "ram" => "16GB",
        "dysk" => "512GB SSD"
    ]
];

// Dostęp do elementów tablicy asocjacyjnej
echo "Nazwa produktu: " . $daneProduktu["nazwa"] . "<br>";
echo "Cena: " . $daneProduktu["cena"] . " zł<br>";

// Modyfikacja elementu
$daneProduktu["cena"] = 3799.00;
echo "Nowa cena: " . $daneProduktu["cena"] . " zł<br>";

// Dodawanie nowego elementu
$daneProduktu["gwarancja_lata"] = 2;

echo "<h3>Dane produktu (pętla foreach z kluczami):</h3>";
foreach ($daneProduktu as $klucz => $wartosc) {
    if (is_array($wartosc)) { // Sprawdzenie, czy wartość jest tablicą (dla specyfikacji)
        echo htmlspecialchars(ucfirst($klucz)) . ": <br>";
        echo "<ul>";
        foreach ($wartosc as $subKlucz => $subWartosc) {
            echo "<li>" . htmlspecialchars(ucfirst($subKlucz)) . ": " . htmlspecialchars($subWartosc) . "</li>";
        }
        echo "</ul>";
    } else {
        echo htmlspecialchars(ucfirst($klucz)) . ": " . htmlspecialchars(is_bool($wartosc) ? ($wartosc ? 'Tak' : 'Nie') : $wartosc) . "<br>";
    }
}

// Sprawdzanie, czy klucz istnieje w tablicy
if (array_key_exists("producent", $daneProduktu)) {
    echo "Klucz 'producent' istnieje w tablicy.<br>";
}

if (isset($daneProduktu["kolor"])) {
    echo "Kolor produktu: " . $daneProduktu["kolor"] . "<br>";
} else {
    echo "Informacja o kolorze produktu jest niedostępna.<br>";
}
?>

Klucze w tablicach asocjacyjnych muszą być unikalne. Jeśli przypiszesz wartość do istniejącego klucza, poprzednia wartość zostanie nadpisana. Klucze mogą być dowolnymi ciągami znaków, ale PHP może próbować konwertować niektóre wartości na klucze całkowite, jeśli wyglądają jak liczby (np. "8" zostanie potraktowane jako int 8).

Tablice Wielowymiarowe

Jak wspomniano, elementy tablicy mogą być innymi tablicami. Tworzy to tablice wielowymiarowe, które są przydatne do reprezentowania bardziej złożonych struktur danych, takich jak macierze, tabele, drzewa itp.

<?php
// Tablica dwuwymiarowa (macierz)
$macierz = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
];

// Dostęp do elementu: $macierz[wiersz][kolumna]
echo "Element w drugim wierszu, trzeciej kolumnie: " . $macierz[1][2] . "<br>"; // 6 (indeksy od 0)

// Tablica studentów, gdzie każdy student jest tablicą asocjacyjną
$studenci = [
    ["imie" => "Alicja", "nazwisko" => "Nowak", "oceny" => [5, 4, 5]],
    ["imie" => "Piotr", "nazwisko" => "Zieliński", "oceny" => [3, 4, 4]],
    ["imie" => "Ewa", "nazwisko" => "Wiśniewska", "oceny" => [5, 5, 5, 4]]
];

echo "<h3>Lista studentów i ich pierwsza ocena:</h3>";
foreach ($studenci as $student) {
    echo "Student: " . htmlspecialchars($student["imie"]) . " " . htmlspecialchars($student["nazwisko"]);
    if (!empty($student["oceny"])) {
        echo ", Pierwsza ocena: " . $student["oceny"][0];
    }
    echo "<br>";
}

// Dostęp do konkretnej oceny konkretnego studenta
echo "Druga ocena Piotra: " . $studenci[1]["oceny"][1] . "<br>"; // 4

// Wyświetlanie całej struktury wielowymiarowej
echo "<pre>";
print_r($studenci);
echo "</pre>";
?>

Można tworzyć tablice o dowolnej liczbie wymiarów, choć w praktyce rzadko używa się więcej niż 2-3 wymiary, ponieważ zarządzanie nimi staje się skomplikowane.

Podstawowe Operacje na Tablicach

PHP oferuje bogaty zestaw funkcji do pracy z tablicami. Oto kilka podstawowych i często używanych:

<?php
$mojeNumery = [10, 20, 30, 40, 50];
echo "Liczba elementów: " . count($mojeNumery) . "<br>"; // 5

if (in_array(30, $mojeNumery)) {
    echo "Liczba 30 znajduje się w tablicy.<br>";
}

$konfiguracja = ["host" => "localhost", "user" => "root", "pass" => null];
if (array_key_exists("pass", $konfiguracja)) {
    echo "Klucz 'pass' istnieje.<br>"; // Tak
}
if (isset($konfiguracja["pass"])) {
    echo "Klucz 'pass' jest ustawiony i nie jest NULL.<br>"; // Nie, bo jest NULL
} else {
    echo "Klucz 'pass' nie jest ustawiony lub jest NULL.<br>";
}

// Dodawanie elementów
array_push($mojeNumery, 60, 70);
print_r($mojeNumery); // [10, 20, 30, 40, 50, 60, 70]
echo "<br>";

array_unshift($mojeNumery, 0, 5);
print_r($mojeNumery); // [0, 5, 10, 20, 30, 40, 50, 60, 70]
echo "<br>";

// Usuwanie elementów
$ostatni = array_pop($mojeNumery);
echo "Usunięto ostatni element: $ostatni<br>"; // 70
print_r($mojeNumery);
echo "<br>";

$pierwszy = array_shift($mojeNumery);
echo "Usunięto pierwszy element: $pierwszy<br>"; // 0
print_r($mojeNumery); // Klucze numeryczne zostały zreindeksowane od 0
echo "<br>";

unset($mojeNumery[2]); // Usuwa element o kluczu 2 (który teraz ma wartość 20)
print_r($mojeNumery); // Pozostanie dziura w indeksacji, np. klucze 0, 1, 3, 4...
echo "<br>";

// Aby "naprawić" indeksację po unset, można użyć array_values()
$naprawioneNumery = array_values($mojeNumery);
print_r($naprawioneNumery); // Klucze będą od 0 do n-1
echo "<br>";
?>

Istnieje o wiele więcej funkcji do manipulacji tablicami, takich jak sortowanie (sort(), rsort(), asort(), arsort(), ksort(), krsort(), usort()), łączenie (array_merge(), array_combine()), wyszukiwanie (array_search()), filtrowanie (array_filter()), mapowanie (array_map()) i wiele innych. Zostaną one szczegółowo omówione w kolejnej lekcji poświęconej funkcjom tablicowym.

Iteracja po Tablicach - Podsumowanie

Jak widzieliśmy, głównymi sposobami iteracji po tablicach są pętle for i foreach.

Pętle while i do...while mogą być również używane do iteracji po tablicach, zwłaszcza w połączeniu z funkcjami takimi jak each() (przestarzała od PHP 7.2, usunięta w PHP 8.0), current(), key(), next(), prev(), reset(), które pozwalają na ręczne zarządzanie wewnętrznym wskaźnikiem tablicy. Jednak foreach jest zazwyczaj prostszym i bezpieczniejszym wyborem.

Podsumowanie Lekcji

W tej obszernej lekcji nauczyliśmy się, czym są tablice w PHP i jak fundamentalną rolę odgrywają. Poznaliśmy różne sposoby ich tworzenia, ze szczególnym uwzględnieniem nowoczesnej składni []. Zrozumieliśmy różnicę między tablicami indeksowanymi (numerycznymi) a asocjacyjnymi (z kluczami stringowymi) oraz zobaczyliśmy, jak tworzyć i uzyskiwać dostęp do elementów tablic wielowymiarowych. Omówiliśmy również podstawowe operacje, takie jak zliczanie elementów, sprawdzanie istnienia wartości/kluczy, dodawanie i usuwanie elementów. Na koniec podsumowaliśmy najlepsze praktyki dotyczące iteracji po tablicach za pomocą pętli for i foreach.

Tablice są wszechobecne w PHP i stanowią podstawę wielu bardziej złożonych struktur danych i algorytmów. W następnej lekcji przyjrzymy się bliżej bogatemu zestawowi wbudowanych funkcji PHP przeznaczonych do pracy z tablicami, które znacznie ułatwiają ich sortowanie, przeszukiwanie, filtrowanie i transformowanie.


Zadanie praktyczne

Napisz skrypt PHP, który:

  1. Stwórz tablicę indeksowaną o nazwie $filmy zawierającą tytuły co najmniej trzech Twoich ulubionych filmów. Wyświetl drugi film z listy.
  2. Stwórz tablicę asocjacyjną o nazwie $ksiazka, która będzie przechowywać informacje o książce: tytuł, autora, rok wydania i liczbę stron. Wyświetl wszystkie te informacje w czytelny sposób.
  3. Do tablicy $ksiazka dodaj nowy element o kluczu "gatunek" i przypisz mu odpowiednią wartość. Następnie zmodyfikuj rok wydania na inny. Wyświetl zaktualizowaną tablicę $ksiazka używając print_r().
  4. Stwórz tablicę wielowymiarową $menuRestauracji, gdzie każdy element główny to kategoria (np. "Przystawki", "Dania główne", "Desery"), a wartością dla tych kluczy są tablice indeksowane zawierające nazwy dań w danej kategorii. Wyświetl wszystkie dania główne używając pętli foreach.
  5. Sprawdź, czy w tablicy $filmy znajduje się film o tytule "Matrix" (użyj in_array()). Wyświetl odpowiedni komunikat.

Pokaż przykładowe rozwiązanie
<?php
// 1. Tablica filmów
$filmy = ["Incepcja", "Skazani na Shawshank", "Władca Pierścieni: Drużyna Pierścienia"];
echo "<h3>Ulubione filmy:</h3>";
if (count($filmy) >= 2) {
    echo "Drugi film na liście: " . htmlspecialchars($filmy[1]) . "<br>";
} else {
    echo "Za mało filmów na liście, aby wyświetlić drugi.<br>";
}

// 2. Tablica asocjacyjna książki
$ksiazka = [
    "tytuł" => "Rok 1984",
    "autor" => "George Orwell",
    "rok_wydania" => 1949,
    "liczba_stron" => 328
];
echo "<h3>Informacje o książce:</h3>";
foreach ($ksiazka as $klucz => $wartosc) {
    echo htmlspecialchars(ucfirst(str_replace("_", " ", $klucz))) . ": " . htmlspecialchars($wartosc) . "<br>";
}

// 3. Modyfikacja i dodanie elementu do książki
$ksiazka["gatunek"] = "Dystopia";
$ksiazka["rok_wydania"] = 1950; // Zmieniamy rok

echo "<h3>Zaktualizowane informacje o książce (print_r):</h3>";
echo "<pre>";
print_r($ksiazka);
echo "</pre>";

// 4. Tablica wielowymiarowa - menu restauracji
$menuRestauracji = [
    "Przystawki" => ["Tatar wołowy", "Śledź w śmietanie", "Bruschetta"],
    "Dania główne" => ["Schabowy z kapustą", "Pierogi ruskie", "Łosoś z grilla"],
    "Desery" => ["Szarlotka na ciepło", "Sernik", "Lody waniliowe"]
];

echo "<h3>Dania główne:</h3>";
if (isset($menuRestauracji["Dania główne"]) && is_array($menuRestauracji["Dania główne"])) {
    foreach ($menuRestauracji["Dania główne"] as $danie) {
        echo htmlspecialchars($danie) . "<br>";
    }
} else {
    echo "Brak dań głównych w menu.<br>";
}

// 5. Sprawdzenie czy "Matrix" jest w tablicy filmów
echo "<h3>Czy 'Matrix' jest na liście filmów?</h3>";
$szukanyFilm = "Matrix";
if (in_array($szukanyFilm, $filmy)) {
    echo "Tak, film '" . htmlspecialchars($szukanyFilm) . "' znajduje się na liście.<br>";
} else {
    echo "Nie, filmu '" . htmlspecialchars($szukanyFilm) . "' nie ma na liście.<br>";
}
?>
            

Zadanie do samodzielnego wykonania

Stwórz tablicę wielowymiarową reprezentującą koszyk zakupów. Każdy element koszyka powinien być tablicą asocjacyjną zawierającą: nazwę produktu, cenę jednostkową i ilość. Napisz skrypt, który:

  1. Wyświetli zawartość koszyka w czytelnej formie (nazwa, cena, ilość, wartość pozycji).
  2. Obliczy i wyświetli łączną wartość wszystkich produktów w koszyku.
  3. Doda nowy produkt do koszyka.
  4. Usunie jeden z produktów z koszyka (np. po nazwie lub indeksie).


FAQ - Tablice w PHP

Jaka jest maksymalna liczba elementów w tablicy PHP?

Teoretycznie, maksymalna liczba elementów w tablicy PHP jest ograniczona jedynie dostępną pamięcią serwera. W praktyce można tworzyć bardzo duże tablice, ale należy pamiętać o wydajności i zużyciu pamięci, zwłaszcza przy operacjach na nich.

Czy klucze w tablicach asocjacyjnych są wrażliwe na wielkość liter?

Tak, klucze w tablicach asocjacyjnych PHP są wrażliwe na wielkość liter. Oznacza to, że $tablica["Klucz"] i $tablica["klucz"] odnoszą się do dwóch różnych elementów (lub jeden z nich może nie istnieć).

Jak sprawdzić, czy tablica jest pusta?

Można to zrobić na kilka sposobów: używając funkcji empty($tablica), która zwróci true, jeśli tablica nie ma elementów (lub jeśli sama zmienna nie jest ustawiona). Można też sprawdzić, czy count($tablica) === 0.

Czy mogę mieć mieszane klucze (numeryczne i stringowe) w jednej tablicy?

Tak, PHP jest bardzo elastyczne pod tym względem. Jedna tablica może zawierać zarówno elementy z kluczami numerycznymi (indeksowanymi), jak i elementy z kluczami stringowymi (asocjacyjnymi).

Co się stanie, jeśli spróbuję uzyskać dostęp do nieistniejącego klucza w tablicy?

Jeśli spróbujesz odczytać wartość z nieistniejącego klucza, PHP wygeneruje ostrzeżenie (Warning: Undefined array key "nazwa_klucza" w PHP 8+, wcześniej Notice) i wyrażenie zwróci NULL. Dlatego zawsze warto sprawdzać istnienie klucza za pomocą isset() lub array_key_exists() przed próbą odczytu, lub używać operatora koalescencji NULL (??).

Jak przekazać tablicę do funkcji przez referencję?

Aby funkcja mogła modyfikować oryginalną tablicę (a nie jej kopię), należy w definicji funkcji poprzedzić nazwę parametru tablicy znakiem ampersand (&), np. function modyfikujTablice(&$mojaTablica) { ... }.

Czy tablice w PHP są tym samym co listy lub słowniki w Pythonie?

Tablice w PHP są bardziej uniwersalne. Mogą działać jak listy w Pythonie (gdy używają tylko kluczy numerycznych, zwłaszcza ciągłych od 0) oraz jak słowniki w Pythonie (gdy używają kluczy stringowych - tablice asocjacyjne). PHP nie ma oddzielnych typów dla list i słowników; wszystko to jest obsługiwane przez jeden typ array.