Skip to content

Functions

Overview

Functions are reusable blocks of code that perform specific tasks. They help organize code, reduce repetition, and make programs easier to maintain. This chapter covers function definitions, parameters, return values, scope, and advanced function concepts in PHP.

Basic Function Definition

Simple Functions

php
<?php
// Basic function definition
function greet() {
    echo "Hello, World!";
}

// Calling a function
greet(); // Output: Hello, World!

// Function with return value
function getMessage() {
    return "Greetings from function!";
}

$message = getMessage();
echo $message; // Output: Greetings from function!

// Simple calculation function
function addNumbers() {
    $a = 5;
    $b = 3;
    return $a + $b;
}

echo addNumbers(); // Output: 8
?>

Functions with Parameters

php
<?php
// Function with single parameter
function greetUser($name) {
    return "Hello, $name!";
}

echo greetUser("Alice"); // Output: Hello, Alice!

// Function with multiple parameters
function addTwoNumbers($a, $b) {
    return $a + $b;
}

echo addTwoNumbers(5, 3); // Output: 8

// Function with type hints (PHP 7+)
function multiply(int $a, int $b): int {
    return $a * $b;
}

echo multiply(4, 5); // Output: 20

// Function with mixed parameter types
function formatMessage(string $name, int $age, bool $isActive): string {
    $status = $isActive ? "active" : "inactive";
    return "User: $name, Age: $age, Status: $status";
}

echo formatMessage("Xiaoming", 30, true);
// Output: User: Xiaoming, Age: 30, Status: active
?>

Default Parameters

Basic Default Values

php
<?php
// Function with default parameter
function greetWithDefault($name = "Guest") {
    return "Hello, $name!";
}

echo greetWithDefault();        // Output: Hello, Guest!
echo greetWithDefault("Alice"); // Output: Hello, Alice!

// Multiple default parameters
function createUser($name, $role = "user", $active = true) {
    return [
        'name' => $name,
        'role' => $role,
        'active' => $active
    ];
}

$user1 = createUser("Xiaoming");
$user2 = createUser("Xiaohong", "admin");
$user3 = createUser("Xiaoqiang", "moderator", false);

print_r($user1); // ['name' => 'Xiaoming', 'role' => 'user', 'active' => true]
print_r($user2); // ['name' => 'Xiaohong', 'role' => 'admin', 'active' => true]
print_r($user3); // ['name' => 'Xiaoqiang', 'role' => 'moderator', 'active' => false]
?>

Advanced Default Parameters

php
<?php
// Default parameter with expression (PHP 5.6+)
function logMessage($message, $timestamp = null, $level = "INFO") {
    if ($timestamp === null) {
        $timestamp = date('Y-m-d H:i:s');
    }
    
    return "[$timestamp] [$level] $message";
}

echo logMessage("Application started");
echo logMessage("Error occurred", null, "ERROR");
echo logMessage("Custom time", "2023-01-01 12:00:00", "DEBUG");

// Default parameter with function call
function getDefaultConfig() {
    return ['theme' => 'light', 'language' => 'en'];
}

function initializeApp($config = null) {
    if ($config === null) {
        $config = getDefaultConfig();
    }
    
    return "Application initialized, theme: {$config['theme']}";
}

echo initializeApp();
echo initializeApp(['theme' => 'dark', 'language' => 'en']);
?>

Variable-Length Arguments

Using func_get_args()

php
<?php
// Variable number of arguments (old way)
function sum() {
    $args = func_get_args();
    $total = 0;
    
    foreach ($args as $arg) {
        $total += $arg;
    }
    
    return $total;
}

echo sum(1, 2, 3);        // Output: 6
echo sum(1, 2, 3, 4, 5);  // Output: 15

// Get specific arguments
function processArgs() {
    $numArgs = func_num_args();
    echo "Number of arguments: $numArgs\n";
    
    for ($i = 0; $i < $numArgs; $i++) {
        $arg = func_get_arg($i);
        echo "Argument $i: $arg\n";
    }
}

processArgs("Hello", 42, true);
?>

Variadic Functions (PHP 5.6+)

php
<?php
// Variadic function using ... operator
function sumVariadic(...$numbers) {
    $total = 0;
    foreach ($numbers as $number) {
        $total += $number;
    }
    return $total;
}

