Skip to content

PHP Tutorial PHP Interview and Practice Challenge

Coding Challenges

Lesson 367 of 369 2 min read By Deepak Paswan Updated Oct 5, 2026

Solve each challenge before you open the solution. Then compare, and think about edge cases.

Challenge 1: palindrome

Write isPalindrome(string $text): bool that ignores case, spaces and punctuation. "A man, a plan, a canal: Panama" should be true.

Show a possible solution
index.php
PHP
<?php
function isPalindrome(string $text): bool
{
    $clean = preg_replace('/[^a-z0-9]/', "", strtolower($text)) ?? "";

    return $clean !== "" && $clean === strrev($clean);
}

var_dump(isPalindrome("A man, a plan, a canal: Panama"));
var_dump(isPalindrome("Hello"));
var_dump(isPalindrome("   "));
Output
OUTPUT
bool(true)
bool(false)
bool(false)

Challenge 2: anagrams

Write areAnagrams(string $a, string $b): bool.

Show a possible solution
index.php
PHP
<?php
function areAnagrams(string $a, string $b): bool
{
    $normalise = function (string $s): array {
        $letters = str_split(strtolower(preg_replace('/\s+/', "", $s) ?? ""));
        sort($letters);

        return $letters;
    };

    return $normalise($a) === $normalise($b);
}

var_dump(areAnagrams("Listen", "Silent"));
var_dump(areAnagrams("Hello", "World"));
Output
OUTPUT
bool(true)
bool(false)

Challenge 3: word frequency

Return the three most common words of a text (ignore case and punctuation). Break ties alphabetically.

Show a possible solution
index.php
PHP
<?php
function topWords(string $text, int $limit = 3): array
{
    preg_match_all('/[a-z0-9\']+/', strtolower($text), $m);

    $counts = array_count_values($m[0]);

    uksort($counts, fn($a, $b) => $counts[$b] <=> $counts[$a] ?: strcmp($a, $b));

    return array_slice($counts, 0, $limit, true);
}

print_r(topWords("The cat and the hat and the bat. The end!"));
Output
OUTPUT
Array
(
    [the] => 4
    [and] => 2
    [bat] => 1
)

Challenge 4: flatten a nested array

Write flatten(array $data): array for any depth.

Show a possible solution
index.php
PHP
<?php
function flatten(array $data): array
{
    $result = [];

    array_walk_recursive($data, function ($value) use (&$result) {
        $result[] = $value;
    });

    return $result;
}

echo implode(",", flatten([1, [2, [3, [4]], 5], [[6]]]));
Output
OUTPUT
1,2,3,4,5,6

Challenge 5: two numbers that sum to a target

Given an array and a target, return the positions of two numbers that add up to it, in one pass.

Show a possible solution
index.php
PHP
<?php
function twoSum(array $numbers, int $target): ?array
{
    $seen = [];

    foreach ($numbers as $i => $n) {
        $need = $target - $n;

        if (isset($seen[$need])) {
            return [$seen[$need], $i];
        }

        $seen[$n] = $i;
    }

    return null;
}

echo json_encode(twoSum([2, 7, 11, 15], 9)) . " ";
var_dump(twoSum([1, 2, 3], 100));
Output
OUTPUT
[0,1] NULL

The array $seen is a hash lookup, so the whole search takes one pass instead of two nested loops.

Challenge 6: a small validator function

Write validate(array $data, array $rules): array where rules are "required", "email" and "min:N". Return an array of errors.

Show a possible solution
index.php
PHP
<?php
function validate(array $data, array $rules): array
{
    $errors = [];

    foreach ($rules as $field => $list) {
        $value = trim((string) ($data[$field] ?? ""));

        foreach ($list as $rule) {
            if ($rule === "required" && $value === "") {
                $errors[$field] = "$field is required";
            } elseif ($rule === "email" && $value !== "" && !filter_var($value, FILTER_VALIDATE_EMAIL)) {
                $errors[$field] = "$field must be an email";
            } elseif (str_starts_with($rule, "min:") && $value !== "" && mb_strlen($value) < (int) substr($rule, 4)) {
                $errors[$field] = "$field is too short";
            }

            if (isset($errors[$field])) {
                break;
            }
        }
    }

    return $errors;
}

print_r(validate(["name" => "A", "email" => "x"], ["name" => ["required", "min:2"], "email" => ["required", "email"], "age" => ["required"]]));
Output
OUTPUT
Array
(
    [name] => name is too short
    [email] => email must be an email
    [age] => age is required
)

Challenge 7: bank account class

Create Account with deposit(), withdraw() and a balance(). Withdrawing more than the balance throws an exception. Deposits must be positive.

Show a possible solution
index.php
PHP
<?php
final class Account
{
    private int $cents = 0;

    public function deposit(int $cents): void
    {
        if ($cents <= 0) {
            throw new InvalidArgumentException("Deposit must be positive.");
        }

        $this->cents += $cents;
    }

    public function withdraw(int $cents): void
    {
        if ($cents > $this->cents) {
            throw new RuntimeException("Insufficient funds.");
        }

        $this->cents -= $cents;
    }

    public function balance(): string
    {
        return number_format($this->cents / 100, 2);
    }
}

$a = new Account();
$a->deposit(10050);

try {
    $a->withdraw(20000);
} catch (RuntimeException $e) {
    echo $e->getMessage() . " ";
}

echo $a->balance();
Output
OUTPUT
Insufficient funds. 100.50

Money is stored as integer cents, not floats.

Challenge 8: FizzBuzz with match

Print 1 to 15 on one line, separated by spaces, using match(true).

Show a possible solution
index.php
PHP
<?php
$out = [];

foreach (range(1, 15) as $n) {
    $out[] = match (true) {
        $n % 15 === 0 => "FizzBuzz",
        $n % 3 === 0 => "Fizz",
        $n % 5 === 0 => "Buzz",
        default => (string) $n,
    };
}

echo implode(" ", $out);
Output
OUTPUT
1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz