Najpopularniejsze pytania rekrutacyjne z PHP (z odpowiedziami)

Mateusz Bogolubow

04-11-2026

(aktualizacja: 04-11-2026)

Typy i porównania, tablice, OOP, PDO, bezpieczeństwo i Laravel. Sprawdź, jakie pytania z PHP padają na rozmowach na juniora i jak na nie odpowiadać.

Najpopularniejsze pytania rekrutacyjne z PHP (z odpowiedziami)
Na rozmowach z PHP najczęściej pada kilkanaście pytań: czym różni się == od ===, include od require, isset od empty, interfejs od klasy abstrakcyjnej, jak działa PDO z zapytaniami przygotowanymi oraz jak zabezpieczyć hasła i dane wejściowe. Rekruter nie sprawdza definicji z pamięci, tylko to, czy rozumiesz, jak PHP porównuje i konwertuje wartości oraz jak pisać kod bezpieczny. Dobra odpowiedź to jedno zdanie definicji i krótki przykład.

Rozmowa techniczna z PHP rzadko jest egzaminem z całego podręcznika. Najczęściej to te same kilkanaście tematów, przy których rekruter sprawdza, czy rozumiesz, jak PHP traktuje typy i dane z formularza, a nie tylko czy potrafisz skopiować gotowy skrypt. Poniżej znajdziesz pytania, które wracają na rozmowach na stanowisko juniora, razem z tym, jak na nie odpowiadać. Jeśli dopiero zastanawiasz się, czy PHP to dobry wybór, najpierw posłuchaj podcastu, a ten tekst potraktuj jako listę kontrolną. Pytania o bazę danych są osobno w artykule o pytaniach rekrutacyjnych z baz danych i SQL, bo na rozmowie z backendu padają zawsze obok pytań o PHP.

Przykłady z tego artykułu uruchomiliśmy w PHP 8.4.5, dlatego wyniki podane w tekście to faktyczne wyniki, a nie zgadywanie. Tam, gdzie zachowanie różni się w starszych wersjach, zaznaczamy to wprost.

Jak odpowiadać na pytania rekrutacyjne z PHP?

Najlepiej w trzech krokach: jedno zdanie definicji, krótki przykład (kilka linijek kodu lub sytuacja z projektu) i informacja, kiedy to ma znaczenie w praktyce. Taka odpowiedź zajmuje 30–60 sekund i pokazuje, że rozumiesz mechanizm, a nie wkułeś formułkę. Jeśli czegoś nie wiesz, powiedz, co wiesz, i rozumuj na głos. Rekruterzy oceniają sposób myślenia, a nie tylko wynik.

Pytania są ułożone od podstaw do tematów, które częściej pojawiają się przy ofertach na mid-poziom.

Podstawy PHP

Czym jest PHP i jak działa?

PHP to język skryptowy wykonywany po stronie serwera. Przeglądarka wysyła żądanie, serwer WWW (np. Apache lub nginx) przekazuje je do PHP, interpreter wykonuje skrypt i zwraca przeglądarce gotowy wynik, najczęściej HTML lub JSON. Kod PHP nie trafia do użytkownika, dlatego można w nim bezpiecznie łączyć się z bazą danych. Na PHP działa m.in. WordPress oraz frameworki takie jak Laravel i Symfony, więc w ofertach pracy to nadal jeden z najczęstszych języków backendowych. Zalety, wady i przyszłość języka omawia gość podcastu, którego znajdziesz na końcu artykułu.

Czym różni się == od ===?

== porównuje wartości po konwersji typów, a === porównuje wartość i typ bez konwersji. To najczęstsze pytanie z PHP, bo wynik luźnego porównania bywa zaskakujący:

var_dump(0 == "a");       // false (w PHP 8; w PHP 7 było true)
var_dump("1" == "01");    // true
var_dump("10" == "1e1");  // true
var_dump(100 == "1e2");   // true
var_dump(null == false);  // true
var_dump("0" == false);   // true
var_dump([] == false);    // true

