PHP Probeaufgabe: fair gestalten und richtig bewerten

Redaktion PHP-Entwickler gesucht Aktualisiert 5 Min. Lesezeit

Kurz gesagt

Eine gute PHP-Probeaufgabe dauert höchstens drei Stunden, stammt aus einer realistischen, aber nicht produktiv nutzbaren Domäne und wird nach einem vorher festgelegten Raster bewertet. Besonders aussagekräftig ist eine Code-Review-Aufgabe: Kandidaten finden Fehler in vorhandenem Code und begründen Verbesserungen. Zahl eine Pauschale, denn die Zeit der Bewerber ist Arbeitszeit.

Hände tippen auf einem Laptop, auf dessen Bildschirm ein Code-Editor geöffnet ist
Foto: Crew crew, CC0, via Wikimedia Commons

Die meisten Probeaufgaben scheitern nicht an den Kandidaten. Sie scheitern daran, dass niemand vorher festgelegt hat, woran eine gute Lösung zu erkennen ist. Dann bewertet jeder im Team nach Gefühl, und am Ende gewinnt die Lösung mit den meisten Zeilen.

Dazu kommt ein Zeitproblem. Eine „kleine Aufgabe fürs Wochenende“ wird schnell zu acht Stunden Arbeit. Erfahrene PHP-Entwickler, die gerade einen Job haben, abends Familie und am Wochenende andere Pläne, sagen dann einfach ab und bewerben sich bei der nächsten Firma, die weniger verlangt.

Hausaufgabe, Live-Coding oder Code-Review?

Es gibt drei gängige Formate. Sie messen unterschiedliche Dinge und kosten unterschiedlich viel Zeit.

Formate für die technische Probe im Vergleich
KriteriumHausaufgabeLive-CodingCode-Review
Zeit für Kandidaten2 bis 3 Stunden45 bis 60 Minuten60 bis 90 Minuten
Zeit fürs TeamBewertung plus GesprächGesprächVorbereitung einmalig, dann Gespräch
Realistische Arbeitssituation
Misst Stressresistenz statt Könnenteilweise
Zeigt Qualitätsbewusstseinteilweise
Anfällig für KI-Hilfeteilweise

Meine Empfehlung für die meisten PHP-Stellen: eine Code-Review-Aufgabe, die Kandidaten vorab bekommen und im Gespräch erläutern. Sie ist kurz, nah am Alltag und schwer zu fälschen, weil die Begründungen zählen und nicht der Code.

Das passt auch zum Berufsalltag. Wer in einem Team arbeitet, liest mehr Code, als er schreibt. Ein Entwickler, der fremden Code schnell versteht und Probleme klar benennt, ist in fast jedem Projekt wertvoll.

Eine fertige Code-Review-Aufgabe

Die folgende Aufgabe kannst du direkt verwenden. Sie stammt aus einer allgemeinen Domäne, Rechnungen, und hat nichts mit deinem Produkt zu tun. Die Anweisung an die Kandidaten lautet: „Diese Klasse ist so in einem Pull Request eingereicht worden. Schreib dein Review: Was würdest du ändern, und warum? Maximal 90 Minuten.“

<?php

class InvoiceService
{
    public function __construct(private PDO $db) {}

    public function markPaid($id, $amount)
    {
        $invoice = $this->db->query("SELECT * FROM invoices WHERE id = $id")->fetch();

        if ($invoice['total'] == $amount) {
            $this->db->exec("UPDATE invoices SET status = 'paid' WHERE id = $id");
            mail($invoice['email'], 'Danke', 'Zahlung erhalten');
            return true;
        }

        return false;
    }
}

In den knapp 20 Zeilen steckt mehr, als man auf den ersten Blick sieht. Diese Punkte sollte ein gutes Review finden, ungefähr nach Schwere sortiert:

  1. SQL-Injection: $id landet ungeprüft im SQL-String, zweimal.
  2. Keine Prüfung, ob die Rechnung existiert. fetch() liefert dann false, und der Zugriff auf $invoice['total'] erzeugt eine Warnung statt eines klaren Fehlers.
  3. Loser Vergleich == bei Geldbeträgen, vermutlich als Float oder String. Beträge gehören als Cent in einen Integer.
  4. Keine Transaktion und keine Sperre: Zwei gleichzeitige Zahlungen können dieselbe Rechnung zweimal verbuchen.
  5. Eine bereits bezahlte Rechnung wird nicht erkannt.
  6. Der Mailversand passiert synchron mitten in der Geschäftslogik. Schlägt er fehl, ist der Status trotzdem geändert.
  7. Rückgabewert bool sagt nicht, warum etwas nicht geklappt hat.
  8. Fehlende Typen, kein declare(strict_types=1), Klasse nicht final.

Eine mögliche Überarbeitung in PHP 8.3, als Referenz für dein Team:

<?php

declare(strict_types=1);

