Szybki quiz – przypomnienie poprzedniej lekcji
1. Co zostanie wyświetlone?
$tekst = "ąć";
echo strlen($tekst) . " / " . mb_strlen($tekst);
2. Dlaczego ten kod nic nie wyświetla, chociaż tekst zawiera „PHP”? Popraw warunek.
if (strpos("PHP jest super", "PHP")) {
echo "Znaleziono!";
}
3. Co zwróci wyczyscTytul(" Ala ma kota ")?
function wyczyscTytul(string $tytul): string
{
$tytul = trim($tytul);
$tytul = preg_replace('/\s+/', ' ', $tytul);
return $tytul;
}
4. Funkcja walidujLogin() używa wzorca /^[a-zA-Z0-9_-]{3,20}$/. Dla których loginów zwróci true?
Ka, Kama_2026, Kama 2026, Kama-2026, Kama!!!
5. Usuwamy z wzorca kotwice: /[a-zA-Z0-9_-]{3,20}/. Co teraz zwróci walidujLogin("!!!Kama_2026!!!") i dlaczego?
6. Co zwróci skrocOpis("Powtórzyć funkcje", 9)?
function skrocOpis(string $opis, int $limit = 50): string
{
if (mb_strlen($opis) <= $limit) {
return $opis;
}
return mb_substr($opis, 0, $limit) . "...";
}
7. $tytulZadania = "Nauka php"; Który warunek jest spełniony?
A. strpos($tytulZadania, 'PHP') !== false
B. stripos($tytulZadania, 'PHP') !== false
8. Dlaczego w walidujLogin() piszemy preg_match(...) === 1, a nie samo preg_match(...)?
Odpowiedzi
4 / 2–strlen()liczy bajty (polska litera w UTF-8 to 2 bajty),mb_strlen()liczy znaki.- „PHP” jest na pozycji
0, a0w warunkuifjest traktowane jakfalse. Poprawnie:if (strpos("PHP jest super", "PHP") !== false). "Ala ma kota"–trim()usuwa spacje z brzegów,preg_replace('/\s+/', ' ', ...)zamienia ciągi białych znaków na jedną spację.Kama_2026iKama-2026.Ka– za krótki,Kama 2026– spacja,Kama!!!– niedozwolone znaki.true– bez^i$wystarczy, że gdzieś w środku tekstu jest pasujący fragment (Kama_2026). Kotwice wymuszają, by wzorzec pasował do całego tekstu."Powtórzyć..."– tekst ma 17 znaków, więc zostaje pierwsze 9 znaków i....- B –
stripos()nie rozróżnia wielkości liter,strpos()tak. preg_match()zwraca liczbę (1– dopasowano,0– nie) albofalseprzy błędzie, a funkcja ma zwracaćbool. Porównanie=== 1daje dokładnietruelubfalse.
Pełną listę funkcji znajdziecie w dokumentacji PHP, poniżej najczęściej wykorzystywane.
Tablica (ang. array) to uporządkowany zbiór danych przechowywany w jednej zmiennej. Każdy element tablicy ma swój indeks (klucz) i wartość.
Zastosowania:
– Przechowywanie list danych (produkty, użytkownicy, etc.)
– Gromadzenie wyników z bazy danych
– Konfiguracja aplikacji
– Przesyłanie danych między funkcjami
Typy indeksów:
– Numeryczne (0, 1, 2, …) – tablice indeksowane
– Tekstowe (ciągi znaków) – tablice asocjacyjne
Sposób 1:
Inicjowanie tablicy za pomocą nawiasów kwadratowych [].
// Pusta tablica
$tablica = [];
// Tablica z wartościami
$owoce = ['jabłko', 'banan', 'gruszka'];
// Tablica asocjacyjna
$osoba = [
'imie' => 'Jan',
'nazwisko' => 'Kowalski',
'wiek' => 30
];
// Dodawanie elementów
$owoce[] = 'pomarańcza'; // doda na końcu
$owoce[10] = 'kiwi'; // doda pod indeksem 10
W powyższym przykładzie wskazujemy konkretny nr indeksu w jaki ma zostać wpisana wartość np. $owoce[10] = 'kiwi’;. Odczytujemy ten zapis jako: w tablicy o nazwie „owoce” wstaw do indexu „10” wartość „kiwi”.
Podawanie indeksów nie jest konieczne:
$tablica[0] = "Wpis numer 0";
$tablica[] = "Wpis numer 1";
$tablica[] = "Wpis numer 2";
echo '<pre>';
print_r($tablica);
echo '</pre>';
/*
Wyświetli:
Array (
[0] => Wpis numer 0
[1] => Wpis numer 1
[2] => Wpis numer 2
)
*/
Nie wskazanie podczas inicjowania tablicy konkretnych indexów danych uruchamia proces autonumerowania od ostatniej najwyższej wartości.
Sposób 2:
Inicjowanie tablicy za pomocą konstrukcji array(). Zalecenie: Używaj składni [] – krótsza i nowocześniejsza
// Pusta tablica
$tablica = array();
// Tablica z wartościami
$owoce = array('jabłko', 'banan', 'gruszka');
// Tablica asocjacyjna
$osoba = array(
'imie' => 'Jan',
'nazwisko' => 'Kowalski',
'wiek' => 30
);
Możemy wskazywać konkretne indeksy, w których chcemy wstawić wartości. Wykonujemy to za pomocą wskazania „index => wartość”.
Trochę więcej o array() niżej.
Elementem tablicy może być każdy typ zmiennej (z innymi tablicami i obiektami włącznie).
Tablica dwuwymiarowa, zawiera dwa indeksy, np. $tablica[0][2] = 1; O nich troszkę niżej.
Sposób 3:
Przypisywanie indeksowe
$tablica[0] = "Element 0";
$tablica[1] = "Element 1";
$tablica[2] = "Element 2";
// Bez podawania indeksu - auto-numeracja
$tablica[] = "Element 3"; // indeks 3
$tablica[] = "Element 4"; // indeks 4
Indexy zewnetrzne
Typy tablic
Tablica indeksowana (numeryczna)
Indeksy to liczby całkowite (domyślnie od 0).
$kolory = ['czerwony', 'zielony', 'niebieski'];
echo $kolory[0]; // czerwony
echo $kolory[1]; // zielony
echo $kolory[2]; // niebieski
// Pętla for
for ($i = 0; $i < count($kolory); $i++) {
echo $kolory[$i] . "\n";
}
Tablica asocjacyjna
W PHP występuje też inny rodzaj tablic, tak zwane tablice asocjacyjne. Są to tablice, w których zamiast indeksów liczbowych używa się identyfikatorów znakowych (kluczy), a po polsku – nadajemy indeksom nazwy słowne, tak jak w nagłówkach zwykłej tabeli:
$osoba = [
'imie' => 'Jan',
'nazwisko' => 'Kowalski',
'wiek' => 30,
'miasto' => 'Warszawa'
];
echo $osoba['imie']; // Jan
echo $osoba['nazwisko']; // Kowalski
// Pętla foreach
foreach ($osoba as $klucz => $wartosc) {
echo "$klucz: $wartosc\n";
}
Tablica wielowymiarowa
Tablica zawierająca inne tablice jako elementy.
// Dwuwymiarowa
$uczniowie = [
['Jan', 'Kowalski', 15],
['Anna', 'Nowak', 16],
['Piotr', 'Wiśniewski', 15]
];
echo $uczniowie[0][0]; // Jan
echo $uczniowie[1][1]; // Nowak
// Wielowymiarowa asocjacyjna
$produkty = [
'elektronika' => [
'laptop' => 3000,
'telefon' => 1500,
'tablet' => 800
],
'odzież' => [
'koszula' => 100,
'spodnie' => 150
]
];
echo $produkty['elektronika']['laptop']; // 3000
Podglądanie zawartości tabel
Aby w całości wyświetlić tablicę (podejrzeć jej zawartość) – wykorzystujemy funkcje:
print_r ($zmienna_tablicowa);
lub
var_dump($zmienna_tablicowa);
print_r()
wyświetla tablice w sposób jasny i przejrzysty dla programisty, pokazując nazwy indeksów:
<pre> <?php
$a=array(
'a' => 'jabłko',
'b' => 'banan',
'c' => array ('x', 'y', 'z')
);
print_r($a);
?> </pre> /*zostanie wyświetlone: Array ( [a] => jabłko [b] => banan [c] => Array ( [0] => x [1] => y [2] => z ) ) */
Operacje na tablicach
Sprawdzanie typu – is_array()
$zmienna = ['a', 'b', 'c'];
if (is_array($zmienna)) {
echo "To jest tablica";
} else {
echo "To nie jest tablica";
}
// Krótka forma
echo is_array($zmienna) ? 'tablica' : 'nie tablica';
Liczba elementów – count() / sizeof()
$owoce = ['jabłko', 'banan', 'gruszka', 'pomarańcza'];
echo count($owoce); // 4
echo sizeof($owoce); // 4 (alias count)
// Tablica wielowymiarowa
$multi = [
[1, 2, 3],
[4, 5, 6]
];
echo count($multi); // 2 (tylko pierwsze poziom)
echo count($multi, COUNT_RECURSIVE); // 8 (wszystkie elementy)
Dodawanie elementów
$owoce = ['jabłko', 'banan'];
// Na końcu
$owoce[] = 'gruszka';
array_push($owoce, 'pomarańcza', 'kiwi');
// Na początku
array_unshift($owoce, 'truskawka');
print_r($owoce);
// ['truskawka', 'jabłko', 'banan', 'gruszka', 'pomarańcza', 'kiwi']
$array[] = $value jest szybsze niż array_push().
Usuwanie elementów
$owoce = ['jabłko', 'banan', 'gruszka', 'pomarańcza'];
// Z końca
$ostatni = array_pop($owoce);
echo $ostatni; // pomarańcza
// Z początku
$pierwszy = array_shift($owoce);
echo $pierwszy; // jabłko
// Konkretny indeks
unset($owoce[1]); // usuń 'banan'
// Wszystkie elementy
unset($owoce);
$owoce = []; // lub tak
Łączenie tablic
$tablica1 = ['a', 'b', 'c'];
$tablica2 = ['d', 'e', 'f'];
// array_merge() - łączy tablice
$polaczona = array_merge($tablica1, $tablica2);
print_r($polaczona);
// ['a', 'b', 'c', 'd', 'e', 'f']
// Operator + (zachowuje klucze)
$tab1 = [0 => 'a', 1 => 'b'];
$tab2 = [0 => 'c', 2 => 'd'];
$wynik = $tab1 + $tab2;
print_r($wynik);
// [0 => 'a', 1 => 'b', 2 => 'd'] // klucz 0 z $tab2 został pominięty
// Spread operator (PHP 7.4+)
$polaczona = [...$tablica1, ...$tablica2];
Wyszukiwanie w tablicy
PHP
$owoce = ['jabłko', 'banan', 'gruszka'];
// in_array() - sprawdza czy wartość istnieje
if (in_array('banan', $owoce)) {
echo "Jest banan!";
}
// array_search() - zwraca klucz (indeks)
$indeks = array_search('gruszka', $owoce);
echo $indeks; // 2
// array_key_exists() - sprawdza czy klucz istnieje
$osoba = ['imie' => 'Jan', 'wiek' => 30];
if (array_key_exists('imie', $osoba)) {
echo "Klucz 'imie' istnieje";
}
// isset() - szybsza alternatywa
if (isset($osoba['imie'])) {
echo "Klucz 'imie' istnieje";
Wyciąganie kluczy i wartości
$osoba = [
'imie' => 'Jan',
'nazwisko' => 'Kowalski',
'wiek' => 30
];
// Wszystkie klucze
$klucze = array_keys($osoba);
print_r($klucze);
// ['imie', 'nazwisko', 'wiek']
// Wszystkie wartości
$wartosci = array_values($osoba);
print_r($wartosci);
// ['Jan', 'Kowalski', 30]
// Odwrócenie kluczy z wartościami
$odwrocona = array_flip($osoba);
print_r($odwrocona);
// ['Jan' => 'imie', 'Kowalski' => 'nazwisko', 30 => 'wiek']
Przeglądanie tablic
Pętla for (dla tablic indeksowanych)
$liczby = [10, 20, 30, 40, 50];
for ($i = 0; $i < count($liczby); $i++) {
echo $liczby[$i] . "\n";
}
// Lepiej - zachowaj count w zmiennej
$dlugosc = count($liczby);
for ($i = 0; $i < $dlugosc; $i++) {
echo $liczby[$i] . "\n";
}
Pętla foreach (uniwersalna, zalecana)
// Tylko wartości
$owoce = ['jabłko', 'banan', 'gruszka'];
foreach ($owoce as $owoc) {
echo $owoc . "\n";
}
// Klucze i wartości
$osoba = ['imie' => 'Jan', 'wiek' => 30];
foreach ($osoba as $klucz => $wartosc) {
echo "$klucz: $wartosc\n";
}
// 🆕 Modyfikacja przez referencję
$liczby = [1, 2, 3, 4, 5];
foreach ($liczby as &$liczba) {
$liczba *= 2;
}
unset($liczba); // WAŻNE: zawsze unset po pętli z referencją!
print_r($liczby);
// [2, 4, 6, 8, 10]
Funkcja list() – destrukturyzacja
// Podstawowe użycie
$info = ['kawa', 'brązowa', 'kofeina'];
list($napoj, $kolor, $skladnik) = $info;
echo "$napoj jest $kolor a $skladnik czyni ją wyjątkową";
// kawa jest brązowa a kofeina czyni ją wyjątkową
// Pomijanie elementów
list($napoj, , $skladnik) = $info;
echo "$napoj zawiera $skladnik";
// kawa zawiera kofeina
// Krótka składnia (PHP 7.1+)
[$napoj, $kolor, $skladnik] = $info;
// Z kluczami asocjacyjnymi (PHP 7.1+)
$osoba = ['imie' => 'Jan', 'wiek' => 30, 'miasto' => 'Warszawa'];
['imie' => $imie, 'wiek' => $wiek] = $osoba;
echo "$imie ma $wiek lat";
reset() – ustawianie wskaźnika
$tablica = ['a', 'b', 'c'];
// Przesuń wskaźnik
next($tablica);
next($tablica);
echo current($tablica); // c
// Zresetuj na początek
reset($tablica);
echo current($tablica); // a
W nowoczesnym PHP rzadko używane – preferuj foreach.
Sortowanie tablic
sort() / rsort() – sortowanie wartości (indeksowane)
$liczby = [5, 2, 8, 1, 9];
// Rosnąco
sort($liczby);
print_r($liczby); // [1, 2, 5, 8, 9]
// Malejąco
rsort($liczby);
print_r($liczby); // [9, 8, 5, 2, 1]
// ⚠️ Uwaga: indeksy są resetowane!
$owoce = [2 => 'banan', 0 => 'jabłko', 1 => 'gruszka'];
sort($owoce);
print_r($owoce);
// [0 => 'banan', 1 => 'gruszka', 2 => 'jabłko']
asort() / arsort() – sortowanie wartości (asocjacyjne)
Zachowuje przypisanie kluczy do wartości.
$owoce = [
'd' => 'mango',
'a' => 'papaja',
'b' => 'banan',
'c' => 'aronia'
];
// Rosnąco
asort($owoce);
print_r($owoce);
// ['c' => 'aronia', 'b' => 'banan', 'd' => 'mango', 'a' => 'papaja']
// Malejąco
arsort($owoce);
print_r($owoce);
// ['a' => 'papaja', 'd' => 'mango', 'b' => 'banan', 'c' => 'aronia']
ksort() / krsort() – sortowanie kluczy
$owoce = [
'd' => 'mango',
'a' => 'papaja',
'b' => 'banan',
'c' => 'aronia'
];
// Rosnąco po kluczach
ksort($owoce);
print_r($owoce);
// ['a' => 'papaja', 'b' => 'banan', 'c' => 'aronia', 'd' => 'mango']
// Malejąco po kluczach
krsort($owoce);
print_r($owoce);
// ['d' => 'mango', 'c' => 'aronia', 'b' => 'banan', 'a' => 'papaja']
usort() / uasort() / uksort() – sortowanie własną funkcją
$osoby = [
['imie' => 'Jan', 'wiek' => 30],
['imie' => 'Anna', 'wiek' => 25],
['imie' => 'Piotr', 'wiek' => 35]
];
// usort() - sortowanie wartości
usort($osoby, function($a, $b) {
return $a['wiek'] <=> $b['wiek']; // sortuj po wieku
});
print_r($osoby);
// [['imie' => 'Anna', 'wiek' => 25], ['imie' => 'Jan', 'wiek' => 30], ...]
// Arrow function (PHP 7.4+)
usort($osoby, fn($a, $b) => $a['wiek'] <=> $b['wiek']);
// uasort() - zachowuje klucze
$oceny = ['Jan' => 4, 'Anna' => 5, 'Piotr' => 3];
uasort($oceny, fn($a, $b) => $b <=> $a); // malejąco
print_r($oceny);
// ['Anna' => 5, 'Jan' => 4, 'Piotr' => 3]
Tabela funkcji sortujących
| Funkcja | Sortuje po | Zachowuje klucze | Kierunek |
|---|---|---|---|
sort() | Wartościach | ✗ | Rosnąco |
rsort() | Wartościach | ✗ | Malejąco |
asort() | Wartościach | ✓ | Rosnąco |
arsort() | Wartościach | ✓ | Malejąco |
ksort() | Kluczach | ✓ | Rosnąco |
krsort() | Kluczach | ✓ | Malejąco |
usort() | Wartościach (custom) | ✗ | Custom |
uasort() | Wartościach (custom) | ✓ | Custom |
uksort() | Kluczach (custom) | ✓ | Custom |
Funkcje tablicowe
explode() / implode() – string ↔ array
// explode() - dzieli string na tablicę
$tekst = "alfa;beta;gamma;delta";
$tablica = explode(";", $tekst);
print_r($tablica);
// ['alfa', 'beta', 'gamma', 'delta']
// Z limitem
$tablica = explode(";", $tekst, 2);
print_r($tablica);
// ['alfa', 'beta;gamma;delta']
// implode() / join() - łączy tablicę w string
$tekst = implode(";", $tablica);
echo $tekst; // alfa;beta;gamma;delta
str_split() – dzieli string na znaki
$str = "Hello";
// Na pojedyncze znaki
$znaki = str_split($str);
print_r($znaki);
// ['H', 'e', 'l', 'l', 'o']
// Na fragmenty długości 2
$fragmenty = str_split($str, 2);
print_r($fragmenty);
// ['He', 'll', 'o']
array_slice() – wycina fragment tablicy
$owoce = ['jabłko', 'banan', 'gruszka', 'pomarańcza', 'kiwi'];
// Od indeksu 1, 3 elementy
$fragment = array_slice($owoce, 1, 3);
print_r($fragment);
// ['banan', 'gruszka', 'pomarańcza']
// Od końca
$ostatnie = array_slice($owoce, -2);
print_r($ostatnie);
// ['pomarańcza', 'kiwi']
// Zachowaj klucze
$fragment = array_slice($owoce, 1, 3, true);
array_splice() – usuwa/zastępuje fragment
$owoce = ['jabłko', 'banan', 'gruszka', 'pomarańcza'];
// Usuń 2 elementy od indeksu 1
$usuniete = array_splice($owoce, 1, 2);
print_r($owoce); // ['jabłko', 'pomarańcza']
print_r($usuniete); // ['banan', 'gruszka']
// Zastąp
$owoce = ['jabłko', 'banan', 'gruszka'];
array_splice($owoce, 1, 1, ['kiwi', 'mango']);
print_r($owoce);
// ['jabłko', 'kiwi', 'mango', 'gruszka']
// Wstaw bez usuwania
array_splice($owoce, 2, 0, ['truskawka']);
array_unique() – usuwa duplikaty
$liczby = [1, 2, 2, 3, 4, 4, 5];
$unikalne = array_unique($liczby);
print_r($unikalne);
// [0 => 1, 1 => 2, 3 => 3, 4 => 4, 6 => 5]
// Zresetuj indeksy
$unikalne = array_values(array_unique($liczby));
print_r($unikalne);
// [1, 2, 3, 4, 5]
array_reverse() – odwraca tablicę
$owoce = ['jabłko', 'banan', 'gruszka'];
$odwrocone = array_reverse($owoce);
print_r($odwrocone);
// ['gruszka', 'banan', 'jabłko']
// Zachowaj klucze
$odwrocone = array_reverse($owoce, true);
array_sum() / array_product()
$liczby = [1, 2, 3, 4, 5];
// Suma
echo array_sum($liczby); // 15
// Iloczyn
echo array_product($liczby); // 120
array_rand() – losowy element
$owoce = ['jabłko', 'banan', 'gruszka', 'pomarańcza'];
// Jeden losowy klucz
$klucz = array_rand($owoce);
echo $owoce[$klucz];
// Trzy losowe klucze
$klucze = array_rand($owoce, 3);
foreach ($klucze as $k) {
echo $owoce[$k] . "\n";
}
array_chunk() – dzieli tablicę na mniejsze
$liczby = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
$chunki = array_chunk($liczby, 3);
print_r($chunki);
// [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]
// Zachowaj klucze
$chunki = array_chunk($liczby, 3, true);
array_map() – transformacja elementów
$liczby = [1, 2, 3, 4, 5];
// Podwój każdą liczbę
$podwojone = array_map(function($x) {
return $x * 2;
}, $liczby);
print_r($podwojone);
// [2, 4, 6, 8, 10]
// Arrow function (PHP 7.4+)
$podwojone = array_map(fn($x) => $x * 2, $liczby);
// Wiele tablic
$imiona = ['Jan', 'Anna'];
$nazwiska = ['Kowalski', 'Nowak'];
$pelne = array_map(function($imie, $nazwisko) {
return "$imie $nazwisko";
}, $imiona, $nazwiska);
print_r($pelne);
// ['Jan Kowalski', 'Anna Nowak']
// Spread + array_map (PHP 7.4+)
$kwadraty = array_map(fn($x) => $x ** 2, range(1, 10));
array_filter() – filtrowanie elementów
$liczby = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// Tylko parzyste
$parzyste = array_filter($liczby, function($x) {
return $x % 2 == 0;
});
print_r($parzyste);
// [1 => 2, 3 => 4, 5 => 6, 7 => 8, 9 => 10]
// Arrow function
$parzyste = array_filter($liczby, fn($x) => $x % 2 == 0);
// Filtruj z kluczami
$osoby = ['Jan' => 25, 'Anna' => 17, 'Piotr' => 30];
$pelnoletni = array_filter($osoby, fn($wiek) => $wiek >= 18);
print_r($pelnoletni);
// ['Jan' => 25, 'Piotr' => 30]
// ARRAY_FILTER_USE_KEY - filtruj po kluczach
$filtered = array_filter($osoby, fn($klucz) => strlen($klucz) > 3, ARRAY_FILTER_USE_KEY);
array_reduce() – redukuje do pojedynczej wartości
$liczby = [1, 2, 3, 4, 5];
// Suma
$suma = array_reduce($liczby, function($carry, $item) {
return $carry + $item;
}, 0);
echo $suma; // 15
// Arrow function
$suma = array_reduce($liczby, fn($carry, $item) => $carry + $item, 0);
// Iloczyn
$iloczyn = array_reduce($liczby, fn($c, $i) => $c * $i, 1);
echo $iloczyn; // 120
// Konkatenacja
$slowa = ['Hello', 'World', 'PHP'];
$zdanie = array_reduce($slowa, fn($c, $i) => $c . ' ' . $i, '');
echo trim($zdanie); // Hello World PHP
array_walk() – modyfikacja w miejscu
$liczby = [1, 2, 3, 4, 5];
// Podwój każdy element
array_walk($liczby, function(&$wartosc, $klucz) {
$wartosc *= 2;
});
print_r($liczby);
// [2, 4, 6, 8, 10]
// Z dodatkowym parametrem
array_walk($liczby, function(&$v, $k, $mnoznik) {
$v *= $mnoznik;
}, 3);
array_column() – wyciąga kolumnę z wielowymiarowej
$osoby = [
['id' => 1, 'imie' => 'Jan', 'wiek' => 30],
['id' => 2, 'imie' => 'Anna', 'wiek' => 25],
['id' => 3, 'imie' => 'Piotr', 'wiek' => 35]
];
// Wyciągnij wszystkie imiona
$imiona = array_column($osoby, 'imie');
print_r($imiona);
// ['Jan', 'Anna', 'Piotr']
// Z kluczem
$iminaPoId = array_column($osoby, 'imie', 'id');
print_r($iminaPoId);
// [1 => 'Jan', 2 => 'Anna', 3 => 'Piotr']
Spread operator (PHP 7.4+)
$tab1 = [1, 2, 3];
$tab2 = [4, 5, 6];
// Łączenie
$polaczona = [...$tab1, ...$tab2];
print_r($polaczona);
// [1, 2, 3, 4, 5, 6]
// W argumentach funkcji
function suma(...$liczby) {
return array_sum($liczby);
}
echo suma(1, 2, 3, 4, 5); // 15
echo suma(...[10, 20, 30]); // 60
// W array_merge
$wynik = [...$tab1, 'x', 'y', ...$tab2];
// [1, 2, 3, 'x', 'y', 4, 5, 6]
Null coalescing dla tablic (PHP 7.0+)
$config = ['db' => 'mysql', 'port' => 3306];
// Stary sposób
$host = isset($config['host']) ? $config['host'] : 'localhost';
// Null coalescing
$host = $config['host'] ?? 'localhost';
// Łańcuchowe (PHP 7.4+)
$wartość = $config['a'] ?? $config['b'] ?? $config['c'] ?? 'domyślna';
Tablice superglobalne
Tablice superglobalne w PHP to automatycznie dostępne, globalne tablice zawierające dane zebrane od serwera, użytkownika lub z sesji, co oznacza, że można ich używać w dowolnym miejscu skryptu bez potrzeby ich deklarowania.
$_GET
Przechowuje dane przekazane do skryptu za pomocą metody GET (np. parametry w adresie URL).
// URL: http://example.com/page.php?name=Jan&age=30
echo $_GET['name']; // Jan
echo $_GET['age']; // 30
// Bezpieczne pobieranie
$name = $_GET['name'] ?? 'Gość';
$age = filter_input(INPUT_GET, 'age', FILTER_VALIDATE_INT) ?? 0;
$_POST
Zawiera dane wprowadzone przez użytkownika w formularzach przesłanych metodą POST.
// Formularz wysłany metodą POST
$username = $_POST['username'] ?? '';
$password = $_POST['password'] ?? '';
// ⚠️ Walidacja!
$username = htmlspecialchars($username, ENT_QUOTES, 'UTF-8');
$_SERVER
Dostarcza informacji o serwerze i środowisku, w tym dane o połączeniu, adresie IP czy nagłówkach HTTP.
// Najczęściej używane:
echo $_SERVER['HTTP_HOST']; // example.com
echo $_SERVER['REQUEST_URI']; // /page.php?id=1
echo $_SERVER['REQUEST_METHOD']; // GET, POST, etc.
echo $_SERVER['REMOTE_ADDR']; // IP klienta
echo $_SERVER['HTTP_USER_AGENT']; // przeglądarka
echo $_SERVER['SCRIPT_NAME']; // /path/script.php
echo $_SERVER['DOCUMENT_ROOT']; // ścieżka root serwera
// Pełna lista
echo '<pre>';
print_r($_SERVER);
echo '</pre>';
$_FILES
Używana do przetwarzania plików przesłanych do skryptu metodą POST.
// Formularz z <input type="file" name="plik">
if (isset($_FILES['plik'])) {
$file = $_FILES['plik'];
echo $file['name']; // nazwa pliku
echo $file['type']; // typ MIME
echo $file['size']; // rozmiar w bajtach
echo $file['tmp_name']; // tymczasowa lokalizacja
echo $file['error']; // kod błędu (0 = OK)
// Przeniesienie pliku
if ($file['error'] === 0) {
move_uploaded_file($file['tmp_name'], 'uploads/' . $file['name']);
}
}
$_COOKIE
Zawiera ciasteczka (cookies) wysłane przez serwer WWW, które są dostępne w przeglądarce użytkownika.
// Ustawianie cookie
setcookie('username', 'Jan', time() + 3600); // 1 godzina
// Odczytywanie
$username = $_COOKIE['username'] ?? 'Gość';
$_SESSION
Przechowuje dane użytkownika między różnymi stronami lub żądaniami (dane sesji).
// Rozpocznij sesję
session_start();
// Zapisz dane
$_SESSION['user_id'] = 123;
$_SESSION['username'] = 'Jan';
// Odczytaj dane
$userId = $_SESSION['user_id'] ?? null;
// Usuń zmienną
unset($_SESSION['username']);
// Zniszcz całą sesję
session_destroy();
$_ENV
Zawiera zmienne środowiskowe dostępne dla skryptu PHP.
$_REQUEST – $_GET + $_POST + $_COOKIE
Jest to tablica, która zawiera dane zebrane jednocześnie z $_GET, $_POST i $_COOKIE
// Nie zalecane - lepiej używać konkretnych tablic
$id = $_REQUEST['id'] ?? 0;
// Lepiej:
$id = $_GET['id'] ?? $_POST['id'] ?? 0;
$GLOBALS
(ta jedna nie ma podłogi w nazwie) Tablica zawierająca odniesienia do wszystkich zmiennych o zasięgu globalnym w danym skrypcie.
$x = 10;
$y = 20;
function suma() {
return $GLOBALS['x'] + $GLOBALS['y'];
}
echo suma(); // 30
// Nie zalecane - lepiej przekazywać jako argumenty
Jeżeli chcemy zobaczyć co dana tablica zawiera, wystarczy że wykonamy poniższy kod
echo "<pre>";
print_r($_SERVER); //tutaj wpisujemy nazwę tablicy
echo "</pre>";
Zadania:
1. Utworzyć dowolną tablicę asocjacyjną, posortować ją rosnąco i malejąco według wartości i wyświetlić elementy kolejno na ekranie.
2. Napisz skrypt obliczający sumę elementów w tablicy.
3. Utworzyć tablicę zawierającą kąty i kolejne wartości funkcji sin(x) w zakresie od 0 do 900 z krokiem 50 wyświetlić jej zawartość na ekranie: w 2 kolumnach (kąt – wartość).
4. Wypełnij tablicę 1000 losowych liczb z zakresu od 1 do 10000. Wyznacz:
a) ile jest w tablicy liczb parzystych
b) ile jest w tablicy liczb nieparzystych
c) najmniejszą i największą liczbę w tablicy
d) średnią arytmetyczną wszystkich liczb z tablicy
5. (dla klas, które miały HTMLa) Napisz skrypt, który za pomocą formularza przekaże dane osobowe do tablicy (imię, nazwisko, klasa, grupa) i wyświetli je na ekranie.
5. (dla klas, które nie miały HTMLa) Napisz skrypt, który rozdzieli po spacji podany ciąg (imię, nazwisko, klasa, grupa) dodając wydzielone elementy do tablicy i wyświetli ją na ekranie.
6. Napisz skrypt, który stworzy tablicę wielowymiarową zawierająca następujące dane: nazwy kontynentów (min 3) -> państwa mieszczące się na danym kontynencie (min 3) -> miasta w danym państwie (min 3). Posortuj tablicę rosnąco wg klucza: kontynent, państwo, miasto.
7. Utwórz tablicę czteroelementową zawierającą następujące wartości: “Fioletowy”, “Niebieski”, “Różowy”, “Zielony”. Następnie użyj jej do wyświetlenia listy:
- Fioletowy
- Niebieskie
- Różowy
- Zielony
8. Zsumuj wszystkie elementy z tablicy: $wartosci = [1, 15, 12, 51, 08, -11]. Wykorzystaj pętle for
9. Oblicz temperaturę średnią. Posłuż się tablicą $wartosci przechowującą odczytane temperatury:
$wartosci = [20, 17, 22, 20, 16, 31, 22, 15, 13, -12, 16, 7, 1, 0, -7, -10];
10. Wyświetl wszystkie elementy tablicy: $auta = [„VW”, „Audi”, „BMW”, „Mercedes”]. Użyj pętli foreach.
11. Napisz skrypt odnajdujący największy element tablicy:
$liczby = [10, 15, 9, 61, 78, 2, 44, 21, 30];
12. Napisz skrypt, który wyświetla nazwę kraju i jego stolicę . Posłuż się tablicą $europa:
$europa = array(„Włochy” => „Rzym”, „Belgia” => „Bruksela”,
„Dania” => „Kopenhaga”, „Finlandia” => „Helsinki”,
„Francja => „Paryż”, „Niemcy” => „Berlin”,
„Rosja” => „Moskwa”, „Polska” => „Warszawa”);
// tu umieść kod wyświetlający informacje wg schematu:
// Kraj: Włochy, stolica: Rzym
// …
// Kraj: Polska, stolica: Warszawa
13. Napisać funkcję o nazwie ListaLiczb (o 3 parametrach: $zakres1, $zakres2, $ilosc) wczytujący do utworzonej wewnątrz funkcji tablicy $tab losowe liczby całkowite z zakresu od $zakres1 do
$zakres2 w ilości $ilosc.
Należy przy tym najpierw sprawdzić, czy $zakres1 jest mniejsze lub równe $zakres2 – jeśli nie, to należy zamienić między sobą obie liczby.
Dodatkowo, jeśli $ilosc nie jest większa od zera, to wyświetlić komunikat o błędzie („Ilość elementów w tablicy musi być większa od 0.”) i przerwać działanie funkcji.
Ostatecznie funkcja wyświetla liczby z tablicy w postaci listy nienumerowanej.
Ściągawka funkcji tablicowych
| Kategoria | Funkcje |
|---|---|
| Tworzenie | [], array(), range(), array_fill() |
| Dodawanie | [], array_push(), array_unshift() |
| Usuwanie | array_pop(), array_shift(), unset() |
| Wyszukiwanie | in_array(), array_search(), array_key_exists() |
| Sortowanie | sort(), rsort(), asort(), arsort(), ksort(), krsort() |
| Transformacja | array_map(), array_filter(), array_reduce() |
| Łączenie | array_merge(), +, … (spread) |
| Dzielenie | array_slice(), array_chunk() |
| Informacje | count(), sizeof(), empty(), isset() |
| String ↔ Array | explode(), implode(), str_split() |
Dobre praktyki
1. Preferuj [] nad array()
// ŹLE - stara składnia
$tab = array(1, 2, 3);
// DOBRZE - nowoczesna składnia
$tab = [1, 2, 3];
2. Używaj array_map/filter zamiast pętli
// ŹLE - niepotrzebna pętla
$podwojone = [];
foreach ($liczby as $liczba) {
$podwojone[] = $liczba * 2;
}
// DOBRZE - array_map
$podwojone = array_map(fn($x) => $x * 2, $liczby);
3. Unset referencji po foreach
foreach ($tablica as &$wartosc) {
$wartosc *= 2;
}
unset($wartosc); // ZAWSZE!
4. Waliduj dane z superglobalnych
// ŹLE
$id = $_GET['id'];
// DOBRZE
$id = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT) ?? 0;
5. Używaj spread operator dla łączenia
// ŹLE - wolniejsze
$polaczona = array_merge($tab1, $tab2, $tab3);
// DOBRZE - szybsze (PHP 7.4+)
$polaczona = [...$tab1, ...$tab2, ...$tab3];
TaskQuest 9 — powstaje prawdziwa lista zadań
KARTA PRACY
Do tej pory TaskQuest znał jedno zadanie, zapisane w kilku osobnych zmiennych:
$tytulZadania
$opisZadania
$terminZadania
$zadanieWykonane
Prawdziwa aplikacja do zarządzania zadaniami musi jednak pokazać ich dziesiątki. Nie możemy przecież tworzyć $tytulZadania1, $tytulZadania2, $tytulZadania3…
Cel lekcji
Nauczyć TaskQuest:
- przechowywać wiele zadań w jednej zmiennej (tablica tablic asocjacyjnych),
- wyświetlać całą listę zadań jedną pętlą
foreach, - liczyć zadania i sumować XP,
- wybierać zadania wykonane i aktywne (
array_filter()), - sortować zadania według terminu (
usort()), - sprawdzać, czy aktywne zadania wystarczą na awans na kolejny poziom.
Wszystkie funkcje z Lekcji 7 i 8 (komunikatTerminu(), aktualizujStreak(), wyczyscTytul(), skrocOpis(), walidujLogin()) zostają i zaczną pracować na elementach listy.
Uwaga: to pierwsza lekcja, w której świadomie używamy tablic. Dane nadal są zapisane „na sztywno” w kodzie (nie ma jeszcze formularzy, plików ani bazy danych), więc lista zadań jest na tym etapie symulowana. Przygotowujemy logikę, którą w kolejnych lekcjach podłączymy do prawdziwych źródeł danych.
Porządki na start — trzy poprawki w kodzie z Lekcji 8
Zanim dołożymy nowy temat, poprawiamy trzy drobiazgi z Lekcji 8. Zrób to teraz, w swoim pliku TaskQuest.
Poprawka 1: $login zamiast $loginUzytkownika
CO JEST PROBLEMEM?
W materiale z Lekcji 8 login raz nazywał się $login, a raz $loginUzytkownika.
↓
DLACZEGO TO PROBLEM?
To ta sama informacja pod dwiema nazwami. Kod z jedną z nich może przestać działać
(np. "Undefined variable"), a w kolejnych lekcjach (tablice, baza danych) nazwy
zaczną się mnożyć.
↓
CO ZMIENIAMY?
Zostaje wyłącznie $login — do końca kursu. Ta sama nazwa będzie kluczem 'login'
w tablicach i nazwą kolumny w bazie danych.
↓
DLACZEGO TAK?
Jedna informacja = jedna nazwa. $imieUzytkownika (imię) i $login (login)
to natomiast dwie RÓŻNE informacje — obie zostają.
↓
JAK WYGLĄDA NOWY KOD?
$login = "Kama_2026";
if (walidujLogin($login)) {
echo "<p>Login poprawny: $login</p>";
}
Sprawdź w całym pliku, czy nigdzie nie została nazwa $loginUzytkownika (użyj wyszukiwania w edytorze).
Poprawka 2: ++$poziom zamieniamy na ($poziom + 1)
CO JEST PROBLEMEM?
W nagłówku z paskiem postępu numer następnego poziomu liczyliśmy przez ++$poziom.
↓
DLACZEGO TO PROBLEM?
++$poziom TRWALE zwiększa wartość zmiennej. Od tej linii $poziom przestaje oznaczać
aktualny poziom użytkownika. Działało "przypadkiem", bo nic dalej z $poziom nie korzystało.
Od tej lekcji korzystamy z $poziom niżej (komunikat o awansie) — błąd byłby widoczny.
↓
CO ZMIENIAMY?
Numer następnego poziomu liczymy "obok": ($poziom + 1), bez zmiany $poziom.
↓
DLACZEGO TAK?
$poziom ma przez cały skrypt znaczenie "aktualny poziom".
↓
JAK WYGLĄDA NOWY KOD?
<?= "Masz $xpWAktualnymPoziomie XP z " . XP_NA_POZIOM . " XP potrzebnych do poziomu " . ($poziom + 1) . " (" . round($procentPostepu, 2) . "%)"; ?>
Poprawka 3: literówka w komunikatTerminu()
CO JEST PROBLEMEM?
Komunikat o przekroczonym terminie kończył się dziwnie: "...dni temu.!"
↓
DLACZEGO TO PROBLEM?
To zwykła literówka (dwa znaki interpunkcyjne), ale będzie widoczna przy każdym
przeterminowanym zadaniu na liście.
↓
CO ZMIENIAMY?
Tylko tekst w jednej gałęzi funkcji. Logika funkcji się nie zmienia.
↓
JAK WYGLĄDA NOWY KOD?
return "Termin minął {$roznica->days} dni temu!";
1. Wracamy do naszego TaskQuest
Mamy działającą aplikację, która potrafi:
- policzyć poziom, tytuł i postęp XP,
- sprawdzić login,
- oczyścić tytuł i skrócić opis zadania,
- powiedzieć, ile dni zostało do terminu,
- zaktualizować streak.
Zostaje
$imieUzytkownika, $login
$xp, $poziom, $tytul, $xpWAktualnymPoziomie, $procentPostepu, $brakujeXp,
$liczbaAktywnychSegmentow, $progNastepnegoPoziomu
$streak, $dataOstatniejAktywnosci
oraz wszystkie dotychczasowe funkcje.
Zmieni się
Pojedyncze zmienne zadania ($tytulZadania, $opisZadania, $terminZadania) przechodzą do jednej struktury: tablicy $zadania.
Uwaga na nazwy:
$tytul(bez „Zadania”) to nadal tytuł gracza („Nowicjusz”). Tytuł zadania będzie od teraz kluczem'tytul'wewnątrz tablicy zadania. To dwie różne rzeczy — nie pomyl ich.
2. Problem w aplikacji
Użytkownik TaskQuest chce zobaczyć:
[ ] Powtórzyć funkcje — 15 XP
[ ] Ćwiczenia z DateTime — 10 XP
[X] Nauczyć się regexów PHP — 20 XP
...
Zadań będzie raz pięć, a raz pięćdziesiąt. Kod wyświetlający listę nie może się zmieniać za każdym razem, gdy zadanie dochodzi lub znika.
Potrzebujemy:
- sposobu przechowania wielu wartości w jednej zmiennej,
- sposobu, żeby „przejść” przez wszystkie z nich.
3. Nowy mechanizm PHP: tablice
Tablica to uporządkowany zbiór wartości w jednej zmiennej. Każda wartość ma swój klucz (indeks).
Tablica indeksowana — klucze to numery od 0
$xpZaDni = [10, 25, 5];
echo $xpZaDni[0]; // 10 (numeracja zaczyna się od 0!)
echo count($xpZaDni); // 3 (ile elementów)
$xpZaDni[] = 40; // dopisuje element na końcu
Tablica asocjacyjna — klucze to nazwy
$gracz = [
'login' => 'Kama_2026',
'xp' => 99
];
echo $gracz['login']; // Kama_2026
To dokładnie to, czego potrzebujemy do opisania jednego zadania: klucz 'tytul', klucz 'termin', klucz 'xp'…
Tablica tablic — lista rekordów
$gracze = [
['login' => 'Kama_2026', 'xp' => 99],
['login' => 'Adam_12', 'xp' => 40]
];
echo $gracze[1]['login']; // Adam_12 (drugi gracz, klucz 'login')
Podglądanie zawartości: print_r()
Kiedy nie wiesz, co jest w tablicy — wypisz ją. Tag <pre> zachowuje wcięcia:
echo '<pre>';
print_r($gracze);
echo '</pre>';
Przechodzenie po tablicy: foreach
foreach ($gracze as $gracz) {
echo $gracz['login'] . " — " . $gracz['xp'] . " XP<br>";
}
W każdym obrocie pętli $gracz to kolejny element tablicy $gracze. Nie zmienia się nic w kodzie, gdy na liście jest 2 albo 200 graczy.
4. SAMODZIELNIE — jedno zadanie jako tablica
Utwórz nowy plik brudnopis.php (tam poćwiczymy, zanim ruszymy TaskQuest).
Dane zadania z Lekcji 8 zapisz w jednej tablicy asocjacyjnej $zadanie z kluczami:
id, tytul, opis, termin, wykonane, xp
Wartości:
id → 1
tytul → " Nauczyć się regexów PHP " (z zapasem spacji — zaraz się przyda)
opis → "Powtórzyć wyrażenia regularne przed następną lekcją."
termin → "2026-09-20"
wykonane → true
xp → 20
Wyświetl tytuł zadania.
HINT
Wartość przypisujesz do klucza zapisem:
'klucz' => wartość
POMOC
$zadanie = [
'id' => 1,
'tytul' => '...',
// pozostałe klucze
];
echo $zadanie['tytul'];
ROZWIĄZANIE
<?php
$zadanie = [
'id' => 1,
'tytul' => ' Nauczyć się regexów PHP ',
'opis' => 'Powtórzyć wyrażenia regularne przed następną lekcją.',
'termin' => '2026-09-20',
'wykonane' => true,
'xp' => 20
];
echo $zadanie['tytul'];
Zwróć uwagę: 'xp' to nagroda za wykonanie zadania. To nowa informacja — do tej pory zadanie nie miało wartości XP.
5. SAMODZIELNIE — lista zadań
W brudnopis.php zbuduj tablicę $zadania, w której każdy element to tablica asocjacyjna zadania (tak jak $gracze w przykładzie). Dane:
| id | tytul | opis | termin | wykonane | xp |
|---|---|---|---|---|---|
| 1 | Nauczyć się regexów PHP | Powtórzyć wyrażenia regularne przed następną lekcją. | 2026-09-20 | true | 20 |
| 2 | Powtórzyć funkcje | Przejrzeć wszystkie funkcje TaskQuest i sprawdzić ich parametry oraz typy zwracanych wartości. | 2026-09-16 | false | 15 |
| 3 | Ćwiczenia z DateTime | Napisać trzy własne przykłady z diff() i format(). | 2026-09-18 | false | 10 |
| 4 | Nauczyć się tablic PHP | Zbudować listę zadań TaskQuest jako tablicę tablic asocjacyjnych. | 2026-09-25 | false | 30 |
| 5 | Przygotować projekt do Lekcji 10 | Zastanowić się, jak podzielić TaskQuest na pliki i katalogi. | 2026-09-22 | true | 25 |
Wypisz $zadania przez print_r() w <pre> i sprawdź, czy struktura wygląda tak, jak zamierzałeś/aś.
HINT
To lista w liście: nawias [ na zewnątrz, a w środku pięć nawiasów [ ... ] oddzielonych przecinkami.
POMOC
$zadania = [
[
'id' => 1,
// ...
],
[
'id' => 2,
// ...
],
// ...
];
ROZWIĄZANIE
Pełna lista dokładnie w tej postaci jest w kodzie referencyjnym (sekcja 13).
6. Włączamy listę do TaskQuest
Teraz wracamy do pliku TaskQuest. Robimy krok po kroku, żeby nic nie zgubić.
Krok 1 — usuwamy pojedyncze zmienne zadania
Usuń z kodu z Lekcji 8:
$tytulZadania = " Nauczyć się regexów PHP ";
$tytulZadania = wyczyscTytul($tytulZadania);
$opisZadania = "Powtórzyć wyrażenia regularne przed następną lekcją.";
$terminZadania = "2026-09-20";
Dlaczego? Dane tego zadania będą teraz jednym z elementów tablicy $zadania. Gdybyśmy zostawili obie wersje, mielibyśmy tę samą informację w dwóch miejscach (a jeśli zmienisz jedną, druga się „rozjedzie”).
Funkcje wyczyscTytul() i skrocOpis() zostają bez zmian — dopiero teraz będą naprawdę potrzebne, bo tytuły i opisy przyjdą z listy.
Krok 2 — wklejamy $zadania
Pod funkcją skrocOpis() wklej tablicę $zadania z brudnopisu.
Krok 3 — wyświetlamy listę
W panelu HTML, w miejscu dawnych linii z Zadanie:, opisem, Termin:, Komunikat:, Stan: i informacją o PHP, wyświetlimy teraz całą listę zadań.
SAMODZIELNIE
Wyświetl w pętli foreach każde zadanie z listy. Dla każdego zadania pokaż:
[ ] albo [X] + tytuł (oczyszczony!) + XP
skrócony opis (max 50 znaków)
Termin: ... + komunikat o terminie (tylko dla zadań, które NIE są wykonane)
"To zadanie dotyczy PHP." (jeśli tytuł zawiera PHP)
Wykorzystaj funkcje, które już masz: wyczyscTytul(), skrocOpis(), komunikatTerminu() i stripos().
HINT
- Znacznik zadania: operator
? :(znasz go ze zmiennej$status), - Wartości z elementu odczytujesz jak z każdej tablicy asocjacyjnej:
$zadanie['termin'], - Zadanie jest „nie wykonane”, gdy
!$zadanie['wykonane'].
POMOC
foreach ($zadania as $zadanie) {
$tytulCzysty = wyczyscTytul($zadanie['tytul']);
$znacznik = $zadanie['wykonane'] ? "[X]" : "[ ]";
echo '<div class="zadanie">';
echo "<p><strong>$znacznik $tytulCzysty</strong> — {$zadanie['xp']} XP</p>";
// opis, termin, komunikat, PHP...
echo '</div>';
}
Zapis {$zadanie['xp']} w cudzysłowie działa tak samo jak {$roznica->days} w komunikatTerminu().
ROZWIĄZANIE
Blok foreach z tej sekcji znajdziesz w kodzie referencyjnym (na końcu panelu). Tam iterujemy już po posortowanej liście — do tego dojdziemy w sekcji 9.
Krok 4 — zostaw $streak i $dataOstatniejAktywnosci
Te dwie zmienne zostają bez zmian. Usuń natomiast:
$zadanieWykonane = true;
$status = $zadanieWykonane ? "Aktywny" : "Nieaktywny";
CO JEST PROBLEMEM?
$zadanieWykonane i $status opisywały stan JEDNEGO zadania.
↓
DLACZEGO TO PROBLEM?
Teraz każde zadanie ma własny klucz 'wykonane'. Osobna zmienna byłaby duplikatem,
a $status ("Aktywny" dla wykonanego zadania?) i tak mylił.
↓
CO ZMIENIAMY?
$status usuwamy — stan każdego zadania pokazuje znacznik [X] / [ ].
$zadanieWykonane zostaje, ale NIE wpisujemy go już ręcznie —
wyliczymy je z listy (sekcja 10), bo aktualizujStreak() nadal go potrzebuje.
Usuń też (na razie) wywołanie $streak = aktualizujStreak(...) — bez $zadanieWykonane PHP zgłosiłby ostrzeżenie. Wrócimy do niego w sekcji 10. Sama funkcja aktualizujStreak() zostaje w kodzie.
7. Liczymy zadania i sumujemy XP
Ile mamy zadań? Odpowiada count():
$liczbaWszystkich = count($zadania);
A ile XP jest do zdobycia? Musimy przejść po wszystkich elementach i dodać ich 'xp'.
SAMODZIELNIE
Napisz funkcję:
function sumujXp(array $zadania): int
która zwraca sumę wartości 'xp' wszystkich zadań z przekazanej tablicy. Dla pustej tablicy ma zwrócić 0.
Typ array w parametrze działa dokładnie tak samo jak int czy string — mówi, że funkcja oczekuje tablicy.
HINT
Zacznij od zmiennej, która „zbiera” wynik, i dodawaj do niej w każdym obrocie pętli:
$suma = 0;
$suma += 5; // $suma = $suma + 5
POMOC
function sumujXp(array $zadania): int
{
$suma = 0;
foreach ($zadania as $zadanie) {
// dodaj $zadanie['xp'] do $suma
}
return $suma;
}
ROZWIĄZANIE
function sumujXp(array $zadania): int
{
$suma = 0;
foreach ($zadania as $zadanie) {
$suma += $zadanie['xp'];
}
return $suma;
}
Wklej ją pod funkcją aktualizujStreak(). Test: sumujXp($zadania) dla listy z lekcji powinno dać 100.
8. Zadania wykonane i aktywne — array_filter()
Użytkownik chce widzieć osobno zadania do zrobienia i te, które ma za sobą. Potrzebujemy filtra: z całej listy wybrać tylko niektóre elementy.
array_filter() bierze tablicę i funkcję decydującą, czy element zostaje.
Minimalny przykład
$liczby = [1, 2, 3, 4, 5, 6];
$parzyste = array_filter($liczby, function ($liczba) {
return $liczba % 2 === 0;
});
print_r($parzyste);
Wynik:
Array ( [1] => 2 [3] => 4 [5] => 6 )
Co tu się dzieje?
function ($liczba) { ... }to funkcja bez nazwy (anonimowa). Nie definiujemy jej osobno — podajemy ją od razu jako drugi argument.- PHP wywołuje ją dla każdego elementu tablicy.
- Jeśli funkcja zwróci
true— element zostaje w wyniku, jeślifalse— jest pomijany.
Zwróć uwagę na klucze wyniku: 1, 3, 5. array_filter() zachowuje oryginalne klucze, więc w wyniku mogą być „dziury”. Dla foreach nie ma to znaczenia, ale $parzyste[0] nie istnieje!
SAMODZIELNIE
Napisz dwie funkcje:
function pobierzWykonaneZadania(array $zadania): array
function pobierzAktywneZadania(array $zadania): array
Pierwsza zwraca tylko zadania z 'wykonane' => true, druga — tylko z 'wykonane' => false.
HINT
Funkcja decydująca dostaje jeden element (jedno zadanie) i ma zwrócić true lub false. A wartość 'wykonane' jest już wartością true / false.
POMOC
function pobierzWykonaneZadania(array $zadania): array
{
return array_filter($zadania, function ($zadanie) {
// zwróć true, jeśli zadanie jest wykonane
});
}
W drugiej funkcji potrzebujesz zaprzeczenia: !.
ROZWIĄZANIE
function pobierzWykonaneZadania(array $zadania): array
{
return array_filter($zadania, function ($zadanie) {
return $zadanie['wykonane'];
});
}
function pobierzAktywneZadania(array $zadania): array
{
return array_filter($zadania, function ($zadanie) {
return !$zadanie['wykonane'];
});
}
Wklej pod sumujXp(). Następnie (w części „wywołania”, sekcja 10):
$wykonaneZadania = pobierzWykonaneZadania($zadania);
$aktywneZadania = pobierzAktywneZadania($zadania);
$liczbaWykonanych = count($wykonaneZadania);
$liczbaAktywnych = count($aktywneZadania);
9. Sortowanie według terminu — usort()
Lista powinna zaczynać się od zadań, które trzeba zrobić najszybciej. sort() nie wystarczy — elementy to tablice, a my chcemy sortować po jednym z kluczy. Potrzebujemy usort() (sortowanie własną regułą).
Minimalny przykład
$liczby = [30, 10, 20];
usort($liczby, function ($pierwsza, $druga) {
return $pierwsza <=> $druga;
});
print_r($liczby); // [10, 20, 30]
Operator <=> („spaceship operator”) porównuje dwie wartości i zwraca:
-1 jeśli lewa jest mniejsza
0 jeśli są równe
1 jeśli lewa jest większa
usort() sam wywołuje naszą funkcję dla par elementów i układa tablicę wg wyników. Zmiana kolejności argumentów ($druga <=> $pierwsza) daje sortowanie malejące.
Dwie ważne rzeczy:
usort()zmienia tablicę, na której pracuje (nie zwraca nowej) i numeruje klucze od nowa (0, 1, 2, …).- Daty w formacie
RRRR-MM-DDmożna porównywać jako zwykłe teksty — dlatego sortowanie po'termin'działa. (To jeden z powodów, dla których zapisujemy daty właśnie tak. Sprawdzisz to w eksperymencie).
SAMODZIELNIE
Napisz funkcję:
function sortujPoTerminie(array $zadania): array
która zwraca zadania ułożone od najwcześniejszego terminu do najpóźniejszego.
HINT
Porównujesz $zadanieA['termin'] z $zadanieB['termin'] — operatorem <=>.
POMOC
function sortujPoTerminie(array $zadania): array
{
usort($zadania, function ($zadanieA, $zadanieB) {
// porównaj terminy
});
return $zadania;
}
Dlaczego wewnątrz funkcji możemy bezpiecznie sortować? Funkcja dostaje kopię tablicy — oryginalna $zadania z głównego kodu pozostaje nietknięta. Zwracamy posortowaną kopię.
ROZWIĄZANIE
function sortujPoTerminie(array $zadania): array
{
usort($zadania, function ($zadanieA, $zadanieB) {
return $zadanieA['termin'] <=> $zadanieB['termin'];
});
return $zadania;
}
Wklej pod pobierzAktywneZadania(). W wywołaniach:
$zadaniaWgTerminu = sortujPoTerminie($zadania);
$aktywneWgTerminu = sortujPoTerminie($aktywneZadania);
Teraz w bloku foreach z sekcji 6 zmień $zadania na $zadaniaWgTerminu.
10. Kolejne zadanie — awans i najpilniejsze zadanie
Łączymy nowy temat z tym, co TaskQuest już umie: systemem poziomów.
a) $zadanieWykonane liczymy z listy
aktualizujStreak() potrzebuje informacji, czy użytkownik wykonał zadanie. Zamiast wpisywać true ręcznie, wyliczamy to z listy:
$zadanieWykonane = $liczbaWykonanych > 0;
$streak = aktualizujStreak($streak, $dataOstatniejAktywnosci, $zadanieWykonane);
Uproszczenie (symulacja): zadania nie mają jeszcze daty wykonania, więc na tym etapie uznajemy, że aktywność = „na liście jest choć jedno wykonane zadanie”. Gdy dojdzie baza danych, każde zadanie dostanie datę wykonania i to ona zastąpi to uproszczenie.
Wywołanie aktualizujStreak() przenieś pod linię z $zadanieWykonane — musi ją znać.
SAMODZIELNIE
- Oblicz ile XP jest do zdobycia z aktywnych zadań (wykorzystaj
sumujXp()) i zapisz w$xpDoZdobycia. - W panelu wyświetl komunikat:
- jeśli
$xpDoZdobycia >= $brakujeXp→ „Wykonując aktywne zadania, awansujesz na poziom N!” (N = następny poziom — pamiętasz$poziom + 1?), - w przeciwnym razie → „Aktywne zadania nie wystarczą jeszcze na awans — brakuje X XP.”
- jeśli
- Wyświetl najpilniejsze zadanie: pierwsze z listy
$aktywneWgTerminu(tytuł + komunikat o terminie). - Zadbaj o dwa przypadki brzegowe: lista pusta i wszystkie zadania wykonane. (Wtedy
$aktywneWgTerminu[0]nie istnieje!)
HINT
$aktywneWgTerminu[0]działa, bousort()numeruje klucze od zera (a$aktywneZadania[0]— jak pamiętasz — mogłoby nie istnieć).- Przypadki brzegowe sprawdzaj przez
count()(u nas:$liczbaWszystkichi$liczbaAktywnych).
ROZWIĄZANIE
Zmienna w części wywołań:
$xpDoZdobycia = sumujXp($aktywneZadania);
Fragment panelu HTML (pod statystykami):
<?php
if ($liczbaWszystkich === 0) {
echo "<p>Brak zadań.</p>";
} elseif ($liczbaAktywnych === 0) {
echo "<p>Wszystkie zadania wykonane — świetna robota!</p>";
} else {
if ($xpDoZdobycia >= $brakujeXp) {
echo "<p class=\"awans\">Wykonując aktywne zadania, awansujesz na poziom " . ($poziom + 1) . "!</p>";
} else {
echo "<p>Aktywne zadania nie wystarczą jeszcze na awans — brakuje " . ($brakujeXp - $xpDoZdobycia) . " XP.</p>";
}
$najpilniejsze = $aktywneWgTerminu[0];
echo "<p>Najpilniejsze zadanie: <strong>" . wyczyscTytul($najpilniejsze['tytul']) . "</strong> — "
. komunikatTerminu($najpilniejsze['termin']) . "</p>";
}
?>
Klasa .awans była w stylach od Lekcji 8 — wreszcie do czegoś służy.
11. Testy
Poniższe wyniki zakładają uruchomienie kodu 18.09.2026. Funkcja
komunikatTerminu()porównuje termin z prawdziwą, dzisiejszą datą, więc przy innym dniu komunikaty będą inne. Możesz wtedy przesunąć daty w$zadaniao odpowiednią liczbę dni.
Przed uruchomieniem spróbuj przewidzieć wynik.
Test 1 — liczby
| Co sprawdzamy | Oczekiwany wynik |
|---|---|
count($zadania) | 5 |
$liczbaWykonanych | 2 |
$liczbaAktywnych | 3 |
sumujXp($zadania) | 100 |
sumujXp($aktywneZadania) | 55 |
sumujXp($wykonaneZadania) | 45 |
sumujXp([]) | 0 |
Test 2 — kolejność po sortowaniu
| Lista | Kolejność id |
|---|---|
$zadaniaWgTerminu | 2, 3, 1, 5, 4 |
$aktywneWgTerminu | 2, 3, 4 |
Test 3 — klucze (print_r)
| Tablica | Klucze |
|---|---|
$aktywneZadania | 1, 2, 3 |
$wykonaneZadania | 0, 4 |
$aktywneWgTerminu | 0, 1, 2 |
Wyjaśnij, skąd ta różnica między pierwszym a trzecim wierszem.
Test 4 — komunikaty terminów (dla aktywnych zadań)
| Zadanie | Termin | Komunikat |
|---|---|---|
| Powtórzyć funkcje | 2026-09-16 | Termin minął 2 dni temu! |
| Ćwiczenia z DateTime | 2026-09-18 | Termin jest dzisiaj. |
| Nauczyć się tablic PHP | 2026-09-25 | Do terminu pozostało: 7 dni. |
Zadania wykonane nie pokazują komunikatu o terminie.
Test 5 — wartości graniczne awansu
Zmień $xp na wartości z tabeli (aktywne zadania to zawsze 55 XP):
$xp | $brakujeXp | Wynik |
|---|---|---|
| 0 | 100 | nie wystarczą — brakuje 45 XP |
| 44 | 56 | nie wystarczą — brakuje 1 XP |
| 45 | 55 | awansujesz (dokładnie tyle, ile trzeba!) |
| 99 | 1 | awansujesz |
Test 6 — streak
| Co sprawdzamy | Oczekiwany wynik |
|---|---|
$streak = 5, ostatnia aktywność 2026-09-14, jest wykonane zadanie | 1 (przerwa dłuższa niż dzień) |
ta sama sytuacja, ale $dataOstatniejAktywnosci = "2026-09-17" | 6 (aktywność wczoraj) |
ta sama sytuacja, ale wszystkie zadania 'wykonane' => false | 5 (bez zmian) |
Test 7 — przypadki brzegowe listy
| Zmiana w kodzie | Oczekiwany efekt |
|---|---|
$zadania = []; | „Brak zadań.”, liczniki 0/0/0, brak błędów |
wszystkie zadania 'wykonane' => true | „Wszystkie zadania wykonane — świetna robota!”, brak błędów |
dopisz szóste zadanie do $zadania | pojawia się na liście bez zmiany kodu wyświetlania |
12. Obowiązkowy eksperyment
Eksperyment 1: dlaczego data w formacie RRRR-MM-DD?
Zmień terminy w $zadania na format polski:
zadanie 1 → '20.09.2026'
zadanie 2 → '16.09.2026'
zadanie 3 → '18.09.2026'
zadanie 4 → '02.10.2026'
zadanie 5 → '22.09.2026'
Uruchom aplikację. Które zadanie jest teraz na początku listy? Czy to poprawne?
Odpowiedz:
Dlaczego zadanie z 2 października wylądowało przed zadaniami z września? Jak porównuje teksty operator
<=>? Dlaczego formatRRRR-MM-DDtego problemu nie ma?
(Wskazówka: usort() porównuje tutaj teksty znak po znaku, a pierwszy znak '0' jest „mniejszy” niż '1').
Przywróć poprawne daty.
Eksperyment 2: array_filter() a klucze
Wypisz print_r($aktywneZadania) i spróbuj odczytać $aktywneZadania[0]['tytul']. Co się stanie? Dlaczego? Jak zmieni się wynik po użyciu array_values($aktywneZadania)?
Eksperyment 3 (dodatkowy): sortowanie na kopii
Po wywołaniu sortujPoTerminie($zadania) wypisz $zadania[0]['id']. Czy oryginalna lista została zmieniona? Co by się stało, gdybyśmy wywołali usort($zadania, ...) bezpośrednio w głównym kodzie?
Eksperyment 4 (dodatkowy): krótsza wersja sumujXp()
Zapisz sumowanie w jednej linii:
return array_sum(array_column($zadania, 'xp'));
array_column() wyciąga z listy rekordów jedną „kolumnę” (tu: wartości 'xp'), a array_sum() je dodaje. Porównaj wyniki z wersją z foreach.
13. ROZWIĄZANIE — wersja referencyjna
Pełny kod TaskQuest po Lekcji 9. Zwróć uwagę na miejsca oznaczone komentarzem NOWE w Lekcji 9.
Pełny kod
<?php
define('XP_NA_POZIOM', 100);
$imieUzytkownika = "Kama";
$xp = 99;
function obliczPoziom(int $xp) : int {
$poziom = 1;
while ($xp >= $poziom * XP_NA_POZIOM) {
$poziom++;
}
return $poziom;
}
$poziom = obliczPoziom($xp);
function pobierzTytul(int $poziom) : string {
return match ($poziom) {
1 => "Nowicjusz",
2 => "Wojownik",
default => "Mistrz"
};
}
$tytul = pobierzTytul($poziom);
//postęp wewnątrz aktualnego poziomu
function obliczXpWAktualnymPoziomie(int $xp, int $poziom) : int {
$xpNaPoczatkuPoziomu = ($poziom - 1) * XP_NA_POZIOM;
$xpWAktualnymPoziomie = $xp - $xpNaPoczatkuPoziomu;
return $xpWAktualnymPoziomie;
}
$xpWAktualnymPoziomie = obliczXpWAktualnymPoziomie($xp, $poziom);
function obliczProcentPostepu(int $xpWAktualnymPoziomie) : float {
return ($xpWAktualnymPoziomie / XP_NA_POZIOM) * 100;
}
$procentPostepu = obliczProcentPostepu($xpWAktualnymPoziomie);
function ileBrakujeXp(int $xp, int $poziom): int
{
$progNastepnegoPoziomu = $poziom * XP_NA_POZIOM;
return $progNastepnegoPoziomu - $xp;
}
$brakujeXp = ileBrakujeXp($xp, $poziom);
//pasek postępu
$liczbaAktywnychSegmentow = (int) ($procentPostepu / 10);
$progNastepnegoPoziomu = $poziom * XP_NA_POZIOM;
$login = "Kama_2026";
function walidujLogin(string $login): bool {
return preg_match('/^[a-zA-Z0-9_-]{3,20}$/', $login) === 1;
}
function wyczyscTytul(string $tytul): string
{
$tytul = trim(preg_replace('/\s+/', ' ', $tytul));
return $tytul;
}
function skrocOpis(string $opis, int $limit = 50): string {
if (mb_strlen($opis) <= $limit) {
return $opis;
}
return mb_substr($opis, 0, $limit) . "...";
}
// --- NOWE w Lekcji 9: lista zadań zamiast pojedynczych zmiennych ---
$zadania = [
[
'id' => 1,
'tytul' => ' Nauczyć się regexów PHP ',
'opis' => 'Powtórzyć wyrażenia regularne przed następną lekcją.',
'termin' => '2026-09-20',
'wykonane' => true,
'xp' => 20
],
[
'id' => 2,
'tytul' => 'Powtórzyć funkcje',
'opis' => 'Przejrzeć wszystkie funkcje TaskQuest i sprawdzić ich parametry oraz typy zwracanych wartości.',
'termin' => '2026-09-16',
'wykonane' => false,
'xp' => 15
],
[
'id' => 3,
'tytul' => 'Ćwiczenia z DateTime',
'opis' => 'Napisać trzy własne przykłady z diff() i format().',
'termin' => '2026-09-18',
'wykonane' => false,
'xp' => 10
],
[
'id' => 4,
'tytul' => 'Nauczyć się tablic PHP',
'opis' => 'Zbudować listę zadań TaskQuest jako tablicę tablic asocjacyjnych.',
'termin' => '2026-09-25',
'wykonane' => false,
'xp' => 30
],
[
'id' => 5,
'tytul' => 'Przygotować projekt do Lekcji 10',
'opis' => 'Zastanowić się, jak podzielić TaskQuest na pliki i katalogi.',
'termin' => '2026-09-22',
'wykonane' => true,
'xp' => 25
]
];
$streak = 5;
$dataOstatniejAktywnosci = "2026-09-14";
function komunikatTerminu(string $terminZadania): string{
$dzisiaj = new DateTime('today');
$termin = new DateTime($terminZadania);
$roznica = $dzisiaj->diff($termin);
if ($termin < $dzisiaj) {
return "Termin minął {$roznica->days} dni temu!";
} elseif ($termin == $dzisiaj) {
return "Termin jest dzisiaj.";
} else{
return "Do terminu pozostało: {$roznica->days} dni.";
}
}
function aktualizujStreak(int $streak, string $dataOstatniejAktywnosci, bool $zadanieWykonane): int {
if (!$zadanieWykonane) return $streak;
$dzisiaj = new DateTime('today');
$wczoraj = new DateTime('yesterday');
$ostatniaAktywnosc = new DateTime($dataOstatniejAktywnosci);
if ($ostatniaAktywnosc->format('Y-m-d') === $dzisiaj->format('Y-m-d')) return $streak;
if ($ostatniaAktywnosc->format('Y-m-d') === $wczoraj->format('Y-m-d')) return $streak + 1;
return 1;
}
// --- NOWE w Lekcji 9: funkcje pracujące na liście zadań ---
function pobierzWykonaneZadania(array $zadania): array
{
return array_filter($zadania, function ($zadanie) {
return $zadanie['wykonane'];
});
}
function pobierzAktywneZadania(array $zadania): array
{
return array_filter($zadania, function ($zadanie) {
return !$zadanie['wykonane'];
});
}
function sumujXp(array $zadania): int
{
$suma = 0;
foreach ($zadania as $zadanie) {
$suma += $zadanie['xp'];
}
return $suma;
}
function sortujPoTerminie(array $zadania): array
{
usort($zadania, function ($zadanieA, $zadanieB) {
return $zadanieA['termin'] <=> $zadanieB['termin'];
});
return $zadania;
}
// --- wywołania funkcji dla listy zadań ---
$wykonaneZadania = pobierzWykonaneZadania($zadania);
$aktywneZadania = pobierzAktywneZadania($zadania);
$liczbaWszystkich = count($zadania);
$liczbaWykonanych = count($wykonaneZadania);
$liczbaAktywnych = count($aktywneZadania);
$xpDoZdobycia = sumujXp($aktywneZadania);
$zadaniaWgTerminu = sortujPoTerminie($zadania);
$aktywneWgTerminu = sortujPoTerminie($aktywneZadania);
// uproszczenie (symulacja): aktywność = wykonane jakiekolwiek zadanie z listy
$zadanieWykonane = $liczbaWykonanych > 0;
$streak = aktualizujStreak($streak, $dataOstatniejAktywnosci, $zadanieWykonane);
?>
<!DOCTYPE html>
<html lang="pl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TaskQuest</title>
<style>
body { font-family: Arial, sans-serif; max-width: 700px; margin: 40px auto; padding: 20px; }
.panel { border: 1px solid #ccc; padding: 24px; border-radius: 12px; }
.pasek-xp { display: flex; gap: 4px; margin: 10px 0; }
.segment { width: 32px; height: 18px; background: #ddd; border-radius: 3px; }
.segment.aktywny { background: #555; }
.awans { font-weight: bold; }
.zadanie { border: 1px solid #ddd; border-radius: 8px; padding: 4px 16px; margin: 10px 0; }
.zadanie.wykonane { background: #f2f2f2; color: #666; }
</style>
</head>
<body>
<div class="panel">
<h1>TaskQuest</h1>
<p>Zdobywaj punkty za wykonane zadania!</p>
<?php
if (walidujLogin($login)) {
echo "<p>Login poprawny: $login</p>";
} else {
echo "<p>Login jest niepoprawny.</p>";
}
?>
<h2>Witaj, <?= $imieUzytkownika; ?>!</h2>
<p>Poziom: <strong><?= $poziom; ?></strong></p>
<p>Tytuł: <strong><?= $tytul; ?></strong></p>
<p>Łączne XP: <strong><?= $xp; ?></strong></p>
<h3>
<?= "Masz $xpWAktualnymPoziomie XP z " . XP_NA_POZIOM . " XP potrzebnych do poziomu " . ($poziom + 1) . " (" . round($procentPostepu, 2) . "%)"; ?>
</h3>
<div class="pasek-xp">
<?php
for ($segment = 1; $segment <= 10; $segment++) {
if ($segment <= $liczbaAktywnychSegmentow) {
echo "█";
} else {
echo "░";
}
}
?>
</div>
<p>Kolejny próg: <?= $progNastepnegoPoziomu; ?> XP</p>
<p>Brakuje XP: <strong><?= $brakujeXp; ?></strong></p>
<p>Streak: <strong><?= $streak ?></strong></p>
<h2>Twoje zadania</h2>
<p>
Wszystkie: <strong><?= $liczbaWszystkich; ?></strong> |
Wykonane: <strong><?= $liczbaWykonanych; ?></strong> |
Aktywne: <strong><?= $liczbaAktywnych; ?></strong>
</p>
<p>XP do zdobycia z aktywnych zadań: <strong><?= $xpDoZdobycia; ?></strong></p>
<?php
if ($liczbaWszystkich === 0) {
echo "<p>Brak zadań.</p>";
} elseif ($liczbaAktywnych === 0) {
echo "<p>Wszystkie zadania wykonane — świetna robota!</p>";
} else {
if ($xpDoZdobycia >= $brakujeXp) {
echo "<p class=\"awans\">Wykonując aktywne zadania, awansujesz na poziom " . ($poziom + 1) . "!</p>";
} else {
echo "<p>Aktywne zadania nie wystarczą jeszcze na awans — brakuje " . ($brakujeXp - $xpDoZdobycia) . " XP.</p>";
}
$najpilniejsze = $aktywneWgTerminu[0];
echo "<p>Najpilniejsze zadanie: <strong>" . wyczyscTytul($najpilniejsze['tytul']) . "</strong> — "
. komunikatTerminu($najpilniejsze['termin']) . "</p>";
}
echo "<h3>Lista zadań (wg terminu)</h3>";
foreach ($zadaniaWgTerminu as $zadanie) {
$tytulCzysty = wyczyscTytul($zadanie['tytul']);
$znacznik = $zadanie['wykonane'] ? "[X]" : "[ ]";
$klasa = $zadanie['wykonane'] ? "zadanie wykonane" : "zadanie";
echo "<div class=\"$klasa\">";
echo "<p><strong>$znacznik $tytulCzysty</strong> — {$zadanie['xp']} XP</p>";
echo "<p>" . skrocOpis($zadanie['opis'], 50) . "</p>";
echo "<p>Termin: {$zadanie['termin']}";
if (!$zadanie['wykonane']) {
echo " — " . komunikatTerminu($zadanie['termin']);
}
echo "</p>";
if (stripos($tytulCzysty, 'PHP') !== false) {
echo "<p>To zadanie dotyczy PHP.</p>";
}
echo "</div>";
}
?>
</div>
</body>
</html>
14. Co zmieniliśmy w TaskQuest?
Zostaje
$imieUzytkownika, $login
$xp, $poziom, $tytul, $xpWAktualnymPoziomie, $procentPostepu, $brakujeXp,
$liczbaAktywnychSegmentow, $progNastepnegoPoziomu
$streak, $dataOstatniejAktywnosci, $zadanieWykonane
define('XP_NA_POZIOM', 100)
obliczPoziom(), pobierzTytul(), obliczXpWAktualnymPoziomie(), obliczProcentPostepu(),
ileBrakujeXp(), walidujLogin(), wyczyscTytul(), skrocOpis(), komunikatTerminu(), aktualizujStreak()
Dochodzi
$zadania // tablica tablic asocjacyjnych
$wykonaneZadania, $aktywneZadania
$liczbaWszystkich, $liczbaWykonanych, $liczbaAktywnych
$zadaniaWgTerminu, $aktywneWgTerminu
$xpDoZdobycia
pobierzWykonaneZadania(), pobierzAktywneZadania(), sumujXp(), sortujPoTerminie()
Nowe klucze zadania: id, tytul, opis, termin, wykonane, xp. Nowe narzędzia PHP: tablice, foreach, count(), array_filter(), usort(), <=>, funkcje anonimowe, print_r().
Zmieniamy
$zadanieWykonane— nie wpisujemytrueręcznie, tylko wyliczamy z listy (uproszczenie: choć jedno wykonane zadanie = aktywność),komunikatTerminu()— poprawiona literówka w tekście (logika bez zmian),- nagłówek z paskiem postępu —
($poziom + 1)zamiast++$poziom, wyczyscTytul(),skrocOpis(),komunikatTerminu()istripos()działają teraz na elementach listy, wewnątrzforeach.
Usuwamy
$tytulZadania,$opisZadania,$terminZadania— dane tego zadania są teraz w$zadania(unikamy duplikatu),$status— zastąpiony znacznikiem[X]/[ ]przy każdym zadaniu,$loginUzytkownika(jeśli występowało w Twoim kodzie) — obowiązuje$login.
Co nowego potrafi TaskQuest po tej lekcji?
Po Lekcji 9 TaskQuest przechowuje listę zadań, wyświetla ją posortowaną według terminów, liczy zadania wykonane i aktywne, podsumowuje XP do zdobycia i sprawdza, czy aktywne zadania wystarczą na awans na kolejny poziom.
Do samodzielnego sprawdzenia
[ ] Nadal rozwijam ten sam projekt TaskQuest (nie zaczynam nowego).
[ ] W kodzie nie ma już $loginUzytkownika ani ++$poziom.
[ ] Wiem, czym różni się tablica indeksowana od asocjacyjnej.
[ ] Każde zadanie to tablica asocjacyjna, a $zadania to tablica takich tablic.
[ ] Potrafię wyświetlić całą listę jedną pętlą foreach.
[ ] Dodanie szóstego zadania nie wymaga zmian w kodzie wyświetlania.
[ ] Wiem, do czego służy count().
[ ] Potrafię użyć array_filter() i wiem, co zwraca funkcja decydująca.
[ ] Wiem, dlaczego po array_filter() klucze mogą mieć "dziury".
[ ] Potrafię posortować tablicę rekordów przez usort() i <=>.
[ ] Zachowałem funkcje z Lekcji 7 i 8 i używam ich na elementach listy.
[ ] Przetestowałem pustą listę i listę, w której wszystkie zadania są wykonane.
Pytania kontrolne
- Dlaczego zestaw zmiennych
$tytulZadania,$terminZadania… przestał wystarczać? - Czym różni się
$xpZaDni[0]od$zadanie['xp']? - Co wypisze
echo $zadania[1]['tytul'];dla listy z lekcji? (Przewidź, potem sprawdź.) - W jakiej sytuacji
foreachnie wypisze niczego — i dlaczego to nie jest błąd? - Co zwraca funkcja podana do
array_filter()? Co dzieje się z elementem, dla którego zwróciłafalse? - Dlaczego
$aktywneZadania[0]może nie istnieć, a$aktywneWgTerminu[0]istnieje? - Co oznacza wynik
-1z operatora<=>? Jak zamienić sortowanie rosnące na malejące? - Dlaczego wewnątrz
sortujPoTerminie()możemy sortować, a oryginalna$zadaniasię nie zmienia? - Dlaczego w Lekcji 9 nie usuwamy
komunikatTerminu()iaktualizujStreak(), choć zmienia się sposób przechowywania zadań? $tytuli$zadanie['tytul']— czym się różnią w TaskQuest?
Zadanie końcowe — rozbuduj TaskQuest samodzielnie
Wybierz jedno (albo oba):
A) Sortowanie według XP. Dopisz funkcję sortujPoXp(array $zadania): array, która układa zadania od najwyżej do najniżej punktowanych (pamiętasz, jak zamienić kolejność w <=>?). Wyświetl w panelu informację „Największa nagroda: …” — czyli tytuł i XP pierwszego zadania z posortowanej listy.
B) Pierwszy ranking graczy. Utwórz tablicę $ranking z co najmniej trzema graczami. Każdy gracz ma klucze 'login' i 'xp'. Wpisz tam siebie ($login, $xp) i dwóch „rywali”. Posortuj ranking malejąco po XP i wyświetl go w foreach z numerami miejsc.
Pamiętaj: nazwa klucza to 'login' — nie 'loginUzytkownika'.
Most do Lekcji 10
Plik TaskQuest ma już kilkaset linii: funkcje, dane, style i HTML w jednym miejscu. Coraz trudniej w nim cokolwiek znaleźć.
Następny problem:
Jak podzielić TaskQuest na osobne pliki i katalogi, żeby aplikacja wciąż działała tak samo?
PODSUMOWANIE LEKCJI
W skrócie
- Tablica to jedna zmienna z wieloma wartościami. Każda wartość ma klucz (indeks) i wartość.
- Tablica indeksowana: klucze to liczby od
0. Pierwszy element to[0], ostatni to[count($tab) - 1]. - Tablica asocjacyjna: klucze to nazwy (
'tytul','xp'). Opisuje jedną „rzecz” – np. jedno zadanie. - Tablica tablic (lista rekordów) = lista zadań. Odczyt: najpierw numer elementu, potem klucz:
$zadania[1]['tytul']. $tab[] = wartoscdopisuje na końcu z kluczem o 1 większym od największego klucza liczbowego (nie „kolejnym wolnym”).- Odczyt nieistniejącego klucza nie zatrzymuje skryptu, ale daje ostrzeżenie
Undefined array keyi wartośćnull. foreach ($zadania as $zadanie)–$zadanieto kopia elementu. Zmiana$zadanie['wykonane']w pętli nie zmienia$zadania.- Kod z
foreachnie zależy od liczby elementów – dla pustej tablicy pętla po prostu się nie wykona (to nie jest błąd). - W cudzysłowie klucz tablicy zapisujemy w klamrach:
"{$zadanie['xp']} XP". Bez klamer ("$zadanie['xp']") jest błąd składni. array_filter()zachowuje oryginalne klucze → w wyniku mogą być „dziury” ([1],[3]…), a[0]może nie istnieć. Numerację od zera przywracaarray_values().- Funkcja podana do
array_filter()zwracatrue(element zostaje) albofalse(element odpada). usort()zmienia tablicę, którą dostaje, numeruje klucze od nowa i zwracatrue– nie zwraca posortowanej tablicy.- Funkcja porównująca w
usort()zwraca wynik<=>:$a <=> $b– rosnąco,$b <=> $a– malejąco. sort()/rsort()gubią klucze – nie używaj ich na tablicy asocjacyjnej, jeśli klucze są ważne (wtedyasort()/arsort()/ksort()).- Tablica przekazana do funkcji to kopia – dlatego
sortujPoTerminie()może sortować, a oryginał$zadaniazostaje bez zmian. - Daty w formacie
RRRR-MM-DDsortują się poprawnie jako tekst. DatyDD.MM.RRRR– nie. - W TaskQuest:
$tytulto tytuł gracza,$zadanie['tytul']to tytuł zadania.
Co trzeba umieć na INF.03?
- odczytać element tablicy indeksowanej i asocjacyjnej (
$wiersz[1],$wiersz['nazwa']), - odczytać wartość z tablicy tablic (
$zadania[2]['termin']), - wyświetlić wszystkie elementy tablicy w pętli
foreach, wstawiając je w HTML (akapity,<li>, wiersze<tr>,<option>), - wstawić element tablicy do tekstu w cudzysłowie (
{$...}) lub przez konkatenację, - podać wartość domyślną dla brakującego klucza:
$_GET['id'] ?? 6(alboisset()), - sprawdzić liczbę elementów (
count()) i obsłużyć pustą tablicę, - podejrzeć zawartość tablicy (
print_r()w<pre>) podczas szukania błędu.
Minimum, które powinno wejść w pamięć
- Indeksy zaczynają się od 0.
$tab[] = x;– dopisz na końcu.count($tab)– ile elementów.- Lista rekordów:
$zadania[numer]['klucz']. foreach ($tablica as $element)orazforeach ($tablica as $klucz => $wartosc).- W cudzysłowie:
"{$zadanie['xp']}"– z klamrami. print_r()w<pre>– gdy nie wiesz, co jest w tablicy.array_filter()zachowuje klucze → uważaj na[0];array_values()numeruje od nowa.usort($tab, funkcja)sortuje w miejscu;$a <=> $brosnąco,$b <=> $amalejąco.sort()gubi klucze,asort()je zachowuje.- Brakujący klucz →
?? wartośćDomyślna.
Ściągawka – najważniejsze polecenia i składnia
Tworzenie i odczyt
| Zapis | Znaczenie |
|---|---|
$t = []; | pusta tablica |
$t = [10, 25, 5]; | indeksowana (klucze 0, 1, 2) |
$z = ['tytul' => 'PHP', 'xp' => 20]; | asocjacyjna |
$lista = [ [...], [...] ]; | tablica tablic |
$t[0], $z['xp'], $lista[1]['xp'] | odczyt |
$t[] = 40; | dopisanie na końcu |
unset($t[1]); | usunięcie elementu (klucze się nie przesuwają) |
Informacje i wyszukiwanie
| Funkcja | Zwraca |
|---|---|
count($t) | liczbę elementów |
in_array('x', $t) | true/false – czy jest taka wartość |
isset($z['xp']) / array_key_exists('xp', $z) | czy jest taki klucz |
$z['opis'] ?? 'brak' | wartość albo domyślną |
array_sum(array_column($lista, 'xp')) | suma jednej „kolumny” listy |
implode(', ', $t) / explode(',', $tekst) | tablica → tekst / tekst → tablica |
Pętle
foreach ($zadania as $zadanie) {
echo "<li>{$zadanie['tytul']} — {$zadanie['xp']} XP</li>";
}
foreach ($zadanie as $klucz => $wartosc) {
echo "$klucz: $wartosc<br>";
}
Filtrowanie
$wynik = array_filter($tablica, function ($element) {
return /* warunek: true = zostaje */;
});
$wynik = array_values($wynik); // opcjonalnie: klucze od 0
Sortowanie
usort($tablica, function ($a, $b) {
return $a['klucz'] <=> $b['klucz']; // rosnąco; $b <=> $a – malejąco
});
<=> zwraca | gdy |
|---|---|
-1 | lewa < prawa |
0 | równe |
1 | lewa > prawa |
| Funkcja | Sortuje po | Klucze |
|---|---|---|
sort() / rsort() | wartościach ↑ / ↓ | tracone |
asort() / arsort() | wartościach ↑ / ↓ | zachowane |
ksort() / krsort() | kluczach ↑ / ↓ | zachowane |
usort() | własna reguła | tracone |
Podgląd
echo '<pre>';
print_r($zadania);
echo '</pre>';
Quiz – sprawdź się
1. Co zostanie wyświetlone?
$kolory = ['czerwony', 'zielony', 'niebieski'];
echo $kolory[1] . " " . count($kolory);
2. Jakie klucze będą miały elementy 'b' i 'd'?
$t = [5 => 'a'];
$t[] = 'b';
$t[2] = 'c';
$t[] = 'd';
3. Co zostanie wyświetlone?
$gracze = [
['login' => 'Kama_2026', 'xp' => 99],
['login' => 'Adam_12', 'xp' => 40],
['login' => 'Ola-7', 'xp' => 75]
];
echo $gracze[2]['login'] . " ma " . $gracze[0]['xp'] . " XP";
4. Ile wynosi count($macierz)?
$macierz = [[1, 2], [3, 4, 5]];
5. Znajdź błąd i popraw linię.
echo "<p>{$zadanie['tytul']} — $zadanie['xp'] XP</p>";
6. Co wypisze print_r($parzyste)? Co stanie się po echo $parzyste[0];? Jak to naprawić?
$liczby = [3, 8, 5, 10];
$parzyste = array_filter($liczby, function ($liczba) {
return $liczba % 2 === 0;
});
7. Uzupełnij kod tak, aby $cenne zawierało tylko zadania warte co najmniej 20 XP.
$cenne = array_filter($zadania, function ($zadanie) {
return ______________;
});
8. Jaki jest wynik każdego porównania?
echo 5 <=> 3;
echo 2 <=> 2;
echo 'a' <=> 'b';
9. Która wersja ułoży zadania od najwyżej do najniżej punktowanego?
A.
usort($zadania, function ($a, $b) {
return $a['xp'] <=> $b['xp'];
});
B.
usort($zadania, function ($a, $b) {
return $b['xp'] <=> $a['xp'];
});
C.
sort($zadania);
10. Dlaczego ten kod nie wyświetla listy (PHP zgłasza ostrzeżenie przy foreach)?
$posortowane = usort($zadania, function ($a, $b) {
return $a['termin'] <=> $b['termin'];
});
foreach ($posortowane as $zadanie) {
echo $zadanie['tytul'] . "<br>";
}
11. Lista $zadania z lekcji ma 3 aktywne zadania. Co wyświetli ten kod i dlaczego?
foreach ($zadania as $zadanie) {
$zadanie['wykonane'] = true;
}
echo count(pobierzAktywneZadania($zadania));
12. Co wyświetli kod i które z dwóch zadań zostanie przez to uznane za pilniejsze przy sortowaniu usort() po terminie? Czy to poprawne?
echo '02.10.2026' <=> '16.09.2026';
13. Co wypisze print_r($oceny)? Której funkcji użyć, żeby posortować oceny malejąco i nie stracić imion?
$oceny = ['Jan' => 4, 'Anna' => 5, 'Piotr' => 3];
sort($oceny);
14. Wiersz z bazy danych trafił do skryptu jako tablica numeryczna:
$wiersz = [34, 'Polska', 'Siklawica', 70];
Zapisz jedną instrukcję echo, która wyświetli: <tr><td>Siklawica</td><td>70</td></tr>
15. Zadanie praktyczne. W TaskQuest pod listą zadań wyświetl nagłówek Ukończone i listę <ul> z tytułami (oczyszczonymi) tylko wykonanych zadań. Wykorzystaj funkcje, które już masz. Gdy żadne zadanie nie jest wykonane, zamiast listy wyświetl Nic jeszcze nie ukończono.
Odpowiedzi
zielony 3'b'→ klucz6,'d'→ klucz7(nowy klucz = największy dotychczasowy + 1, a nie „pierwszy wolny”).Ola-7 ma 99 XP2–count()liczy elementy tylko pierwszego poziomu.- W cudzysłowie klucz z apostrofami wymaga klamer:
echo "<p>{$zadanie['tytul']} — {$zadanie['xp']} XP</p>";(albo konkatenacja). Array ( [1] => 8 [3] => 10 ).$parzyste[0]nie istnieje – ostrzeżenieUndefined array key 0, nic się nie wyświetli. Naprawa:$parzyste = array_values($parzyste);– wtedy klucze to0i1.return $zadanie['xp'] >= 20;1,0,-1- B. A sortuje rosnąco. C –
sort()nie wie, po którym kluczu rekordu sortować. usort()sortuje tablicę$zadaniaw miejscu i zwracatrue, a nie posortowaną tablicę.$posortowanetotrue, po którym nie da się iterować. Poprawnie: wywołaćusort($zadania, ...)i iterować po$zadania(albo użyćsortujPoTerminie(), która zwraca posortowaną kopię).3–$zadaniewforeachto kopia elementu, więc zmiana nie trafia do$zadania.-1– teksty są porównywane znak po znaku, a'0' < '1'. Zadanie z 2 października trafi przed zadanie z 16 września – to błąd. W formacieRRRR-MM-DDnajpierw porównywany jest rok, potem miesiąc, potem dzień, więc kolejność tekstowa zgadza się z kalendarzową.Array ( [0] => 3 [1] => 4 [2] => 5 )– imiona zniknęły, bosort()nadaje nowe klucze. Malejąco z zachowaniem kluczy:arsort($oceny);- Na przykład:
echo "<tr><td>{$wiersz[2]}</td><td>{$wiersz[3]}</td></tr>";alboecho "<tr><td>" . $wiersz[2] . "</td><td>" . $wiersz[3] . "</td></tr>"; - Przykładowe rozwiązanie:
<h3>Ukończone</h3>
<?php
if (count($wykonaneZadania) === 0) {
echo "<p>Nic jeszcze nie ukończono.</p>";
} else {
echo "<ul>";
foreach ($wykonaneZadania as $zadanie) {
echo "<li>" . wyczyscTytul($zadanie['tytul']) . "</li>";
}
echo "</ul>";
}
?>
Sprawdzenie: dla listy z lekcji – 2 pozycje (Nauczyć się regexów PHP, Przygotować projekt do Lekcji 10); po ustawieniu wszystkich 'wykonane' => false – komunikat „Nic jeszcze nie ukończono.”, bez ostrzeżeń. foreach działa poprawnie mimo „dziur” w kluczach $wykonaneZadania.