echo sumVariadic(1, 2, 3);        // Output: 6
echo sumVariadic(1, 2, 3, 4, 5);  // Output: 15

// Mixed parameters with variadic
function formatList($separator, ...$items) {
    return implode($separator, $items);
}

echo formatList(", ", "apple", "banana", "orange");
// Output: apple, banana, orange

// Variadic with type hints
function calculateAverage(float ...$numbers): float {
    if (empty($numbers)) {
        return 0.0;
    }
    
    return array_sum($numbers) / count($numbers);
}

echo calculateAverage(10.5, 20.3, 15.7); // Output: 15.5

// Unpacking array as function arguments
$numbers = [1, 2, 3, 4, 5];
echo sumVariadic(...$numbers); // Output: 15
?>

Return Values

Single Return Value

php
<?php
// Different return types
function getInteger(): int {
    return 42;
}

function getString(): string {
    return "Hello, World!";
}

function getArray(): array {
    return [1, 2, 3, 4, 5];
}

function getBoolean(): bool {
    return true;
}

// Conditional return
function checkAge($age) {
    if ($age >= 18) {
        return "Adult";
    } elseif ($age >= 13) {
        return "Teenager";
    } else {
        return "Child";
    }
}

echo checkAge(25); // Output: Adult
echo checkAge(16); // Output: Teenager
echo checkAge(10); // Output: Child
?>

Multiple Return Values

php
<?php
// Returning array for multiple values
function getNameAndAge() {
    return ["Zhang San", 30];
}

list($name, $age) = getNameAndAge();
echo "Name: $name, Age: $age";

// Returning associative array
function getUserInfo() {
    return [
        'name' => 'Li Si',
        'email' => 'lisi@example.com',
        'age' => 25
    ];
}

$user = getUserInfo();
echo "Name: {$user['name']}, Email: {$user['email']}";

// Array destructuring (PHP 7.1+)
['name' => $userName, 'email' => $userEmail] = getUserInfo();
echo "User: $userName, Email: $userEmail";

// Returning object
function createUser($name, $email) {
    return (object) [
        'name' => $name,
        'email' => $email,
        'created_at' => date('Y-m-d H:i:s')
    ];
}

$user = createUser("Wang Wu", "wangwu@example.com");
echo "User: {$user->name}, Created: {$user->created_at}";
?>

Early Returns

php
<?php
// Early return for validation
function validateEmail($email) {
    if (empty($email)) {
        return false;
    }
    
    if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
        return false;
    }
    
    return true;
}

// Guard clauses
function processUser($user) {
    if (!$user) {
        return "User not found";
    }
    
    if (!$user['active']) {
        return "User is inactive";
    }
    
    if (!$user['verified']) {
        return "User is not verified";
    }
    
    // Main processing logic
    return "User processed successfully";
}

// Multiple exit points
function divide($a, $b) {
    if ($b === 0) {
        return null; // or throw exception
    }
    
    return $a / $b;
}

$result = divide(10, 2);
if ($result !== null) {
    echo "Result: $result";
} else {
    echo "Division by zero error";
}
?>

Variable Scope

Local and Global Scope

php
<?php
$globalVar = "I am a global variable";

function testScope() {
    $localVar = "I am a local variable";
    echo $localVar; // Works fine
    
    // This won't work without global keyword
    // echo $globalVar; // Undefined variable error
    
    // Access global variable
    global $globalVar;
    echo $globalVar; // Now it works
}

testScope();

// Using $GLOBALS superglobal
function testGlobals() {
    echo $GLOBALS['globalVar']; // Alternative way to access global variable
}

testGlobals();

// Modifying global variable
$counter = 0;

function incrementCounter() {
    global $counter;
    $counter++;
}

incrementCounter();
incrementCounter();
echo $counter; // Output: 2
?>

Static Variables

php
<?php
// Static variables retain their value between function calls
function countCalls() {
    static $count = 0;
    $count++;
    echo "Function called $count times\n";
}

countCalls(); // Function called 1 times
countCalls(); // Function called 2 times
countCalls(); // Function called 3 times

// Static variable with initialization
function generateId() {
    static $id = 1000;
    return ++$id;
}

echo generateId(); // 1001
echo generateId(); // 1002
echo generateId(); // 1003

// Multiple static variables
function processData($data) {
    static $totalProcessed = 0;
    static $errors = 0;
    
    $totalProcessed++;
    
    if (empty($data)) {
        $errors++;
        echo "Data processing error. Total errors: $errors\n";
        return false;
    }
    
    echo "Data processed. Total processed: $totalProcessed\n";
    return true;
}

processData("valid data");
processData("");
processData("more data");
?>

Anonymous Functions (Closures)

Basic Anonymous Functions

php
<?php
// Anonymous function assigned to variable
$greet = function($name) {
    return "Hello, $name!";
};

echo $greet("Alice"); // Output: Hello, Alice!

// Anonymous function as callback
$numbers = [1, 2, 3, 4, 5];

$squared = array_map(function($n) {
    return $n * $n;
}, $numbers);

print_r($squared); // [1, 4, 9, 16, 25]

// Using anonymous function for filtering
$evenNumbers = array_filter($numbers, function($n) {
    return $n % 2 === 0;
});

print_r($evenNumbers); // [2, 4]
?>

Closures with use Keyword

php
<?php
// Closure inheriting variables from parent scope
$multiplier = 3;

$multiply = function($number) use ($multiplier) {
    return $number * $multiplier;
};

echo $multiply(5); // Output: 15

// Multiple variables in use clause
$prefix = "Result: ";
$suffix = " (calculated)";

$format = function($value) use ($prefix, $suffix) {
    return $prefix . $value . $suffix;
};

echo $format(42); // Output: Result: 42 (calculated)

// Modifying variable by reference
$counter = 0;

$increment = function() use (&$counter) {
    $counter++;
    echo "Counter: $counter\n";
};

$increment(); // Counter: 1
$increment(); // Counter: 2
echo $counter; // 2 (modified by closure)
?>

Arrow Functions (PHP 7.4+)

php
<?php
// Arrow functions - simplified syntax for simple closures
$numbers = [1, 2, 3, 4, 5];

// Traditional anonymous function
$doubled1 = array_map(function($n) { return $n * 2; }, $numbers);

// Arrow function (more concise)
$doubled2 = array_map(fn($n) => $n * 2, $numbers);

print_r($doubled2); // [2, 4, 6, 8, 10]

// Arrow function automatically captures variables
$multiplier = 3;
$tripled = array_map(fn($n) => $n * $multiplier, $numbers);

print_r($tripled); // [3, 6, 9, 12, 15]

// More complex arrow function
$users = [
    ['name' => 'Xiaoming', 'age' => 30],
    ['name' => 'Xiaohong', 'age' => 25],
    ['name' => 'Xiaoqiang', 'age' => 35]
];

$names = array_map(fn($user) => $user['name'], $users);
$adults = array_filter($users, fn($user) => $user['age'] >= 18);

print_r($names); // ['Xiaoming', 'Xiaohong', 'Xiaoqiang']
print_r($adults); // All users (all are adults)
?>

Higher-Order Functions

Functions as Parameters

php
<?php
// Function that accepts another function as parameter
function processArray($array, $callback) {
    $result = [];
    foreach ($array as $item) {
        $result[] = $callback($item);
    }
    return $result;
}

// Different callback functions
function double($n) {
    return $n * 2;
}

function square($n) {
    return $n * $n;
}

$numbers = [1, 2, 3, 4, 5];

$doubled = processArray($numbers, 'double');
$squared = processArray($numbers, 'square');

print_r($doubled); // [2, 4, 6, 8, 10]
print_r($squared); // [1, 4, 9, 16, 25]

// Using anonymous function
$cubed = processArray($numbers, function($n) {
    return $n * $n * $n;
});

print_r($cubed); // [1, 8, 27, 64, 125]
?>

Functions Returning Functions

php
<?php
// Function that returns another function
function createMultiplier($factor) {
    return function($number) use ($factor) {
        return $number * $factor;
    };
}

$double = createMultiplier(2);
$triple = createMultiplier(3);

echo $double(5); // Output: 10
echo $triple(5); // Output: 15