final readonly class InvoiceService
{
    public function __construct(
        private PDO $db,
        private PaymentMailer $mailer,
    ) {}

    public function markPaid(int $invoiceId, int $amountInCents): void
    {
        $this->db->beginTransaction();

        try {
            $stmt = $this->db->prepare(
                'SELECT total_cents, status, email FROM invoices WHERE id = :id FOR UPDATE'
            );
            $stmt->execute(['id' => $invoiceId]);
            $invoice = $stmt->fetch(PDO::FETCH_ASSOC);

            if ($invoice === false) {
                throw new InvoiceNotFound($invoiceId);
            }
            if ($invoice['status'] === 'paid') {
                throw new InvoiceAlreadyPaid($invoiceId);
            }
            if ((int) $invoice['total_cents'] !== $amountInCents) {
                throw new AmountMismatch($invoiceId, $amountInCents);
            }

            $this->db
                ->prepare("UPDATE invoices SET status = 'paid' WHERE id = :id")
                ->execute(['id' => $invoiceId]);

            $this->db->commit();
        } catch (Throwable $e) {
            $this->db->rollBack();
            throw $e;
        }

        $this->mailer->queuePaymentConfirmation($invoice['email']);
    }
}

Niemand muss genau diese Lösung schreiben. Wichtig sind die Begründungen. Wer Punkt 4 erkennt und erklärt, warum FOR UPDATE in einer Transaktion hilft, denkt über Nebenläufigkeit nach. Das ist bei Zahlungen keine Kür. Hintergrund zu Prepared Statements bietet das PHP-Handbuch zu PDO.

Wenn es doch eine Programmieraufgabe sein soll

Manche Teams wollen sehen, wie jemand von Grund auf baut. Das ist legitim, gerade für Rollen, in denen viel neuer Code entsteht. Dann gelten drei Regeln.

Erstens: Die Aufgabe muss in drei Stunden machbar sein, und zwar für jemanden, der dein Team nicht kennt. Lass sie vorher von einem Kollegen lösen und stoppe die Zeit. Wenn er vier Stunden braucht, streichst du ein Drittel.

Zweitens: Gib ein Gerüst vor. Ein leeres Laravel- oder Symfony-Projekt mit Datenbank-Setup per Docker spart jedem Kandidaten eine Stunde Konfiguration, die nichts über sein Können aussagt.

Drittens: Sag ehrlich, was zählt. Wenn Tests wichtig sind, schreib es hinein. Wenn dir Lesbarkeit wichtiger ist als Vollständigkeit, ebenso.

Ein Beispiel für eine passende Spezifikation: „Baue einen Endpunkt POST /api/vouchers/redeem, der einen Gutscheincode einlöst. Ein Code darf nur einmal eingelöst werden, auch bei gleichzeitigen Anfragen. Abgelaufene Codes werden abgelehnt. Schreib mindestens drei Tests. Keine Oberfläche nötig.“ Das sind vier Sätze. Sie prüfen Validierung und Nebenläufigkeit, dazu Fehlerbehandlung und Testkultur, ohne dass jemand einen halben Tag an einer Oberfläche bastelt, die du ohnehin nicht bewertest.

Feedback für alle, auch für Absagen

Wer drei Stunden in deine Aufgabe gesteckt hat, verdient mehr als eine Standardabsage. Zwei, drei konkrete Sätze zur Lösung reichen. „Die Transaktion war sauber gelöst, die Fehlerfälle blieben offen“ kostet dich fünf Minuten.

Es lohnt sich auch für dich. Die PHP-Szene ist überschaubar, und Kandidaten erzählen, wie ein Bewerbungsprozess gelaufen ist. Ein fairer Prozess mit ehrlichem Feedback spricht sich herum, ein schlechter auch.

Das Bewertungsraster gehört vor die Aufgabe

Lege fest, was du bewertest, bevor die erste Lösung eingeht. Sonst verschieben sich die Maßstäbe von Kandidat zu Kandidat.

Raster für die Code-Review-Aufgabe (je 0 bis 2 Punkte)
  • Sicherheitslücke erkannt und Lösung benannt
  • Fehlerfall „Rechnung nicht gefunden“ behandelt
  • Problem mit Geldbeträgen und losem Vergleich erklärt
  • Nebenläufigkeit oder Transaktion angesprochen
  • Seiteneffekt Mailversand kritisch bewertet
  • Vorschläge priorisiert statt nur aufgelistet
  • Ton des Reviews: sachlich, respektvoll, konkret

Der letzte Punkt wird oft vergessen. Ein Review, das alle Fehler findet, aber den Autor herunterputzt, sagt viel über die künftige Zusammenarbeit. Bei 14 möglichen Punkten sind 9 für eine Mid-Level-Rolle ein guter Wert, für Senior-Rollen eher 11 und mehr. Diese Schwellen sind ein Vorschlag, passe sie an.