var_dump(0 === "0");      // false
var_dump(1 === 1.0);      // false (int vs float)

Wniosek, który rekruter chce usłyszeć: domyślnie używaj ===, a == tylko wtedy, gdy świadomie chcesz konwersji. Zmiana z PHP 8 (porównanie liczby ze zwykłym tekstem) zredukowała część pułapek, ale "10" == "1e1" nadal daje true, bo oba teksty wyglądają jak liczby. W PHP 7 wynik 0 == "a" był inny; tego nie sprawdzaliśmy, opieramy się na dokumentacji zmian w PHP 8.

Co robi operator „statek kosmiczny” <=>?

Zwraca -1, 0 lub 1, zależnie od tego, czy lewa strona jest mniejsza, równa czy większa od prawej. W naszym teście "abc" <=> "abd" dało -1, 2 <=> 1 dało 1, a 1 <=> 1 dało 0. Najczęściej używa się go w funkcjach porównujących do usort (sortowanie niżej).

Czym różnią się isset, empty i is_null?

Wartośćissetemptyis_null
nullfalsetruetrue
0truetruefalse
"0"truetruefalse
"" (pusty tekst)truetruefalse
[] (pusta tablica)truetruefalse
"abc"truefalsefalse

isset sprawdza, czy zmienna istnieje i nie jest null. empty uznaje za puste także 0, "0", "" i pustą tablicę. Pułapka z życia: formularz z polem „liczba sztuk”, w którym użytkownik wpisał 0, zostanie przez empty uznany za niewypełniony. Jeśli 0 jest poprawną wartością, sprawdzaj isset i === "".

Czym różni się ?? od ?: (operator Elvisa)?

?? (null coalescing) zwraca lewą stronę, jeśli istnieje i nie jest null, w przeciwnym razie prawą. ?: zwraca lewą stronę, jeśli jest „prawdziwa”, więc reaguje też na 0, "" i [].

$x = 0;
var_dump($x ?: "domyślna");   // string(9) "domyślna"
var_dump($x ?? "domyślna");   // int(0)

$arr = [];
var_dump($arr['klucz'] ?? "brak"); // "brak", bez ostrzeżenia o nieistniejącym kluczu

Dla odczytu wartości z $_GET, $_POST czy tablicy konfiguracyjnej prawie zawsze lepszy jest ??, bo nie traktuje 0 jako braku danych i nie zgłasza ostrzeżenia, gdy klucza nie ma. Jest też zapis ??= (przypisz, jeśli brak).

Czym różni się include od require?

Oba wczytują inny plik PHP. Różnica to reakcja na brak pliku: include zgłasza ostrzeżenie (warning) i skrypt działa dalej, a require kończy skrypt błędem krytycznym. W teście wczytanie nieistniejącego pliku przez include wypisało ostrzeżenie Failed to open stream: No such file or directory, po czym wykonała się następna linia, a po require pojawił się Fatal error: Uncaught Error: Failed opening required i skrypt się zatrzymał. Warianty include_once i require_once dodatkowo pilnują, żeby plik wczytać tylko raz. Dobra odpowiedź: do plików niezbędnych (konfiguracja, klasy) użyj require, bo działanie bez nich nie ma sensu.

Czym różni się przekazanie przez wartość od przekazania przez referencję?

Domyślnie PHP przekazuje do funkcji kopię wartości, więc zmiana w funkcji nie wpływa na zmienną z zewnątrz. Znak & w parametrze przekazuje referencję. W teście funkcja addOne(array $arr) dodała element do kopii i tablica $t miała nadal 0 elementów, a addRef(array &$arr) zmieniła oryginał (1 element). Podobnie kopiowanie tablicy ($b = $a; $b[] = 4;) nie zmienia $a: po operacji count($a) to 3, a count($b) to 4.

