Skip to main content

Course Progress

Loading...

Module 2: PHP Array Operators

Duration: 30 minutes
Module 2: PHP Operators

Learning Objectives

  • Master PHP operators
  • Understand operator precedence
  • Apply operators in practical scenarios
  • Write efficient expressions

Introduction to PHP Array Operators

Welcome to our session on PHP Array Operators! Arrays are one of the most versatile and powerful data structures in PHP, allowing you to store and manipulate collections of data efficiently. PHP provides specialized operators designed specifically for working with arrays, making array manipulation intuitive and powerful.

Think of array operators as tools in your programming toolbox that help you combine, compare, and modify arrays. Just as a chef combines ingredients to create a meal, PHP array operators allow you to combine and manipulate collections of data to build dynamic applications. Today, we'll explore these operators, understand how they work, and see them in action through practical examples relevant to web development.

Array Operators Overview

PHP provides several operators specifically designed for working with arrays:

+ Union == Equality === Identity != Inequality !== Non-identity += Union Assignment
Operator Name Example Result
+ Union $a + $b Union of $a and $b
== Equality $a == $b TRUE if $a and $b have the same key/value pairs
=== Identity $a === $b TRUE if $a and $b have the same key/value pairs in the same order and of the same types
!= Inequality $a != $b TRUE if $a is not equal to $b
!== Non-identity $a !== $b TRUE if $a is not identical to $b
+= Union assignment $a += $b $a is set to the union of $a and $b

Now, let's explore each of these operators in detail with examples and real-world applications.

Union Operator (+)

The union operator (+) merges two arrays together, with the values from the left array preserved when there are duplicate keys. This is different from array_merge() which adds elements with numeric keys to the end of the result.