// More complex example: creating validators
function createValidator($rules) {
    return function($data) use ($rules) {
        $errors = [];
        
        foreach ($rules as $field => $rule) {
            if ($rule === 'required' && empty($data[$field])) {
                $errors[] = "$field is required";
            }
            
            if ($rule === 'email' && !filter_var($data[$field], FILTER_VALIDATE_EMAIL)) {
                $errors[] = "$field must be a valid email";
            }
        }
        
        return $errors;
    };
}

$userValidator = createValidator([
    'name' => 'required',
    'email' => 'email'
]);

$errors = $userValidator(['name' => '', 'email' => 'invalid-email']);
print_r($errors); // ['name is required', 'email must be a valid email']
?>

Built-in Functions

String Functions

php
<?php
// Common string functions
$text = "Hello, World!";

echo strlen($text);           // 13 (length)
echo strtoupper($text);       // "HELLO, WORLD!"
echo strtolower($text);       // "hello, world!"
echo ucfirst($text);          // "Hello, world!"
echo ucwords($text);          // "Hello, World!"

// String manipulation
$name = "  John Doe  ";
echo trim($name);             // "John Doe" (remove whitespace)
echo ltrim($name);            // "John Doe  " (remove left whitespace)
echo rtrim($name);            // "  John Doe" (remove right whitespace)

// String searching and replacement
$sentence = "The quick brown fox jumps over the lazy dog";
echo strpos($sentence, "fox");        // 16 (position of "fox")
echo str_replace("fox", "cat", $sentence); // Replace "fox" with "cat"
echo substr($sentence, 0, 9);         // "The quick" (substring)

// String splitting and joining
$words = explode(" ", $sentence);     // Split into array
$rejoined = implode("-", $words);     // Join with hyphens
?>

Array Functions

php
<?php
$numbers = [3, 1, 4, 1, 5, 9, 2, 6];

// Array information
echo count($numbers);         // 8 (number of elements)
echo array_sum($numbers);     // 31 (sum of all elements)
echo max($numbers);           // 9 (maximum value)
echo min($numbers);           // 1 (minimum value)

// Array manipulation
sort($numbers);               // Sort in ascending order
rsort($numbers);              // Sort in descending order
shuffle($numbers);            // Randomize order

// Array searching
$position = array_search(5, $numbers);  // Find position of value 5
$exists = in_array(4, $numbers);        // Check if value exists

// Array filtering and mapping
$evens = array_filter($numbers, function($n) {
    return $n % 2 === 0;
});

$doubled = array_map(function($n) {
    return $n * 2;
}, $numbers);

// Array merging and slicing
$moreNumbers = [7, 8, 9];
$combined = array_merge($numbers, $moreNumbers);
$slice = array_slice($numbers, 2, 3);  // Get 3 elements starting at index 2
?>

Math Functions

php
<?php
// Basic math functions
echo abs(-5);           // 5 (absolute value)
echo round(3.7);        // 4 (round to nearest integer)
echo floor(3.7);        // 3 (round down)
echo ceil(3.2);         // 4 (round up)

// Power and root functions
echo pow(2, 3);         // 8 (2 to the power of 3)
echo sqrt(16);          // 4 (square root)

// Random numbers
echo rand(1, 10);       // Random integer between 1 and 10
echo mt_rand(1, 100);   // Better random number generator

// Trigonometric functions
echo sin(M_PI / 2);     // 1 (sine of 90 degrees in radians)
echo cos(0);            // 1 (cosine of 0 degrees)

// Number formatting
echo number_format(1234.567, 2);        // "1,234.57"
echo number_format(1234567, 0, '.', ','); // "1,234,567"
?>

Function Best Practices

Single Responsibility Principle

php
<?php
// Bad: Function doing too many things
function processUserBad($userData) {
    // Validate data
    if (empty($userData['email'])) {
        return false;
    }
    
    // Hash password
    $userData['password'] = password_hash($userData['password'], PASSWORD_DEFAULT);
    
    // Save to database
    // ... database code ...
    
    // Send welcome email
    // ... email code ...
    
    return true;
}

// Good: Separate functions for each responsibility
function validateUserData($userData) {
    $errors = [];
    
    if (empty($userData['email'])) {
        $errors[] = 'Email is required';
    }
    
    if (empty($userData['password'])) {
        $errors[] = 'Password is required';
    }
    
    return $errors;
}