Odwrotnie jest z obiektami: zmienna zawiera uchwyt do obiektu, więc funkcja przyjmująca obiekt może go zmienić. W teście chg(P $p) ustawiła $p->v = 2 i oryginał też miał 2. Prawdziwą niezależną kopię daje dopiero clone: zmiana w klonie na 9 nie zmieniła oryginału.

Czym różnią się sesje od ciasteczek?

Ciasteczko (cookie) jest zapisywane w przeglądarce i wysyłane z każdym żądaniem, więc użytkownik może je zobaczyć i zmienić. Sesja trzyma dane po stronie serwera, a w przeglądarce zostaje tylko identyfikator sesji (w ciasteczku). Dlatego w sesji przechowuje się to, co ma być zaufane (np. kto jest zalogowany), a w ciasteczku rzeczy mało wrażliwe (np. wybrany język). Tego tematu nie sprawdzaliśmy testem. Pytania uzupełniające dotyczą zwykle atrybutów ciasteczka (HttpOnly, Secure, SameSite) i ataku przez kradzież sesji; o ciasteczku SameSite piszemy w artykule o CSRF.

Czym różni się GET od POST i skąd PHP bierze dane z formularza?

$_GET zawiera dane z adresu URL (po znaku ?), $_POST dane z treści żądania, a $_REQUEST oba naraz (rzadko polecane, bo trudno wiedzieć, skąd wartość przyszła). GET służy do odczytu i nie powinien zmieniać stanu aplikacji, POST do wysyłania danych, które coś zmieniają (rejestracja, zamówienie). Najważniejsza zasada: żadnych danych z tych tablic nie wolno traktować jako zaufanych, trzeba je walidować i zabezpieczać przy wypisywaniu. Praktyczny przykład z walidacją znajdziesz w poradniku o walidacji formularza w PHP.

Tablice i funkcje

Jak posortować tablicę w PHP?

Dla prostych wartości służy sort() (rosnąco), rsort() (malejąco), a dla tablic asocjacyjnych asort() i ksort() (po wartości lub po kluczu). Dla własnych kryteriów używa się usort() z funkcją porównującą, w której przydaje się operator <=>. Sortowanie po wieku malejąco i imieniu rosnąco:

$people = [
    ['n' => 'Zofia', 'a' => 30],
    ['n' => 'Adam',  'a' => 25],
    ['n' => 'Ewa',   'a' => 30],
];

usort($people, fn($x, $y) => [$y['a'], $x['n']] <=> [$x['a'], $y['n']]);
// Ewa, Zofia, Adam

Sztuczka z tablicą po obu stronach <=> porównuje kolejne elementy po kolei, więc pozwala sortować po kilku kryteriach i odwracać kierunek wybranego z nich. W naszym teście wynik to Ewa, Zofia, Adam: najpierw osoby 30-letnie alfabetycznie, potem 25-letnia.

Czym różnią się array_map, array_filter i foreach?

array_map zwraca nową tablicę z przekształconymi elementami, array_filter zwraca tylko te elementy, dla których funkcja zwróciła prawdę, a foreach to pętla do przechodzenia po elementach i wykonywania na nich akcji. Dla [1, 2, 3] wyrażenie array_map(fn($n) => $n * 2, array_filter($nums, fn($n) => $n > 1)) dało 4, 6. foreach jest najczęściej najczytelniejszy przy efektach ubocznych (wypisywanie, zapis), a map i filter przy przekształcaniu danych. Zwróć uwagę, że array_filter zachowuje oryginalne klucze, co bywa zaskoczeniem przy dalszym indeksowaniu.

Programowanie obiektowe

Czym jest klasa, a czym obiekt, i po co są modyfikatory dostępu?

Klasa to opis (wzorzec) z polami i metodami, a obiekt to jej konkretny egzemplarz utworzony przez new. Modyfikatory dostępu ograniczają, kto widzi pole lub metodę: public (wszyscy), protected (klasa i klasy dziedziczące), private (tylko ta klasa). Dzięki nim ukrywasz szczegóły wewnętrzne i zostawiasz na zewnątrz tylko to, co ma być interfejsem klasy (enkapsulacja). Dobry przykład z życia: pole balance w klasie konta powinno być private, a zmiana salda dostępna tylko przez metody, które sprawdzają reguły.