Diagram
Array 1: [a=>1, b=>2 Array 2: [b=>3, c=>4 Union: Array1 + Array2 Result: [a=>1, b=>2, c=>4

Basic Union Operator Examples

<?php
// Simple array union with string keys
$array1 = ["a" => 1, "b" => 2];
$array2 = ["b" => 3, "c" => 4];
$union = $array1 + $array2;

echo "Array 1: ";
print_r($array1);

echo "Array 2: ";
print_r($array2);

echo "Union (Array 1 + Array 2): ";
print_r($union);
// Output: Array ( [a] => 1 [b] => 2 [c] => 4 )
// Note: Key 'b' from $array1 is preserved!

// Array union with numeric keys
$colors1 = [0 => "red", 1 => "green"];
$colors2 = [1 => "blue", 2 => "yellow"];
$all_colors = $colors1 + $colors2;

echo "Colors 1: ";
print_r($colors1);

echo "Colors 2: ";
print_r($colors2);

echo "All Colors (Colors 1 + Colors 2): ";
print_r($all_colors);
// Output: Array ( [0] => red [1] => green [2] => yellow )
// Note: Key 1 from $colors1 is preserved!

// Order matters in union operations
$reverse_colors = $colors2 + $colors1;
echo "Reverse Colors (Colors 2 + Colors 1): ";
print_r($reverse_colors);
// Output: Array ( [1] => blue [2] => yellow [0] => red )
// Note: Key 1 from $colors2 is preserved!
?>

Union vs. array_merge()

It's important to understand the difference between the union operator and the array_merge() function:

<?php
// Union vs. array_merge with string keys
$defaults = ["host" => "localhost", "port" => 3306, "user" => "root", "password" => ""];
$custom = ["host" => "example.com", "user" => "admin"];

// Using union operator
$config_union = $custom + $defaults;
echo "Union result (custom + defaults): ";
print_r($config_union);
// Output: Array ( [host] => example.com [port] => 3306 [user] => admin [password] => )

// Using array_merge function
$config_merge = array_merge($defaults, $custom);
echo "array_merge result (defaults, custom): ";
print_r($config_merge);
// Output: Array ( [host] => example.com [port] => 3306 [user] => admin [password] => )
// Note: For string keys, array_merge overwrites values from left to right

// Union vs. array_merge with numeric keys
$fruits1 = ["apple", "banana"];
$fruits2 = ["orange", "grape"];

// Using union operator
$fruits_union = $fruits1 + $fruits2;
echo "Fruits union: ";
print_r($fruits_union);
// Output: Array ( [0] => apple [1] => banana )
// Note: numeric keys from $fruits2 are not added because they exist in $fruits1

// Using array_merge function
$fruits_merge = array_merge($fruits1, $fruits2);
echo "Fruits merge: ";
print_r($fruits_merge);
// Output: Array ( [0] => apple [1] => banana [2] => orange [3] => grape )
// Note: array_merge reindexes numeric keys and appends all values
?>
Behavior Union Operator (+) array_merge()
String keys with duplicates Left array's values preserved Right array's values overwrite
Numeric keys with duplicates Left array's values preserved All values included with keys reindexed
Use case Providing defaults that won't override custom settings Combining arrays and appending numeric values

Real-World Application: Configuration System

The union operator is perfect for implementing configuration systems with defaults:

<?php
// Configuration system with defaults
class ConfigManager {
    private $default_config = [
        'database' => [
            'host' => 'localhost',
            'port' => 3306,
            'user' => 'root',
            'password' => '',
            'dbname' => 'app',
            'charset' => 'utf8mb4'
        ],
        'app' => [
            'debug' => false,
            'timezone' => 'UTC',
            'log_level' => 'error',
            'session_lifetime' => 3600
        ],
        'mail' => [
            'transport' => 'smtp',
            'host' => 'smtp.example.com',
            'port' => 587,
            'encryption' => 'tls',
            'username' => '',
            'password' => ''
        ]
    ];
    
    private $config = [];
    
    public function __construct(array $custom_config = []) {
        // Apply custom configuration on top of defaults
        $this->config = $this->mergeConfig($custom_config, $this->default_config);
    }
    
    private function mergeConfig($custom, $default) {
        $result = [];
        
        // Start with the defaults
        foreach ($default as $key => $value) {
            if (isset($custom[$key])) {
                // If it's an array, recursively merge
                if (is_array($value) && is_array($custom[$key])) {
                    $result[$key] = $this->mergeConfig($custom[$key], $value);
                } else {
                    // Otherwise use the custom value
                    $result[$key] = $custom[$key];
                }
            } else {
                // Use the default value if no custom value exists
                $result[$key] = $value;
            }
        }
        
        // Add any custom keys that don't exist in the defaults
        foreach ($custom as $key => $value) {
            if (!isset($default[$key])) {
                $result[$key] = $value;
            }
        }
        
        return $result;
    }
    
    public function get($path = null) {
        if ($path === null) {
            return $this->config;
        }
        
        $parts = explode('.', $path);
        $current = $this->config;
        
        foreach ($parts as $part) {
            if (!isset($current[$part])) {
                return null;
            }
            $current = $current[$part];
        }
        
        return $current;
    }
}

// Example usage
$custom_config = [
    'database' => [
        'host' => 'db.production.com',
        'user' => 'app_user',
        'password' => 'secure_password',
        'dbname' => 'production_db'
    ],
    'app' => [
        'debug' => true
    ]
];

$config = new ConfigManager($custom_config);

// Get database configuration
$db_config = $config->get('database');
echo "Database Configuration:<br>";
echo "Host: " . $db_config['host'] . "<br>";
echo "User: " . $db_config['user'] . "<br>";
echo "Port: " . $db_config['port'] . " (from defaults)<br>";
echo "DB Name: " . $db_config['dbname'] . "<br><br>";

// Get app configuration
echo "Debug Mode: " . ($config->get('app.debug') ? 'Enabled' : 'Disabled') . "<br>";
echo "Timezone: " . $config->get('app.timezone') . " (from defaults)<br>";
?>

Analogy: The array union operator is like having a blueprint for a house (default array) and a list of customizations (custom array). When you combine them, your customizations take precedence, but any detail not specified in your customizations will be filled in from the blueprint.

Equality and Identity Operators

PHP provides operators to compare arrays for equality (==) and identity (===). Understanding the difference between these operators is crucial for array manipulation.

Equality Operator (==)

The equality operator (==) checks if arrays have the same key/value pairs, regardless of their order or type.

Diagram
Yes No $a == $b Return true Return false Same key/value pairs?

Array Equality Examples

<?php
// Basic equality check
$array1 = ['a' => 1, 'b' => 2];
$array2 = ['b' => 2, 'a' => 1];
$result = ($array1 == $array2);
echo "Arrays are equal: " . ($result ? 'true' : 'false') . "<br>";
// Output: Arrays are equal: true
// Order doesn't matter for equality

// Type juggling in equality
$array3 = ['a' => 1, 'b' => 2];
$array4 = ['a' => '1', 'b' => '2']; // String values
$result = ($array3 == $array4);
echo "Arrays with different types are equal: " . ($result ? 'true' : 'false') . "<br>";
// Output: Arrays with different types are equal: true
// Type doesn't matter for equality

// Missing keys
$array5 = ['a' => 1, 'b' => 2, 'c' => 3];
$array6 = ['a' => 1, 'b' => 2];
$result = ($array5 == $array6);
echo "Arrays with different keys are equal: " . ($result ? 'true' : 'false') . "<br>";
// Output: Arrays with different keys are equal: false

// Nested arrays
$nested1 = ['a' => 1, 'b' => ['x' => 10, 'y' => 20]];
$nested2 = ['a' => 1, 'b' => ['x' => 10, 'y' => 20]];
$result = ($nested1 == $nested2);
echo "Nested arrays are equal: " . ($result ? 'true' : 'false') . "<br>";
// Output: Nested arrays are equal: true
?>

Identity Operator (===)

The identity operator (===) is stricter than the equality operator. It checks if arrays have the same key/value pairs in the same order with the same types.

Diagram
No Yes No Yes No Yes $a === $b Return false Return false Return false Return true Same key/value pairs? Same order? Same types?

Array Identity Examples

<?php
// Basic identity check
$array1 = ['a' => 1, 'b' => 2];
$array2 = ['a' => 1, 'b' => 2];
$result = ($array1 === $array2);
echo "Arrays are identical: " . ($result ? 'true' : 'false') . "<br>";
// Output: Arrays are identical: true

// Different order
$array3 = ['a' => 1, 'b' => 2];
$array4 = ['b' => 2, 'a' => 1];
$result = ($array3 === $array4);
echo "Arrays with different order are identical: " . ($result ? 'true' : 'false') . "<br>";
// Output: Arrays with different order are identical: false
// Order matters for identity!

// Different types
$array5 = ['a' => 1, 'b' => 2];
$array6 = ['a' => '1', 'b' => '2']; // String values
$result = ($array5 === $array6);
echo "Arrays with different types are identical: " . ($result ? 'true' : 'false') . "<br>";
// Output: Arrays with different types are identical: false
// Type matters for identity!

// Numeric arrays
$nums1 = [1, 2, 3];
$nums2 = [1, 2, 3];
$result = ($nums1 === $nums2);
echo "Numeric arrays are identical: " . ($result ? 'true' : 'false') . "<br>";
// Output: Numeric arrays are identical: true

// Same values, different keys
$assoc1 = [0 => 'a', 1 => 'b', 2 => 'c'];
$assoc2 = ['a', 'b', 'c']; // Implicitly [0 => 'a', 1 => 'b', 2 => 'c']
$result = ($assoc1 === $assoc2);
echo "Arrays with explicit/implicit keys are identical: " . ($result ? 'true' : 'false') . "<br>";
// Output: Arrays with explicit/implicit keys are identical: true
?>

Inequality (!=, <>) and Non-identity (!==) Operators

These operators are simply the negation of the equality and identity operators:

Inequality and Non-identity Examples

<?php
// Inequality operator
$array1 = ['a' => 1, 'b' => 2];
$array2 = ['a' => 1, 'c' => 3];
$result = ($array1 != $array2);
echo "Arrays are not equal: " . ($result ? 'true' : 'false') . "<br>";
// Output: Arrays are not equal: true

// Alternative inequality syntax
$result = ($array1 <> $array2);
echo "Arrays are not equal (alternative syntax): " . ($result ? 'true' : 'false') . "<br>";
// Output: Arrays are not equal (alternative syntax): true

// Non-identity operator
$array3 = ['a' => 1, 'b' => 2];
$array4 = ['a' => '1', 'b' => '2']; // String values
$result = ($array3 !== $array4);
echo "Arrays are not identical: " . ($result ? 'true' : 'false') . "<br>";
// Output: Arrays are not identical: true
?>

Real-World Application: Form Validation

Array comparison operators are useful for form validation and error detection:

<?php
// Form validation class
class FormValidator {
    private $required_fields = [];
    private $data = [];
    private $errors = [];
    
    public function __construct(array $required_fields = []) {
        $this->required_fields = $required_fields;
    }
    
    public function validate(array $data) {
        $this->data = $data;
        $this->errors = [];
        
        // Check required fields
        foreach ($this->required_fields as $field) {
            if (!isset($data[$field]) || trim($data[$field]) === '') {
                $this->errors[$field] = "The $field field is required";
            }
        }
        
        // Check if any of the required fields are missing
        $missing_fields = array_diff($this->required_fields, array_keys($data));
        if (!empty($missing_fields)) {
            foreach ($missing_fields as $field) {
                $this->errors[$field] = "The $field field is missing";
            }
        }
        
        // Return true if no errors
        return empty($this->errors);
    }
    
    public function getErrors() {
        return $this->errors;
    }
    
    public function hasErrors() {
        return !empty($this->errors);
    }
}

// Example usage
$validator = new FormValidator(['name', 'email', 'password']);

// Test with incomplete data
$form_data = [
    'name' => 'John Doe',
    'email' => '',  // Empty email
    // Password is missing
];

echo "<h4>Form Validation Example</h4>";

if ($validator->validate($form_data)) {
    echo "Form is valid!<br>";
} else {
    echo "Form has errors:<br>";
    $errors = $validator->getErrors();
    foreach ($errors as $field => $error) {
        echo "- $error<br>";
    }
}
?>

Analogy: Comparing arrays with == is like comparing two recipe ingredient lists - they can be in any order, but they must contain the same ingredients in the same amounts. Comparing with === is like comparing two precise laboratory procedures - not only must the ingredients be the same, but they must be in the same order and of exactly the same type.

Union Assignment Operator (+=)

The union assignment operator (+=) adds elements from the right array to the left array, but only when the key doesn't already exist in the left array.

Diagram
Yes No $a += $b For each key in $b Keep original value in $a Add key/value to $a Key exists in $a?

Union Assignment Examples

<?php
// Basic union assignment
$base = ['a' => 1, 'b' => 2];
$additional = ['b' => 3, 'c' => 4];

echo "Base Array: ";
print_r($base);

echo "Additional Array: ";
print_r($additional);

// Apply union assignment
$base += $additional;

echo "After Base += Additional: ";
print_r($base);
// Output: Array ( [a] => 1 [b] => 2 [c] => 4 )
// Note: 'b' keeps its original value, 'c' is added

// Multiple union assignments
$settings = ['debug' => false];
$settings += ['cache' => true];
$settings += ['timeout' => 30, 'retries' => 3];

echo "Multiple Assignments Result: ";
print_r($settings);
// Output: Array ( [debug] => false [cache] => true [timeout] => 30 [retries] => 3 )

// Using with numeric arrays
$fruits = ['apple', 'banana'];
$more_fruits = ['orange', 'grape', 'pear'];

$fruits += $more_fruits;
echo "Fruits after union assignment: ";
print_r($fruits);
// Output: Array ( [0] => apple [1] => banana [2] => pear )
// Note: indexes 0 and 1 already exist in $fruits, so only [2] => 'pear' is added
?>

Real-World Application: Filling Missing Values

The union assignment operator is perfect for filling in missing values in arrays:

<?php
// Function to fill missing values in an array
function fillMissingValues(array $data, array $defaults) {
    return $data + $defaults;
}

// Example: User preferences with defaults
function getUserPreferences($user_id) {
    // In a real application, this would fetch from a database
    $user_preferences = [
        1 => ['theme' => 'dark', 'notifications' => true],
        2 => ['theme' => 'light'],
        3 => ['notifications' => false],
        4 => [] // No preferences set
    ];
    
    return isset($user_preferences[$user_id]) ? $user_preferences[$user_id] : [];
}

// Default preferences
$defaults = [
    'theme' => 'system',
    'notifications' => true,
    'auto_save' => true,
    'font_size' => 'medium'
];

// Display preferences for different users
for ($user_id = 1; $user_id <= 4; $user_id++) {
    $user_prefs = getUserPreferences($user_id);
    
    echo "<h4>User $user_id Preferences</h4>";
    echo "Raw user preferences: ";
    print_r($user_prefs);
    
    // Fill missing values with defaults
    $complete_prefs = fillMissingValues($user_prefs, $defaults);
    
    echo "Complete preferences (with defaults): ";
    print_r($complete_prefs);
    
    echo "<hr>";
}
?>

Real-World Application: Pagination Settings

Another practical use of the union assignment operator is handling pagination settings:

<?php
// Pagination class
class Paginator {
    private $defaults = [
        'page' => 1,
        'per_page' => 10,
        'total_items' => 0,
        'url_pattern' => '?page=(:num)',
        'show_prev_next' => true,
        'show_first_last' => false,
        'max_pages' => 5
    ];
    
    private $options = [];
    
    public function __construct(array $options = []) {
        // Apply user options, falling back to defaults for missing values
        $this->options = $options + $this->defaults;
        
        // Ensure page and per_page are at least 1
        $this->options['page'] = max(1, $this->options['page']);
        $this->options['per_page'] = max(1, $this->options['per_page']);
    }
    
    public function getLinks() {
        $total_pages = ceil($this->options['total_items'] / $this->options['per_page']);
        $current_page = $this->options['page'];
        
        if ($total_pages <= 1) {
            return ''; // No pagination needed
        }
        
        $html = '<div class="pagination">';
        
        // First page link
        if ($this->options['show_first_last'] && $current_page > 1) {
            $html .= '<a href="' . str_replace('(:num)', 1, $this->options['url_pattern']) . '"><<</a> ';
        }
        
        // Previous page link
        if ($this->options['show_prev_next'] && $current_page > 1) {
            $html .= '<a href="' . str_replace('(:num)', $current_page - 1, $this->options['url_pattern']) . '"><</a> ';
        }
        
        // Page links
        $start = max(1, $current_page - floor($this->options['max_pages'] / 2));
        $end = min($total_pages, $start + $this->options['max_pages'] - 1);
        
        for ($i = $start; $i <= $end; $i++) {
            if ($i == $current_page) {
                $html .= '<span class="current">' . $i . '</span> ';
            } else {
                $html .= '<a href="' . str_replace('(:num)', $i, $this->options['url_pattern']) . '">' . $i . '</a> ';
            }
        }
        
        // Next page link
        if ($this->options['show_prev_next'] && $current_page < $total_pages) {
            $html .= '<a href="' . str_replace('(:num)', $current_page + 1, $this->options['url_pattern']) . '">></a> ';
        }
        
        // Last page link
        if ($this->options['show_first_last'] && $current_page < $total_pages) {
            $html .= '<a href="' . str_replace('(:num)', $total_pages, $this->options['url_pattern']) . '">>></a>';
        }
        
        $html .= '</div>';
        
        return $html;
    }
    
    public function getInfo() {
        $total_pages = ceil($this->options['total_items'] / $this->options['per_page']);
        $start = (($this->options['page'] - 1) * $this->options['per_page']) + 1;
        $end = min($start + $this->options['per_page'] - 1, $this->options['total_items']);
        
        return [
            'current_page' => $this->options['page'],
            'per_page' => $this->options['per_page'],
            'total_items' => $this->options['total_items'],
            'total_pages' => $total_pages,
            'start' => $start,
            'end' => $end
        ];
    }
}

// Example usage
$paginator = new Paginator([
    'page' => 2,
    'total_items' => 120,
    'per_page' => 15,
    'show_first_last' => true
]);

$info = $paginator->getInfo();
echo "<h4>Pagination Example</h4>";
echo "Page " . $info['current_page'] . " of " . $info['total_pages'] . "<br>";
echo "Showing items " . $info['start'] . " to " . $info['end'] . " of " . $info['total_items'] . "<br><br>";

echo $paginator->getLinks();
?>

Analogy: The union assignment operator (+=) is like filling in a partially completed form. If a field is already filled in, you leave it as is. If a field is empty, you provide the default value. At the end, all fields have values either from the original form or from the defaults.

Advanced Tips and Patterns

Recursively Merging Arrays

Sometimes you need to merge arrays with nested structures, preserving keys but also merging nested arrays:

<?php
// Function to recursively merge arrays
function array_merge_recursive_distinct(array &$array1, array &$array2) {
    $merged = $array1;
    
    foreach ($array2 as $key => &$value) {
        if (is_array($value) && isset($merged[$key]) && is_array($merged[$key])) {
            $merged[$key] = array_merge_recursive_distinct($merged[$key], $value);
        } else {
            $merged[$key] = $value;
        }
    }
    
    return $merged;
}

// Example usage
$base_config = [
    'database' => [
        'host' => 'localhost',
        'user' => 'root',
        'password' => '',
        'options' => [
            'charset' => 'utf8mb4',
            'collation' => 'utf8mb4_unicode_ci',
        ]
    ],
    'app' => [
        'debug' => false
    ]
];

$custom_config = [
    'database' => [
        'host' => 'db.example.com',
        'options' => [
            'timeout' => 30
        ]
    ],
    'app' => [
        'debug' => true
    ]
];

// Using union operator (non-recursive)
$simple_merge = $custom_config + $base_config;
echo "<h4>Simple Merge with + Operator</h4>";
echo "<pre>";
print_r($simple_merge);
echo "</pre>";
// Note: database.options from base_config is completely overwritten

// Using recursive merge
$recursive_merge = array_merge_recursive_distinct($base_config, $custom_config);
echo "<h4>Recursive Merge</h4>";
echo "<pre>";
print_r($recursive_merge);
echo "</pre>";
// Note: database.options are merged properly
?>

Combining Array Operations

In real-world applications, you often need to combine multiple array operations:

<?php
// Creating a complex filtering and merging operation
function process_products($products, $filter_criteria, $default_fields) {
    // Step 1: Filter products based on criteria
    $filtered_products = array_filter($products, function($product) use ($filter_criteria) {
        foreach ($filter_criteria as $field => $value) {
            if (!isset($product[$field]) || $product[$field] != $value) {
                return false;
            }
        }
        return true;
    });
    
    // Step 2: Fill in missing fields with defaults
    $complete_products = array_map(function($product) use ($default_fields) {
        return $product + $default_fields;
    }, $filtered_products);
    
    return $complete_products;
}

// Sample data
$products = [
    [
        'id' => 1,
        'name' => 'Smartphone',
        'category' => 'electronics',
        'price' => 499.99,
        'stock' => 15
    ],
    [
        'id' => 2,
        'name' => 'Laptop',
        'category' => 'electronics',
        'price' => 999.99,
    ],
    [
        'id' => 3,
        'name' => 'Headphones',
        'category' => 'accessories',
        'price' => 79.99,
        'stock' => 8
    ],
    [
        'id' => 4,
        'name' => 'Running Shoes',
        'category' => 'footwear',
        'stock' => 12
    ]
];

// Filter criteria
$criteria = [
    'category' => 'electronics'
];

// Default fields
$defaults = [
    'stock' => 0,
    'price' => 0,
    'status' => 'active',
    'description' => 'No description available'
];

// Process the products
$result = process_products($products, $criteria, $defaults);

echo "<h4>Processed Products</h4>";
echo "<pre>";
print_r($result);
echo "</pre>";
?>

Array Comparison Performance Tips

When working with large arrays, performance considerations become important:

<?php
// Performance tips for array comparison
$large_array1 = array_fill(0, 1000, 'value');
$large_array2 = array_fill(0, 1000, 'value');
$large_array2[500] = 'different value';

// Tip 1: Quick comparison with array_diff for simple arrays
function quick_array_compare($array1, $array2) {
    // If array lengths differ, they're definitely not equal
    if (count($array1) !== count($array2)) {
        return false;
    }
    
    // Check if there are any differences (keys or values)
    return empty(array_diff($array1, $array2)) && empty(array_diff($array2, $array1));
}

// Tip 2: Early exit for identity comparison
function quick_identity_check($array1, $array2) {
    // If array lengths differ, they're definitely not identical
    if (count($array1) !== count($array2)) {
        return false;
    }
    
    // Check each element for identity
    foreach ($array1 as $key => $value) {
        if (!array_key_exists($key, $array2) || $array2[$key] !== $value) {
            return false;
        }
    }
    
    return true;
}

// Tip 3: Hash comparison for large arrays
function hash_array_compare($array1, $array2) {
    return md5(serialize($array1)) === md5(serialize($array2));
}

// Example timing
$start_time = microtime(true);
$result1 = ($large_array1 === $large_array2);
$time1 = microtime(true) - $start_time;

$start_time = microtime(true);
$result2 = quick_identity_check($large_array1, $large_array2);
$time2 = microtime(true) - $start_time;

$start_time = microtime(true);
$result3 = hash_array_compare($large_array1, $large_array2);
$time3 = microtime(true) - $start_time;

echo "<h4>Performance Comparison</h4>";
echo "Standard === operator: " . ($result1 ? 'true' : 'false') . " (took " . number_format($time1 * 1000, 4) . " ms)<br>";
echo "Quick identity check: " . ($result2 ? 'true' : 'false') . " (took " . number_format($time2 * 1000, 4) . " ms)<br>";
echo "Hash comparison: " . ($result3 ? 'true' : 'false') . " (took " . number_format($time3 * 1000, 4) . " ms)<br>";
?>

Note: Performance characteristics can vary significantly based on array size, complexity, and PHP version. Always test your specific use case.

Best Practices for Array Operators

  • Choose the right operator for the job: Understand the difference between + and array_merge() and use them appropriately based on your needs.
  • Use identity (===) for strict comparisons: When order and type matter, use the identity operator. Use equality (==) when only key/value pairs matter.
  • Leverage union assignment (+= ) for defaults: It's a clean way to add default values without overriding existing ones.
  • Be mindful of nested arrays: Standard array operators don't recursively merge nested arrays. Use a recursive function when needed.
  • Consider performance for large arrays: Array operations can be expensive with large datasets. Implement early exits and avoid unnecessary deep comparisons.
  • Document your intention: When using array operators, especially for complex operations, add comments explaining your intention to make the code more maintainable.

Best Practices Example

<?php
/**
 * Process user settings by merging with defaults, validating,
 * and applying business rules.
 *
 * @param array $user_settings User-provided settings
 * @return array Complete and validated settings
 */
function process_user_settings(array $user_settings) {
    // Define default settings
    $defaults = [
        'theme' => 'light',
        'notifications' => [
            'email' => true,
            'push' => false,
            'sms' => false
        ],
        'privacy' => [
            'profile_visibility' => 'public',
            'activity_tracking' => true
        ],
        'display' => [
            'language' => 'en',
            'timezone' => 'UTC',
            'date_format' => 'Y-m-d'
        ]
    ];
    
    // Recursively merge settings, with user settings taking precedence
    $settings = array_merge_recursive_distinct($defaults, $user_settings);
    
    // Apply validation and business rules
    
    // Theme must be one of the allowed values
    $allowed_themes = ['light', 'dark', 'system'];
    if (!in_array($settings['theme'], $allowed_themes)) {
        $settings['theme'] = $defaults['theme'];
    }
    
    // If SMS notifications are enabled, make sure we have a phone number
    if ($settings['notifications']['sms'] === true && empty($user_settings['phone'])) {
        $settings['notifications']['sms'] = false;
    }
    
    // Apply privacy restrictions based on user role
    // (In a real app, user role would come from a database or session)
    $user_role = 'regular'; // For example purposes
    
    if ($user_role !== 'admin') {
        // Regular users can't disable activity tracking
        $settings['privacy']['activity_tracking'] = true;
    }
    
    return $settings;
}

// Recursive array merge function (same as previous example)
function array_merge_recursive_distinct(array $array1, array $array2) {
    $merged = $array1;
    
    foreach ($array2 as $key => &$value) {
        if (is_array($value) && isset($merged[$key]) && is_array($merged[$key])) {
            $merged[$key] = array_merge_recursive_distinct($merged[$key], $value);
        } else {
            $merged[$key] = $value;
        }
    }
    
    return $merged;
}

// Example usage
$user_settings = [
    'theme' => 'dark',
    'notifications' => [
        'push' => true
    ],
    'privacy' => [
        'profile_visibility' => 'friends',
        'activity_tracking' => false // Will be overridden for regular users
    ]
];

$processed_settings = process_user_settings($user_settings);

echo "<h4>Processed User Settings</h4>";
echo "<pre>";
print_r($processed_settings);
echo "</pre>";
?>

Practice Exercises

Test your understanding of PHP array operators with these exercises:

Exercise 1: Array Merge Tool

Create a function that intelligently merges two configuration arrays based on specific rules.

<?php
/*
 * 1. Create a function smart_merge($array1, $array2) with the following rules:
 *    - String keys from $array2 override those in $array1
 *    - Numeric keys are appended, not overwritten
 *    - If both arrays contain an array at the same key, recursively merge them
 * 2. Test with various array combinations, including nested arrays
 */
?>

Exercise 2: Array Comparison Class

Create a class for comparing arrays with different comparison methods.

<?php
/*
 * 1. Create an ArrayComparison class with these methods:
 *    - isEqual($array1, $array2) - Check if arrays are equal (==)
 *    - isIdentical($array1, $array2) - Check if arrays are identical (===)
 *    - getDifferences($array1, $array2) - Return an array of differences between arrays
 *    - getCommonElements($array1, $array2) - Return an array of elements common to both arrays
 * 2. Handle nested arrays in all methods
 * 3. Test with various array combinations
 */
?>

Exercise 3: Configuration Manager

Build a configuration management system that uses array operators effectively.

<?php
/*
 * 1. Create a ConfigManager class with:
 *    - A constructor that accepts default configs
 *    - A method to load configs from different sources (use array operators to merge them)
 *    - A method to get a config value by key (supporting dot notation, e.g., 'database.host')
 *    - A method to set a config value by key
 *    - A method to export the current configuration
 * 2. Implement proper handling of nested configurations
 * 3. Create a simple example using your ConfigManager
 */
?>

Summary

In this session, we've explored PHP's array operators and their practical applications:

  • Union Operator (+): Merges arrays, preserving keys from the left array when duplicate keys exist.
  • Equality Operator (==): Checks if arrays have the same key/value pairs, regardless of order or type.
  • Identity Operator (===): Checks if arrays have the same key/value pairs in the same order and of the same types.
  • Inequality (!= or <>) and Non-identity (!==) Operators: The negated versions of the equality and identity operators.
  • Union Assignment Operator (+=): Adds elements from the right array to the left array when the key doesn't already exist in the left array.

We've also covered important concepts like:

  • The difference between union (+) and array_merge(): Understanding when to use each based on how they handle keys.
  • Recursive array merging: For handling nested arrays properly.
  • Performance considerations: Techniques for efficiently comparing large arrays.
  • Real-world applications: Using array operators for configuration systems, form validation, and pagination.

Array operators are essential tools in PHP development, especially when building applications that require complex data structures, configuration systems, or user input processing. Mastering these operators will make your code more efficient, readable, and maintainable.

Next Session Preview

In our next session, we'll explore PHP Control Structures, which allow you to control the flow of your programs. We'll learn about if/else statements, switch statements, loops, and other constructs that let you make decisions and repeat actions in your PHP applications.

Additional Resources