function hashPassword($password) {
    return password_hash($password, PASSWORD_DEFAULT);
}

function saveUser($userData) {
    // Database save logic
    return true; // or user ID
}

function sendWelcomeEmail($userEmail) {
    // Email sending logic
    return true;
}

// Main function orchestrates the process
function processUser($userData) {
    $errors = validateUserData($userData);
    if (!empty($errors)) {
        return ['success' => false, 'errors' => $errors];
    }
    
    $userData['password'] = hashPassword($userData['password']);
    $userId = saveUser($userData);
    
    if ($userId) {
        sendWelcomeEmail($userData['email']);
        return ['success' => true, 'user_id' => $userId];
    }
    
    return ['success' => false, 'errors' => ['Failed to save user']];
}
?>

Input Validation and Error Handling

php
<?php
// Function with proper input validation
function calculateBMI($weight, $height) {
    // Validate input types
    if (!is_numeric($weight) || !is_numeric($height)) {
        throw new InvalidArgumentException('Weight and height must be numeric');
    }
    
    // Validate input ranges
    if ($weight <= 0) {
        throw new InvalidArgumentException('Weight must be positive');
    }
    
    if ($height <= 0) {
        throw new InvalidArgumentException('Height must be positive');
    }
    
    // Convert height to meters if it seems to be in centimeters
    if ($height > 3) {
        $height = $height / 100;
    }
    
    $bmi = $weight / ($height * $height);
    
    return round($bmi, 2);
}

// Usage with error handling
try {
    $bmi = calculateBMI(70, 1.75);
    echo "BMI: $bmi";
} catch (InvalidArgumentException $e) {
    echo "Error: " . $e->getMessage();
}

// Function with optional error handling
function safeDivide($a, $b, &$error = null) {
    if ($b === 0) {
        $error = "Division by zero";
        return null;
    }
    
    return $a / $b;
}

$error = null;
$result = safeDivide(10, 0, $error);

if ($error) {
    echo "Error: $error";
} else {
    echo "Result: $result";
}
?>

Documentation and Type Hints

php
<?php
/**
 * Calculates the distance between two geographic points
 * 
 * @param float $lat1 Latitude of first point
 * @param float $lon1 Longitude of first point
 * @param float $lat2 Latitude of second point
 * @param float $lon2 Longitude of second point
 * @param string $unit Unit of measurement ('km' or 'miles')
 * @return float Distance between points
 * @throws InvalidArgumentException If coordinates are invalid
 */
function calculateDistance(
    float $lat1, 
    float $lon1, 
    float $lat2, 
    float $lon2, 
    string $unit = 'km'
): float {
    // Validate coordinates
    if ($lat1 < -90 || $lat1 > 90 || $lat2 < -90 || $lat2 > 90) {
        throw new InvalidArgumentException('Latitude must be between -90 and 90');
    }
    
    if ($lon1 < -180 || $lon1 > 180 || $lon2 < -180 || $lon2 > 180) {
        throw new InvalidArgumentException('Longitude must be between -180 and 180');
    }
    
    // Haversine formula
    $earthRadius = ($unit === 'miles') ? 3959 : 6371;
    
    $dLat = deg2rad($lat2 - $lat1);
    $dLon = deg2rad($lon2 - $lon1);
    
    $a = sin($dLat / 2) * sin($dLat / 2) +
         cos(deg2rad($lat1)) * cos(deg2rad($lat2)) *
         sin($dLon / 2) * sin($dLon / 2);
    
    $c = 2 * atan2(sqrt($a), sqrt(1 - $a));
    
    return $earthRadius * $c;
}

// Usage
$distance = calculateDistance(40.7128, -74.0060, 34.0522, -118.2437, 'miles');
echo "Distance: " . number_format($distance, 2) . " miles";
?>

Next Steps

Now that you understand functions, let's explore arrays and objects in more detail in Arrays and Objects.

Practice Exercises

  1. Create a utility function library for string operations
  2. Build a calculator using functions with different operations
  3. Implement a validation system using higher-order functions
  4. Create functions for array processing (sorting, filtering, transforming)
  5. Build a simple templating system using closures

Functions are the fundamental building blocks of well-organized PHP applications!

Content is for learning and research only.