Co to jest constructor promotion i readonly?

Od PHP 8 możesz deklarować i przypisywać pola bezpośrednio w konstruktorze (constructor promotion), a od PHP 8.1 oznaczyć je jako readonly, czyli możliwe do ustawienia tylko raz:

final class Money
{
    public function __construct(
        public readonly int $amount,
        public readonly string $currency = "PLN",
    ) {}
}

$m = new Money(100);
$m->amount = 5;
// Error: Cannot modify readonly property Money::$amount

To krótszy zapis niż osobna deklaracja pól i przypisania w ciele konstruktora. readonly sprawdza się przy obiektach wartości (kwota, adres e-mail), których po utworzeniu nie powinno się zmieniać.

Czym różni się klasa abstrakcyjna od interfejsu i traita?

Klasa abstrakcyjnaInterfejsTrait
Można utworzyć obiektnienienie
Zawiera gotowy kod metodtaknie (tylko sygnatury)tak
Ile można „odziedziczyć”jedną klasęwiele interfejsówwiele traitów
Do czegowspólna baza z częścią implementacjikontrakt: co klasa musi umiećwspółdzielony kod bez dziedziczenia

W teście próba utworzenia new Shape() (klasa abstrakcyjna) skończyła się błędem Cannot instantiate abstract class Shape, a klasa Circle dziedzicząca po niej implementowała metodę area() i dostawała gotową describe(). Interfejs Logger zapewnił kontrakt (log(string $m): void), a dwie różne klasy mogły go spełniać na swój sposób. Reguła kciuka dla rozmowy: interfejs, gdy chodzi o to, co klasa umie robić, klasa abstrakcyjna, gdy klasy mają wspólną część kodu i relację „jest rodzajem”, trait, gdy ten sam kod ma trafić do niepowiązanych klas.

Czym różni się self od static (late static binding)?

self wskazuje klasę, w której napisano kod, a static klasę, na której wywołano metodę (late static binding). Różnicę widać przy dziedziczeniu:

class A {
    public static function create() { return new self(); }
    public static function make()   { return new static(); }
}
class B extends A {}

echo get_class(B::create()); // A
echo get_class(B::make());   // B

new self() zawsze tworzy A, a new static() tworzy klasę, na której wywołano metodę, czyli B. To dobry sprawdzian, czy rozumiesz dziedziczenie metod statycznych.

Co to są przestrzenie nazw, autoloading i Composer?

Przestrzeń nazw (namespace) grupuje klasy i unika kolizji nazw (dwie klasy User w różnych bibliotekach). Autoloading wczytuje plik z klasą dopiero wtedy, gdy ta jest pierwszy raz potrzebna, dzięki czemu nie trzeba ręcznie pisać require dla każdej klasy. Composer to menedżer pakietów dla PHP: pobiera biblioteki zapisane w composer.json i generuje plik vendor/autoload.php. Standard PSR-4 mówi, że przestrzeń nazw odpowiada układowi katalogów. Tego tematu nie uruchamialiśmy w teście; odpowiadamy na podstawie dokumentacji Composera.

Jak obsługuje się wyjątki w PHP?

Blok try zawiera kod mogący zgłosić błąd, catch go obsługuje, a finally wykonuje się zawsze, niezależnie od wyniku. Ciekawostka: finally wykona się nawet po return w try. W naszym teście funkcja zwracająca "try" wypisała najpierw finally, a dopiero potem wynik. W PHP 7 i nowszych błędy dzielą się na Exception (wyjątki aplikacji) i Error (błędy silnika, np. TypeError), a oba implementują interfejs Throwable. Dlatego catch (Exception $e) nie złapie błędu typu; trzeba Error albo Throwable.

