Introduction to Control Structures
Control structures are the decision-makers and traffic directors of programming. They determine the flow of execution in your code - which statements run, when they run, and how many times they run.
Think of control structures as the traffic signals and road signs in a city. Without them, traffic would be chaotic and unpredictable. Similarly, control structures bring order and predictability to your PHP code.
In this lecture, we'll explore how PHP implements these essential programming constructs and how they can be used to create dynamic, responsive web applications.
Conditional Statements
Conditional statements allow your code to make decisions based on certain conditions. They're like the forks in a road - directing your program down different paths based on certain criteria.
The if Statement
The simplest form of decision making uses the if statement, which executes a block of code only when a condition evaluates to true.
<?php
$age = 25;
if ($age >= 18) {
echo "You are an adult.";
}
?>
Real-world application: Displaying age-restricted content on a website only to users who meet the age requirement.
if-else Statement
When you need to handle two alternative cases, use an if-else statement:
<?php
$temperature = 15;
if ($temperature > 20) {
echo "It's warm outside.";
} else {
echo "It's cool outside.";
}
?>
Real-world application: Recommending products based on weather conditions - summer clothes when it's warm, winter clothes when it's cool.
if-elseif-else Chain
For multiple alternative conditions, PHP provides the elseif clause:
<?php
$score = 85;
if ($score >= 90) {
$grade = "A";
} elseif ($score >= 80) {
$grade = "B";
} elseif ($score >= 70) {
$grade = "C";
} elseif ($score >= 60) {
$grade = "D";
} else {
$grade = "F";
}
echo "Your grade is $grade";
?>
Real-world application: An e-commerce site showing different shipping options based on the total order value.
Switch Statement
When comparing a single variable against multiple possible values, the switch statement offers a cleaner alternative to multiple if-elseif checks:
<?php
$dayOfWeek = date("l"); // Returns current day name (e.g., "Monday")
switch ($dayOfWeek) {
case "Monday":
echo "Start of the work week.";
break;
case "Tuesday":
case "Wednesday":
case "Thursday":
echo "Middle of the work week.";
break;
case "Friday":
echo "End of the work week.";
break;
case "Saturday":
case "Sunday":
echo "Weekend!";
break;
default:
echo "Invalid day.";
break;
}
?>
Notice how the break statement is used to prevent "fall-through" to the next case. Without it, execution would continue to the next case regardless of the match.
Real-world application: Displaying different menus or specials in a restaurant's website based on the day of the week.
Ternary Operator
For simple conditional assignments, PHP offers the ternary operator as a compact alternative:
<?php
$age = 20;
// Long form
if ($age >= 18) {
$status = "adult";
} else {
$status = "minor";
}
// Same thing using ternary operator
$status = ($age >= 18) ? "adult" : "minor";
echo "You are a $status.";
?>
Real-world application: Assigning different CSS classes to elements based on user status (premium vs. free user).
Null Coalescing Operator
PHP 7 introduced the null coalescing operator (??), which is especially useful for setting default values for potentially undefined variables:
<?php
// Traditional approach
$username = isset($_GET['user']) ? $_GET['user'] : 'Guest';
// Using null coalescing operator
$username = $_GET['user'] ?? 'Guest';
echo "Hello, $username!";
?>
Real-world application: Handling form submissions where some fields might be optional.
Looping Structures
Loops allow you to execute a block of code repeatedly. They're like assembly lines in a factory, processing items one after another until the job is done.
While Loop
A while loop continues executing as long as its condition evaluates to true:
<?php
$counter = 1;
while ($counter <= 5) {
echo "Iteration $counter<br>";
$counter++;
}
?>
Real-world application: Displaying a live count of active users on a website, updating as long as the user remains on the page.
Do-While Loop
Similar to a while loop, but guarantees that the code block executes at least once, as the condition is checked after execution:
<?php
$counter = 1;
do {
echo "Iteration $counter<br>";
$counter++;
} while ($counter <= 5);
?>
Real-world application: Processing user input in a form where at least one submission attempt must be made before validation.
For Loop
When you know exactly how many times you want to execute a block of code, the for loop is often the best choice:
<?php
for ($i = 1; $i <= 5; $i++) {
echo "Iteration $i<br>";
}
?>
The for loop combines three expressions in one line:
- Initialization:
$i = 1(executed once at the beginning) - Condition:
$i <= 5(checked before each iteration) - Increment:
$i++(executed after each iteration)
Real-world application: Generating pagination links for search results or blog posts.
Foreach Loop
The foreach loop is specially designed for iterating over arrays and objects. It's one of PHP's most used loops for web applications:
<?php
$fruits = ["apple", "banana", "cherry", "date"];
// Basic foreach loop
foreach ($fruits as $fruit) {
echo "I like $fruit<br>";
}
// Associative array with foreach
$person = [
"name" => "John Doe",
"age" => 30,
"occupation" => "Web Developer",
"city" => "New York"
];
foreach ($person as $key => $value) {
echo "$key: $value<br>";
}
?>
Real-world application: Displaying product details in an e-commerce website, or rendering a list of user comments on a blog post.
Loop Control Statements
PHP provides keywords to alter the normal flow of loops:
break: Exits the loop completelycontinue: Skips the current iteration and moves to the next
<?php
// Using break to exit a loop early
for ($i = 1; $i <= 10; $i++) {
if ($i > 5) {
echo "Breaking the loop at $i<br>";
break;
}
echo "Iteration $i<br>";
}
// Using continue to skip specific iterations
for ($i = 1; $i <= 10; $i++) {
if ($i % 2 == 0) {
continue; // Skip even numbers
}
echo "Odd number: $i<br>";
}
?>
Real-world application: In a product listing, using continue to skip out-of-stock items, or using break to exit a search once the first matching result is found.
PHP Functions
Functions are self-contained blocks of code designed to perform specific tasks. They are the building blocks of modular programming, allowing you to organize your code into reusable units.
Think of functions as specialized tools in a workshop - each designed for a particular job, making your work more efficient and your code more maintainable.
Defining Functions
In PHP, we define functions using the function keyword:
<?php
// Basic function definition
function sayHello() {
echo "Hello, World!";
}
// Function with a docblock comment
/**
* Calculate the area of a rectangle
*
* @param float $length The length of the rectangle
* @param float $width The width of the rectangle
* @return float The area of the rectangle
*/
function calculateArea($length, $width) {
return $length * $width;
}
?>
Docblock comments provide documentation for your functions, describing their purpose, parameters, and return values. They're especially useful in larger projects and when working with teams.
Calling Functions
To execute a function, you call it by name with parentheses:
<?php
// Calling a function without parameters
sayHello(); // Output: Hello, World!
// Calling a function with parameters
$area = calculateArea(5, 3);
echo "The area is: $area"; // Output: The area is: 15
?>
Parameters and Arguments
Functions become much more powerful when they can accept input:
<?php
// Function with parameters
function greet($name, $time = "day") {
echo "Good $time, $name!";
}
greet("Alice"); // Output: Good day, Alice!
greet("Bob", "evening"); // Output: Good evening, Bob!
?>
Real-world application: A product pricing function that calculates final cost based on parameters like base price, tax rate, and discount percentage.
Default Parameter Values
You can assign default values to parameters, making them optional:
<?php
function setConnectionTimeout($seconds = 30) {
echo "Connection timeout set to $seconds seconds";
}
setConnectionTimeout(); // Output: Connection timeout set to 30 seconds
setConnectionTimeout(60); // Output: Connection timeout set to 60 seconds
?>
Real-world application: Functions that configure system settings, with sensible defaults for common scenarios but customizable for specific needs.
Return Values
Functions can process data and return results using the return statement:
<?php
function calculateTax($amount, $taxRate = 0.1) {
$taxAmount = $amount * $taxRate;
return $taxAmount;
}
$price = 100;
$tax = calculateTax($price);
$total = $price + $tax;
echo "Price: $$price, Tax: $$tax, Total: $$total";
// Output: Price: $100, Tax: $10, Total: $110
?>
Real-world application: Processing form inputs and returning validation results, or calculating shipping costs based on destination and weight.
Variable Scope in Functions
Understanding variable scope is crucial when working with functions in PHP:
<?php
$globalVar = "I'm global";
function testScope() {
$localVar = "I'm local";
// Using a global variable inside a function
global $globalVar;
echo $globalVar . "<br>";
// Alternatively, use the $GLOBALS array
echo $GLOBALS['globalVar'] . "<br>";
// Local variable
echo $localVar . "<br>";
}
testScope();
// This would cause an error - local variable not accessible outside function
// echo $localVar;
?>
Real-world application: Using global configuration variables within functions that process user inputs or generate website content.
Anonymous Functions
PHP supports anonymous functions (also called closures), which are functions without a specified name:
<?php
// Anonymous function assigned to a variable
$greet = function($name) {
return "Hello, $name!";
};
echo $greet("Alice"); // Output: Hello, Alice!
// Anonymous function as a callback
$numbers = [1, 2, 3, 4, 5];
$squared = array_map(function($n) {
return $n * $n;
}, $numbers);
print_r($squared); // Output: Array ( [0] => 1 [1] => 4 [2] => 9 [3] => 16 [4] => 25 )
?>
Real-world application: Event handlers in JavaScript-like code, or custom sorting and filtering functions for database results.
Arrow Functions (PHP 7.4+)
PHP 7.4 introduced arrow functions, a more concise syntax for simple anonymous functions:
<?php
// Traditional anonymous function
$traditional = function($x) {
return $x * 2;
};
// Arrow function equivalent
$arrow = fn($x) => $x * 2;
echo $traditional(5) . "<br>"; // Output: 10
echo $arrow(5) . "<br>"; // Output: 10
// Using arrow functions with array_map
$numbers = [1, 2, 3, 4, 5];
$doubled = array_map(fn($n) => $n * 2, $numbers);
print_r($doubled); // Output: Array ( [0] => 2 [1] => 4 [2] => 6 [3] => 8 [4] => 10 )
?>
Arrow functions automatically capture variables from the parent scope, making them especially useful for concise, data-processing operations.
Real-world application: Data transformations in API responses, or mapping database records to view-friendly formats.
Recursive Functions
A recursive function is one that calls itself. This can be a powerful technique for solving problems that can be broken down into simpler, similar sub-problems.
<?php
/**
* Calculate factorial using recursion
*
* @param int $n The number to calculate factorial for
* @return int The factorial result
*/
function factorial($n) {
// Base case - stop the recursion
if ($n <= 1) {
return 1;
}
// Recursive case - function calls itself
return $n * factorial($n - 1);
}
echo "5! = " . factorial(5) . "<br>"; // Output: 5! = 120
?>
The execution of factorial(5) would look like:
factorial(5)returns5 * factorial(4)factorial(4)returns4 * factorial(3)factorial(3)returns3 * factorial(2)factorial(2)returns2 * factorial(1)factorial(1)returns1(base case reached)- Then the results bubble up:
2 * 1 = 2,3 * 2 = 6,4 * 6 = 24,5 * 24 = 120
Real-world application: Parsing nested comments in a forum, traversing directory structures, or navigating hierarchical data like organizational charts.
Include and Require
PHP provides several ways to include code from other files, which is essential for creating modular, maintainable applications:
include: Includes and evaluates a file, with a warning on failurerequire: Same as include, but with a fatal error on failureinclude_once: Like include, but ensures the file is included only oncerequire_once: Like require, but ensures the file is included only once
<?php
// Including a file with functions
include 'functions.php';
// Including a required configuration file
require 'config.php';
// Including a file only if it hasn't been included before
include_once 'header.php';
// Including a critical class file only once
require_once 'Database.php';
// Using a function from the included file
$result = calculateDiscount($price, $rate);
?>
When building applications, you'll typically choose:
requirefor critical files that must be present (like configuration)includefor optional files (like additional features)require_oncefor class definitions and core librariesinclude_oncefor template parts that might be included multiple times
Real-world application: Separating header, footer, and sidebar components in a website template, or organizing related functions into separate files for better code organization.
Practical Example: Form Validation System
Let's combine various concepts we've learned into a practical example - a form validation system that processes a user registration form:
<?php
// form_validation.php
/**
* Sanitize user input to prevent XSS attacks
*
* @param string $data The input data to sanitize
* @return string The sanitized data
*/
function sanitizeInput($data) {
$data = trim($data);
$data = stripslashes($data);
$data = htmlspecialchars($data);
return $data;
}
/**
* Validate an email address
*
* @param string $email The email to validate
* @return array An array with 'valid' status and 'message'
*/
function validateEmail($email) {
$email = sanitizeInput($email);
if (empty($email)) {
return [
'valid' => false,
'message' => 'Email is required'
];
}
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
return [
'valid' => false,
'message' => 'Invalid email format'
];
}
return [
'valid' => true,
'message' => 'Email is valid',
'value' => $email
];
}
/**
* Validate a password
*
* @param string $password The password to validate
* @return array An array with 'valid' status and 'message'
*/
function validatePassword($password) {
if (empty($password)) {
return [
'valid' => false,
'message' => 'Password is required'
];
}
// Check length
if (strlen($password) < 8) {
return [
'valid' => false,
'message' => 'Password must be at least 8 characters long'
];
}
// Check for at least one uppercase letter
if (!preg_match('/[A-Z]/', $password)) {
return [
'valid' => false,
'message' => 'Password must contain at least one uppercase letter'
];
}
// Check for at least one number
if (!preg_match('/[0-9]/', $password)) {
return [
'valid' => false,
'message' => 'Password must contain at least one number'
];
}
return [
'valid' => true,
'message' => 'Password is valid'
];
}
/**
* Validate all registration form fields
*
* @param array $formData The form data to validate
* @return array Validation results
*/
function validateRegistrationForm($formData) {
$results = [
'valid' => true,
'errors' => [],
'data' => []
];
// Validate username
if (empty($formData['username'])) {
$results['valid'] = false;
$results['errors']['username'] = 'Username is required';
} else {
$username = sanitizeInput($formData['username']);
if (strlen($username) < 3) {
$results['valid'] = false;
$results['errors']['username'] = 'Username must be at least 3 characters long';
} else {
$results['data']['username'] = $username;
}
}
// Validate email
$emailValidation = validateEmail($formData['email'] ?? '');
if (!$emailValidation['valid']) {
$results['valid'] = false;
$results['errors']['email'] = $emailValidation['message'];
} else {
$results['data']['email'] = $emailValidation['value'];
}
// Validate password
$passwordValidation = validatePassword($formData['password'] ?? '');
if (!$passwordValidation['valid']) {
$results['valid'] = false;
$results['errors']['password'] = $passwordValidation['message'];
} else {
// Don't store plain password in the results
$results['data']['password_valid'] = true;
}
// Validate password confirmation
if (empty($formData['password_confirm'])) {
$results['valid'] = false;
$results['errors']['password_confirm'] = 'Password confirmation is required';
} elseif ($formData['password'] !== $formData['password_confirm']) {
$results['valid'] = false;
$results['errors']['password_confirm'] = 'Passwords do not match';
}
// Validate age
if (empty($formData['age'])) {
$results['valid'] = false;
$results['errors']['age'] = 'Age is required';
} else {
$age = filter_var($formData['age'], FILTER_VALIDATE_INT);
if ($age === false || $age < 18 || $age > 120) {
$results['valid'] = false;
$results['errors']['age'] = 'Age must be between 18 and 120';
} else {
$results['data']['age'] = $age;
}
}
return $results;
}
// Example usage:
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$validationResults = validateRegistrationForm($_POST);
if ($validationResults['valid']) {
// Registration successful
echo "<div class='success'>Registration successful!</div>";
// In a real application, we would:
// 1. Hash the password
// 2. Store the user in the database
// 3. Create a session
// 4. Redirect to a welcome page
} else {
// Display validation errors
echo "<div class='error'>Please correct the following errors:</div>";
echo "<ul>";
foreach ($validationResults['errors'] as $field => $error) {
echo "<li>$error</li>";
}
echo "</ul>";
}
}
?>
<!-- Registration Form HTML -->
<form method="post" action="">
<div>
<label for="username">Username:</label>
<input type="text" name="username" id="username" value="<?php echo $_POST['username'] ?? ''; ?>">
</div>
<div>
<label for="email">Email:</label>
<input type="email" name="email" id="email" value="<?php echo $_POST['email'] ?? ''; ?>">
</div>
<div>
<label for="password">Password:</label>
<input type="password" name="password" id="password">
</div>
<div>
<label for="password_confirm">Confirm Password:</label>
<input type="password" name="password_confirm" id="password_confirm">
</div>
<div>
<label for="age">Age:</label>
<input type="number" name="age" id="age" value="<?php echo $_POST['age'] ?? ''; ?>">
</div>
<div>
<button type="submit">Register</button>
</div>
</form>
This example demonstrates:
- Function creation and organization for specific validation tasks
- Parameter passing and return values
- Conditional logic to validate different types of data
- Using PHP's built-in validation functions
- Gathering and returning detailed error messages
- Sanitizing input for security
- Conditional processing of form submissions
In a production environment, this validation system would likely be part of a larger authentication system, perhaps implemented as a class or integrated with a framework.
Function Best Practices
As you build more complex PHP applications, following these function best practices will help you create maintainable, efficient code:
Single Responsibility Principle
Each function should do one thing and do it well. If a function is trying to do too many things, consider breaking it down into smaller, more focused functions.
<?php
// Not good - function does too much
function processUser($userData) {
// Validates data
// Creates user
// Sends welcome email
// Logs activity
// Returns success message
}
// Better - separate functions with specific responsibilities
function validateUserData($userData) { /* ... */ }
function createUser($validatedData) { /* ... */ }
function sendWelcomeEmail($user) { /* ... */ }
function logUserActivity($action, $userId) { /* ... */ }
?>
Meaningful Function Names
Choose descriptive names that clearly express what the function does. Good function names act as documentation.
<?php
// Unclear function name
function process($data) { /* ... */ }
// Clear, descriptive function name
function calculateTotalWithTax($subtotal, $taxRate) { /* ... */ }
?>
Use Type Hints (PHP 7+)
Type hints make your code more robust by specifying the expected types for parameters and return values:
<?php
// Without type hints
function calculateArea($length, $width) {
return $length * $width;
}
// With type hints (PHP 7+)
function calculateArea(float $length, float $width): float {
return $length * $width;
}
?>
Use Documentation Blocks
Document your functions with PHPDoc blocks to describe their purpose, parameters, and return values:
<?php
/**
* Calculate the monthly payment for a loan
*
* @param float $principal The loan amount
* @param float $rate The annual interest rate (decimal)
* @param int $term The loan term in months
* @return float The monthly payment amount
*/
function calculateMonthlyPayment(float $principal, float $rate, int $term): float {
$monthlyRate = $rate / 12;
$payment = $principal * $monthlyRate * pow(1 + $monthlyRate, $term) /
(pow(1 + $monthlyRate, $term) - 1);
return $payment;
}
?>
Limit Function Parameters
Functions with too many parameters become difficult to use. Consider using an array or object for complex parameter sets:
<?php
// Too many parameters
function createUser($username, $email, $password, $firstName, $lastName,
$address, $city, $state, $zipCode, $country, $phone) {
// ...
}
// Better approach
function createUser(array $userData) {
// Access parameters as $userData['username'], $userData['email'], etc.
}
// Usage
createUser([
'username' => 'jsmith',
'email' => 'john@example.com',
'password' => 'secure123',
// ...
]);
?>
Default Return Values
Provide sensible default return values, especially for error conditions:
<?php
function getUserById(int $id): ?array {
$user = /* database query */;
if ($user) {
return $user;
}
return null; // Explicit default return
}
?>
Avoid Global Variables
Instead of using global variables within functions, pass them as parameters:
<?php
// Not recommended
function updateUserStatus($userId) {
global $db;
// Use $db to update status
}
// Better approach
function updateUserStatus($userId, $db) {
// Use $db to update status
}
?>
Control Structure Best Practices
Early Returns
Use early returns to handle error cases or simple conditions at the beginning of functions, reducing nesting and improving readability:
<?php
// Deeply nested approach
function processOrder($order) {
if ($order) {
if ($order['status'] === 'pending') {
if ($order['payment'] === 'verified') {
// Process the order
return true;
} else {
return false;
}
} else {
return false;
}
} else {
return false;
}
}
// Early return approach
function processOrder($order) {
// Handle error cases first
if (!$order) {
return false;
}
if ($order['status'] !== 'pending') {
return false;
}
if ($order['payment'] !== 'verified') {
return false;
}
// Process the order
return true;
}
?>
Limit Nesting
Deep nesting of control structures makes code hard to read and maintain. Aim to keep nesting to 2-3 levels at most:
<?php
// Avoid this many levels of nesting
if ($condition1) {
if ($condition2) {
if ($condition3) {
if ($condition4) {
// Code here
}
}
}
}
// Better approach using logical operators and early returns
if (!$condition1 || !$condition2) {
return;
}
if (!$condition3) {
return;
}
if ($condition4) {
// Code here
}
?>
Alternative Syntax for Templates
PHP offers an alternative syntax for control structures that's often clearer in template files:
<!-- Using alternative syntax in a template file -->
<div class="products">
<?php if ($hasProducts): ?>
<h2>Our Products</h2>
<ul>
<?php foreach ($products as $product): ?>
<li>
<h3><?= $product['name'] ?></h3>
<p><?= $product['description'] ?></p>
<?php if ($product['on_sale']): ?>
<span class="sale">On Sale!</span>
<?php endif; ?>
</li>
<?php endforeach; ?>
</ul>
<?php else: ?>
<p>No products available.</p>
<?php endif; ?>
</div>
This alternative syntax (using if:, foreach:, endif;, endforeach;, etc.) makes template files more readable, especially when mixing HTML and PHP.
Use Guard Clauses
Guard clauses check conditions at the beginning of a function and return early if they're not met:
<?php
function sendEmail($to, $subject, $message) {
// Guard clauses
if (empty($to)) {
return 'Recipient email is required';
}
if (empty($subject)) {
return 'Subject is required';
}
if (empty($message)) {
return 'Message is required';
}
// Main function logic here
// ...
return 'Email sent successfully';
}
?>
Practice Activities
Activity 1: Temperature Converter
Create a PHP script that:
- Defines a function to convert Celsius to Fahrenheit
- Defines a function to convert Fahrenheit to Celsius
- Creates a simple form that allows users to input a temperature value and select the conversion direction
- Processes the form submission and displays the conversion result
- Includes validation to ensure the input is a valid number
- Handles edge cases (extreme temperatures, etc.)
Activity 2: Password Strength Checker
Create a PHP function that evaluates password strength based on:
- Length (minimum 8 characters)
- Contains uppercase letters
- Contains lowercase letters
- Contains numbers
- Contains special characters
The function should return a score (0-5) based on how many criteria are met, along with specific feedback on which criteria are failing. Then, create a simple form that allows users to test passwords and see their strength score.
Activity 3: Number Guessing Game
Create a PHP-based number guessing game that:
- Generates a random number between 1 and 100
- Lets the user submit guesses via a form
- Provides feedback ("higher", "lower", or "correct")
- Counts the number of attempts
- Uses session variables to maintain the random number and attempt count between form submissions
- Offers an option to restart the game with a new random number
- Displays a congratulatory message when the correct number is guessed, with feedback based on the number of attempts
Summary
In this lecture, we've covered the fundamental control structures and functions in PHP:
- Conditional statements (if, else, elseif, switch) for decision-making
- Loop structures (while, do-while, for, foreach) for repetitive tasks
- Function definition and calling, with parameters and return values
- Variable scope within functions
- Anonymous functions and arrow functions
- Recursive functions for solving problems with similar sub-problems
- Include and require for modular code organization
- Best practices for creating maintainable functions and control structures
These programming constructs are the building blocks of PHP applications, allowing you to create dynamic, responsive websites and web applications. As you continue in web development, these concepts will be used extensively in larger frameworks and applications.
Further Reading
- PHP Control Structures Documentation
- PHP Functions Documentation
- PSR-12: Extended Coding Style - PHP coding standards
- PHP The Right Way - Modern PHP best practices
- PHP Best Practices