Im anschließenden Gespräch lässt du die Person zwei, drei Punkte vertiefen. Passende Nachfragen findest du im Katalog der PHP-Interviewfragen. Für Senior-Rollen bietet es sich an, zusätzlich über Architektur zu sprechen, siehe Senior-PHP-Entwickler erkennen.

Bezahlen, und wie viel?

Rechtlich ist die Lage gemischt. Ein kurzes Kennenlernen im Betrieb ohne Arbeitspflicht, das sogenannte Einfühlungsverhältnis, muss nicht vergütet werden. Sobald jemand produktiv mitarbeitet, gilt mindestens der gesetzliche Mindestlohn, 2026 sind das 13,90 Euro pro Stunde. Eine reine Hausaufgabe liegt dazwischen.

Unabhängig von der Rechtslage: Bezahle. Es signalisiert, dass du die Zeit der Bewerber ernst nimmst, und es senkt die Absagequote bei Leuten, die gerade beschäftigt sind.

Als Orientierung für die Höhe helfen zwei Werte aus einer freelancermap-Auswertung vom September 2026. Angestellte Softwareentwickler kommen dort, auf Basis von kununu-Gehältern, umgerechnet auf etwa 29 Euro brutto pro Stunde, Freelancer im Median auf 90 Euro netto.

Spanne für eine faire Pauschale bei drei Stunden Aufwand
Untergrenze: 3 h × 29 € (Angestellten-Niveau)
87 €
Obergrenze: 3 h × 90 € (Freelancer-Median)
270 €
Sinnvolle Pauschale
zwischen 87 und 270 €

Rechenbeispiel auf Basis der freelancermap-Auswertung „Stundensatz Softwareentwickler“, September 2026.

Eine Pauschale von 150 bis 200 Euro liegt in dieser Spanne und ist für die meisten Firmen verkraftbar. Wie sich die Gesamtkosten einer Einstellung zusammensetzen, beschreibt der Beitrag Was ein Entwickler den Arbeitgeber kostet.

KI-Assistenten in der Probeaufgabe

Laut JetBrains State of PHP 2025 nutzen 80 Prozent der PHP-Entwickler regelmäßig KI-Assistenten. Ein Verbot lässt sich bei Hausaufgaben ohnehin nicht kontrollieren. Ehrlicher ist es, KI ausdrücklich zu erlauben und um einen Satz zu bitten, wofür sie genutzt wurde.

Bei der Code-Review-Aufgabe ist das weniger kritisch als bei einer Programmieraufgabe. Ein Assistent findet die SQL-Injection sofort. Ob die Person aber erklären kann, warum der Mailversand nach dem Commit stehen sollte, zeigt sich erst im Gespräch. Genau dafür gibt es das Gespräch.

Wenn du die Aufgabe einmal sauber aufgesetzt hast, kannst du sie für mehrere Runden verwenden. Ändere nur gelegentlich Details, damit Lösungen nicht im Netz kursieren. Wer keine Zeit für den Aufbau hat, kann die technische Bewertung auch extern einholen, etwa bei einem Studio wie OnlineBuilders, das selbst PHP-Anwendungen entwickelt und betreibt.

Kopiere als Nächstes die Aufgabe in ein privates Repository, lass ein Teammitglied sie in 90 Minuten lösen und miss, ob das Raster zu seinen Ergebnissen passt. Danach erst schickst du sie an Kandidaten, zusammen mit der Info aus deiner Stellenanzeige, wie lange der ganze Prozess dauert.

Häufige Fragen

Muss ich eine Probeaufgabe bezahlen?

Eine Hausaufgabe, die nur der Einschätzung dient und nicht verwertet wird, muss rechtlich nicht zwingend bezahlt werden. Sobald du das Ergebnis produktiv nutzt oder jemand im Betrieb mitarbeitet, sieht das anders aus, dann greift mindestens der Mindestlohn. Fair ist eine Pauschale in jedem Fall.

Darf ich die Lösung der Probeaufgabe weiterverwenden?

Nein, und das solltest du auch nicht wollen. Die Rechte am Code liegen bei der Person, die ihn geschrieben hat. Wähle die Aufgabe so, dass niemand auf den Gedanken kommt, du ließest kostenlos Features bauen.

Was tun, wenn ein Kandidat die Probeaufgabe ablehnt?

Biete eine Alternative an, etwa ein Code-Beispiel aus einem früheren Projekt oder ein öffentliches Repository, über das ihr im Gespräch sprecht. Erfahrene Entwickler mit mehreren Angeboten lehnen lange Hausaufgaben häufig ab. Eine kurze, bezahlte Aufgabe akzeptieren die meisten.

Live-Coding oder Hausaufgabe?

Für PHP-Webentwicklung liefert eine Hausaufgabe mit anschließender Besprechung die realistischeren Ergebnisse. Live-Coding unter Beobachtung misst vor allem, wie jemand mit Stress umgeht. Ein Mittelweg ist gemeinsames Code-Review am Bildschirm.