PHP 8 i typy

Do czego służy declare(strict_types=1)?

Domyślnie PHP próbuje konwertować typy argumentów (tryb „coercive”), więc funkcja z parametrem int przyjmie tekst "5". Po dodaniu declare(strict_types=1); na początku pliku konwersja jest zabroniona dla wywołań z tego pliku:

declare(strict_types=1);

function add(int $a, int $b): int { return $a + $b; }

add("5", 3);
// TypeError: add(): Argument #1 ($a) must be of type int, string given

Bez strict_types ta sama funkcja zwróciła w teście 8. Dobra odpowiedź: w nowym kodzie włączam strict_types i deklaruję typy parametrów oraz zwracanej wartości, bo kompilator i edytor wychwytują wtedy błędy wcześniej. Osobna sprawa to operacje arytmetyczne na tekście: w naszym teście (z strict_types) wyrażenie "abc" * 2 zgłosiło TypeError: Unsupported operand types: string * int.

Czym różni się match od switch?

match (od PHP 8.0) jest wyrażeniem zwracającym wartość, porównuje ściśle (===) i nie wymaga break. Jeśli żaden przypadek nie pasuje, a nie ma default, zgłasza UnhandledMatchError. switch porównuje luźno (==) i „przechodzi” do kolejnych przypadków, jeśli zapomnisz break.

$code = 404;

echo match (true) {
    $code >= 500 => "serwer",
    $code >= 400 => "klient",
    default      => "ok",
}; // klient

echo match ($code) { 200 => "ok" };
// UnhandledMatchError: Unhandled match case 404

W teście switch ("1") { case 1: ... } dopasował liczbę do tekstu (luźne porównanie), czego match by nie zrobił. To pułapka, o którą rekruterzy pytają przy porównaniu obu konstrukcji.

Co to jest enum i operator nullsafe?

Enum (od PHP 8.1) to typ o skończonej liście wartości, np. status konta. Wersja „z wartościami” (backed enum) mapuje je na string lub int:

enum Status: string {
    case Active  = 'active';
    case Blocked = 'blocked';
}

echo Status::from('active')->name;                  // Active
echo Status::tryFrom('x')?->name ?? 'brak';         // brak

from zgłasza błąd dla nieznanej wartości, a tryFrom zwraca null. Operator ?-> (nullsafe) przerywa łańcuch wywołań, gdy po lewej jest null, zamiast zgłaszać błąd. W teście $user?->name ?? "brak użytkownika" dla $user = null dało brak użytkownika.

Bezpieczeństwo i baza danych

Jak bezpiecznie wysyłać zapytania do bazy w PHP?

Zapytaniami przygotowanymi (prepared statements) w PDO: kod SQL i dane są wysyłane do bazy osobno, więc dane nie mogą zmienić struktury zapytania. Porównanie na tej samej tabeli użytkowników, gdy ktoś wpisał jako e-mail tekst ' OR '1'='1:

$input = "' OR '1'='1";

// źle: sklejanie tekstu
$bad = $pdo->query("SELECT name FROM users WHERE email = '$input'")->fetchAll();
// zwróciło 2 wiersze, czyli wszystkich użytkowników

// dobrze: zapytanie przygotowane
$st = $pdo->prepare("SELECT name FROM users WHERE email = :email");
$st->execute(['email' => $input]);
// zwróciło 0 wierszy

Zapytania przygotowane są pierwszą linią obrony, ale nie obejmują nazw tabel, kolumn ani kierunku ORDER BY; te wartości trzeba wybierać z listy dozwolonych. Szczegóły ataku i obrony opisujemy w artykule o tym, czym jest SQL injection i jak się przed nim bronić. W naszym teście użyliśmy SQLite przez PDO; w MySQL zasada jest identyczna, ale tego nie testowaliśmy.

Jak przechowywać hasła użytkowników?

Nigdy w postaci jawnej ani zwykłym md5 czy sha1. Używa się password_hash(), który sam generuje sól i stosuje wolny, odpowiedni dla haseł algorytm, oraz password_verify() do sprawdzenia hasła przy logowaniu. W teście password_hash("tajne", PASSWORD_DEFAULT) dało napis o długości 60 znaków zaczynający się od $2y$ (bcrypt), password_verify("tajne", $hash) zwróciło true, a dla złego hasła false. Dobra odpowiedź podkreśla, że hasła nie da się odczytać z haszu, można je tylko sprawdzić, i że kolumna na hasz powinna być dostatecznie długa (zalecane 255 znaków), bo domyślny algorytm może się zmienić.

Jak zabezpieczyć dane wypisywane na stronie przed XSS?

Przez zamianę znaków specjalnych HTML przed wypisaniem: htmlspecialchars($text, ENT_QUOTES, 'UTF-8'). W teście <script>alert(1)</script> zamieniło się na &lt;script&gt;alert(1)&lt;/script&gt;, które przeglądarka wyświetli jako tekst, a nie wykona. Zasada: filtrujesz dane przy wejściu (walidacja), ale zabezpieczasz przy wyjściu, bo to wyjście zależy od kontekstu (HTML, atrybut, JavaScript). Szerzej o ataku piszemy w artykule o XSS w JavaScript. Powiązany temat to CSRF: ochrona formularzy tokenem, którą frameworki robią automatycznie.

Frameworki i praktyka

Czym jest Laravel i architektura MVC?

Laravel to najpopularniejszy framework PHP. Opiera się na wzorcu MVC (Model-View-Controller): model reprezentuje dane i reguły (w Laravelu przez Eloquent ORM), widok to szablon wyświetlany użytkownikowi (Blade), a kontroler przyjmuje żądanie i łączy oba elementy. Dostajesz gotowy routing, walidację, middleware, migracje bazy i uwierzytelnianie (np. przez Laravel Breeze). Dobra odpowiedź pokazuje, po co framework: żeby nie pisać od nowa tego, co powtarza się w każdej aplikacji, i narzucić strukturę, którą rozumie cały zespół.

Co to jest Eloquent i problem N+1?

Eloquent to ORM w Laravelu: tabela odpowiada klasie modelu, a wiersz obiektowi. Relacje (jeden do wielu, wiele do wielu) opisujesz metodami w modelach. Problem N+1 występuje, gdy pobierasz listę rekordów jednym zapytaniem, a potem dla każdego z nich osobne zapytanie o powiązane dane. Rozwiązanie to eager loading (with()), czyli wczytanie relacji hurtem. Ogólne wyjaśnienie problemu znajdziesz w artykule o pytaniach rekrutacyjnych z SQL.

Jakie zadania z kodem pojawiają się na rozmowach z PHP?

Najczęściej: napisanie klasy z konstruktorem i metodami (np. koszyk, konto bankowe), walidacja danych z formularza, pobranie rekordów z bazy przez PDO i wyświetlenie ich w HTML, sortowanie tablicy asocjacyjnej, FizzBuzz lub odwrócenie tekstu oraz pytania o różnice między konstrukcjami (== i ===, include i require). Rekruter patrzy, czy zabezpieczasz dane wejściowe, czy używasz zapytań przygotowanych i czy kod jest czytelny. Umiejętności wymagane od juniora backendowego zbiera artykuł o tym, jak przygotować się do rekrutacji na juniora developera.

Czy PHP jest trudny i czym różni się od Pythona?

PHP ma niski próg wejścia: pierwsze działające skrypty napiszesz w jeden wieczór, a hosting jest tani i wszechobecny. Trudność pojawia się przy pisaniu bezpiecznego, dobrze zorganizowanego kodu (obiektowość, PDO, frameworki), a nie przy składni. Python jest językiem ogólnego przeznaczenia (backend, dane, AI), a PHP wyspecjalizowanym w aplikacjach webowych, więc wybór zależy od celu. Obydwa mają dużo ofert pracy, a pytania rekrutacyjne z Pythona zebraliśmy w osobnym artykule o pytaniach rekrutacyjnych z Pythona.

Co zwróci ten kod? Mini-test na rozgrzewkę

Rekruterzy lubią pytanie „co wypisze ten kod?”. Spróbuj odpowiedzieć na trzy poniższe, zanim zajrzysz do odpowiedzi. Wszystkie uruchomiliśmy w PHP 8.4.5.

Zadanie 1. Co wypisze ten kod?

$x = 0;
var_dump($x ?: "domyślna");
var_dump($x ?? "domyślna");

Odpowiedź: string(9) "domyślna" i int(0). Operator ?: traktuje 0 jak brak wartości, a ?? reaguje tylko na null lub nieistniejącą zmienną.

Zadanie 2. Ile elementów będzie miała każda tablica?

$a = [1, 2, 3];
$b = $a;
$b[] = 4;

echo count($a), count($b);

Odpowiedź: 34. Tablice są przekazywane i kopiowane przez wartość, więc dopisanie do $b nie zmienia $a.

Zadanie 3. Co się stanie po uruchomieniu tego kodu?

$code = 404;
echo match ($code) { 200 => "ok" };

Odpowiedź: błąd UnhandledMatchError: Unhandled match case 404. match nie ma „domyślnego” przejścia jak switch, więc brak dopasowania i brak default kończy się wyjątkiem.

Jak przygotować się do rozmowy z PHP?

Samo czytanie odpowiedzi nie wystarczy, bo pytania uzupełniające szybko pokazują, czy rozumiesz temat. Skuteczniej działa napisanie małej aplikacji (lista zadań lub księga gości z logowaniem i bazą) bez kopiowania gotowca oraz głośne tłumaczenie decyzji komuś innemu, na przykład mentorowi. Dla porządku:

ObszarCo umieć wyjaśnić własnymi słowami
Podstawyjak działa PHP, == vs ===, isset/empty, ?? vs ?:, include vs require
Dane z formularza$_GET/$_POST, walidacja, sesje i ciasteczka
Tablicesortowanie, usort i <=>, array_map/array_filter, kopiowanie wartościowe
OOPklasa i obiekt, modyfikatory, abstrakcja vs interfejs vs trait, self vs static, wyjątki
PHP 8strict_types, constructor promotion, readonly, match, enum, ?->
BezpieczeństwoPDO i zapytania przygotowane, password_hash, htmlspecialchars, CSRF
FrameworkiComposer i autoloading, MVC, Laravel i Eloquent, problem N+1

Na czym juniorzy najczęściej tracą punkty?

Nie na trudnych tematach, tylko na trzech drobiazgach, które wychodzą dopiero przy pytaniach uzupełniających:

  1. Luźne porównania i empty na danych z formularza. 0, "0" i "" zachowują się inaczej, niż zakłada kandydat. Nie wystarczy napisać „użyję empty”. Wyjaśnij, co się stanie, gdy użytkownik wpisze 0.
  2. Sklejanie zapytań SQL z danych użytkownika. Kod „działa”, dopóki ktoś nie wpisze w pole apostrofu. Pokaż, że od razu sięgasz po PDO i zapytania przygotowane.
  3. Brak rozumienia, czym różni się interfejs od klasy abstrakcyjnej. Odpowiedź „interfejs nie ma kodu” jest prawdziwa, ale niepełna. Powiedz, kiedy wybierzesz jedno, a kiedy drugie, na przykładzie z projektu.

Na co zwraca uwagę mentor, gdy sprawdza kod w PHP?

Przy code review kodu w PHP mentor zwykle zaczyna od trzech rzeczy, które pasują też do rozmowy rekrutacyjnej.

Pierwsze: „Co się stanie, gdy użytkownik wpisze 0, pusty tekst albo apostrof?” Większość błędów w PHP to nie złe algorytmy, tylko dane, których autor nie przewidział: empty("0") uznaje liczbę za brak danych, luźne == zaskakuje przy tekstach wyglądających jak liczby, a apostrof w polu formularza psuje zapytanie sklejone z tekstu. Kto zadaje to pytanie sam sobie przed oddaniem kodu, oszczędza mentorowi poprawek.

Drugie: „Włącz strict_types i typy od pierwszego pliku.” Błąd typu wychwycony w edytorze lub od razu po uruchomieniu to minuta pracy. Ten sam błąd odkryty dopiero w produkcji, gdy "5" po cichu zamienia się w liczbę, a "abc" w zero, to godziny szukania. Typy parametrów i zwracanej wartości są też najlepszą dokumentacją funkcji.

Trzecie: zbuduj małą aplikację bez frameworka, zanim sięgniesz po Laravela. Księga gości z logowaniem, formularzem i bazą przez PDO pokazuje, ile pracy framework robi za ciebie: routing, walidację, ochronę CSRF, migracje. Kto raz napisał to ręcznie, rozumie, po co jest MVC i Eloquent, i potrafi wyjaśnić to na rozmowie, zamiast powtarzać nazwy z dokumentacji.

Jak brzmi dobra odpowiedź, a jak słaba?

Weźmy pytanie o == i ===:

OdpowiedźDlaczego
Słaba„=== jest dokładniejsze.”To nic nie tłumaczy. Pytanie „co zwróci "10" == "1e1"?” od razu to pokaże.
Dobra„== porównuje po konwersji typów, więc "10" == "1e1" jest true, bo oba teksty wyglądają jak liczby. === porównuje też typ, więc 0 === "0" jest false. Domyślnie używam ===.”Jest mechanizm, konkretny przykład i zasada, której się trzymasz.

Ten sam schemat działa przy każdym pytaniu z tego artykułu: definicja, mechanizm, przykład użycia.

Co zrobić, gdy nie znasz odpowiedzi?

Nie zgaduj i nie milcz. Powiedz, co wiesz na pewno, a potem rozumuj na głos, np.: „Nie pamiętam dokładnej nazwy tej funkcji, ale wiem, że szukam czegoś do sortowania z własnym porównaniem, więc sprawdziłbym usort w dokumentacji php.net.” Taka odpowiedź pokazuje, że potrafisz sobie poradzić w pracy, a umiejętność znalezienia odpowiedzi jest w codziennej pracy ważniejsza niż pamięć do szczegółów.

Dobrze też wiedzieć, jak wygląda sama decyzja o nauce PHP. W podcaście Marcin Wesel opowiada o zaletach, wadach i przyszłości tego języka.

Znajomość odpowiedzi to połowa sukcesu, drugą jest znalezienie rozmów, na które warto się umówić. Jeśli szukasz ofert, sięgnij po darmowy poradnik o tym, jak szukać pracy w 2026 roku, w którym zebraliśmy 3 sposoby poszukiwania pracy, które u naszych podopiecznych dają najlepsze efekty. Całość procesu, od CV po rozmowę, opisuje artykuł o tym, jak przejść cały proces rekrutacyjny na juniora.

Jeśli braki wyjdą przy programowaniu obiektowym albo bezpieczeństwie, to sygnał, że warto uporządkować wiedzę z mentorem. W kursie PHP są osobne moduły o programowaniu obiektowym w PHP, Laravelu i Eloquent, a w module o projektowaniu bazy MySQL uczysz się też ochrony przed SQL injection. Zadania i projekty z tej tematyki sprawdza mentor w code review.

Konsultacja i warsztaty devmentor.pl

Masz pytania?

Partnerzy

Firmy, z którymi współpracujemy

To partnerzy odpowiedzialni za staże po naszych kursach. Organizują je dla najlepszych absolwentów.

Zobacz wszystkich partnerów →
  • VR Medical
  • Sophona
  • Robot Force