Skip to content

Arrays and Objects

Overview

Arrays and objects are fundamental data structures in PHP. Arrays store collections of data, while objects encapsulate data and behavior. This chapter covers array operations, object-oriented programming basics, and handling complex data structures.

Arrays in Depth

Array Creation and Types

php
<?php
// Indexed arrays
$fruits = array("apple", "banana", "orange");
$numbers = [1, 2, 3, 4, 5]; // Short syntax (PHP 5.4+)

// Associative arrays
$person = array(
    "name" => "Zhang San",
    "age" => 30,
    "city" => "Beijing"
);

$config = [
    "database" => "mysql",
    "host" => "localhost",
    "port" => 3306
];

// Mixed arrays
$mixed = [
    0 => "First item",
    "key" => "Value",
    1 => "Second item",
    "nested" => ["a", "b", "c"]
];

// Multidimensional arrays
$matrix = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
];

$users = [
    [
        "id" => 1,
        "name" => "Xiaoming",
        "email" => "xiaoming@example.com",
        "roles" => ["user", "editor"]
    ],
    [
        "id" => 2,
        "name" => "Xiaohong",
        "email" => "xiaohong@example.com",
        "roles" => ["user"]
    ]
];
?>

Array Access and Modification

php
<?php
$fruits = ["apple", "banana", "orange"];

// Access elements
echo $fruits[0]; // "apple"
echo $fruits[1]; // "banana"

// Modify elements
$fruits[1] = "grape";
echo $fruits[1]; // "grape"

// Add elements
$fruits[] = "kiwi";           // Append to end
$fruits[10] = "mango";        // Specify index
array_push($fruits, "peach"); // Append using function
array_unshift($fruits, "strawberry"); // Prepend

// Remove elements
unset($fruits[2]);            // Remove specified index
$lastFruit = array_pop($fruits);     // Remove and return last
$firstFruit = array_shift($fruits);  // Remove and return first

// Associative array operations
$person = ["name" => "Zhang San", "age" => 30];

// Add/modify
$person["email"] = "zhangsan@example.com";
$person["age"] = 31;

// Check existence
if (isset($person["email"])) {
    echo "Email exists: " . $person["email"];
}

if (array_key_exists("phone", $person)) {
    echo "Phone exists";
} else {
    echo "Phone not set";
}

// Delete
unset($person["age"]);
?>

Array Functions and Operations

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

// Array information
echo count($numbers);        // 8 (length)
echo sizeof($numbers);       // 8 (alias of count)
echo array_sum($numbers);    // 31 (sum)
echo array_product($numbers); // 6480 (product)

// Min/max values
echo min($numbers);          // 1
echo max($numbers);          // 9

// Search
$position = array_search(5, $numbers);  // Returns first matching index
$exists = in_array(4, $numbers);        // true/false

// Sorting
$sorted = $numbers;
sort($sorted);               // Sort by value, lose keys
print_r($sorted);

$reversed = $numbers;
rsort($reversed);            // Reverse sort
print_r($reversed);

// Associative array sorting
$people = [
    "zhangsan" => 30,
    "lisi" => 25,
    "wangwu" => 35
];

asort($people);              // Sort by value, keep keys
print_r($people);            // lisi=>25, zhangsan=>30, wangwu=>35

ksort($people);              // Sort by key
print_r($people);            // lisi=>25, wangwu=>35, zhangsan=>30

// Custom sorting
$users = [
    ["name" => "Zhang San", "age" => 30],
    ["name" => "Li Si", "age" => 25],
    ["name" => "Wang Wu", "age" => 35]
];

usort($users, function($a, $b) {
    return $a["age"] <=> $b["age"]; // Sort by age
});

print_r($users);
?>

Array Operation Functions

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

// Map - transform each element
$doubled = array_map(function($n) {
    return $n * 2;
}, $numbers);
print_r($doubled); // [2, 4, 6, 8, 10]

// Filter - filter elements based on condition
$evens = array_filter($numbers, function($n) {
    return $n % 2 === 0;
});
print_r($evens); // [2, 4]

// Reduce - combine elements into single value
$sum = array_reduce($numbers, function($carry, $item) {
    return $carry + $item;
}, 0);
echo $sum; // 15

// Array merging
$arr1 = [1, 2, 3];
$arr2 = [4, 5, 6];
$merged = array_merge($arr1, $arr2);
print_r($merged); // [1, 2, 3, 4, 5, 6]

// Array slicing
$slice = array_slice($numbers, 1, 3); // Start at index 1, take 3 elements
print_r($slice); // [2, 3, 4]

// Array chunking
$chunks = array_chunk($numbers, 2);
print_r($chunks); // [[1, 2], [3, 4], [5]]

// Array keys and values
$person = ["name" => "Zhang San", "age" => 30, "city" => "Beijing"];
$keys = array_keys($person);     // ["name", "age", "city"]
$values = array_values($person); // ["Zhang San", 30, "Beijing"]

// Flip keys and values
$flipped = array_flip($person);
print_r($flipped); // ["Zhang San" => "name", 30 => "age", "Beijing" => "city"]
?>

Advanced Array Techniques

php
<?php
// Array walk - apply function to each element
$fruits = ["apple", "banana", "orange"];

array_walk($fruits, function(&$fruit, $key) {
    $fruit = strtoupper($fruit);
});
print_r($fruits); // ["APPLE", "BANANA", "ORANGE"]

// Array column extraction - extract column from multidimensional array
$users = [
    ["id" => 1, "name" => "Zhang San", "email" => "zhangsan@example.com"],
    ["id" => 2, "name" => "Li Si", "email" => "lisi@example.com"],
    ["id" => 3, "name" => "Wang Wu", "email" => "wangwu@example.com"]
];

$names = array_column($users, "name");
print_r($names); // ["Zhang San", "Li Si", "Wang Wu"]

$emailsById = array_column($users, "email", "id");
print_r($emailsById); // [1 => "zhangsan@example.com", 2 => "lisi@example.com", ...]

// Array combine - create array using one array as keys, another as values
$keys = ["name", "age", "city"];
$values = ["Zhang San", 30, "Beijing"];
$combined = array_combine($keys, $values);
print_r($combined); // ["name" => "Zhang San", "age" => 30, "city" => "Beijing"]

// Array intersection and difference
$array1 = [1, 2, 3, 4, 5];
$array2 = [3, 4, 5, 6, 7];

$intersection = array_intersect($array1, $array2); // [3, 4, 5]
$difference = array_diff($array1, $array2);        // [1, 2]

// Unique values
$duplicates = [1, 2, 2, 3, 3, 3, 4];
$unique = array_unique($duplicates);
print_r($unique); // [1, 2, 3, 4]
?>

Object Basics

Class Definition and Instantiation

php
<?php
// Basic class definition
class Person {
    // Properties (attributes)
    public $name;
    public $age;
    public $email;
    
    // Constructor
    public function __construct($name, $age, $email) {
        $this->name = $name;
        $this->age = $age;
        $this->email = $email;
    }
    
    // Methods (functions)
    public function introduce() {
        return "Hello, I am {$this->name}, {$this->age} years old.";
    }
    
    public function getEmail() {
        return $this->email;
    }
    
    public function setEmail($email) {
        if (filter_var($email, FILTER_VALIDATE_EMAIL)) {
            $this->email = $email;
            return true;
        }
        return false;
    }
}

// Create objects (instantiation)
$person1 = new Person("Xiaohong", 25, "xiaohong@example.com");
$person2 = new Person("Xiaoming", 30, "xiaoming@example.com");

// Using objects
echo $person1->introduce(); // "Hello, I am Xiaohong, 25 years old."
echo $person1->name;        // "Xiaohong"

$person1->setEmail("xiaohong.new@example.com");
echo $person1->getEmail();  // "xiaohong.new@example.com"
?>

Property Visibility

php
<?php
class BankAccount {
    public $accountNumber;    // Accessible from anywhere
    protected $balance;       // Accessible from this class and subclasses
    private $pin;            // Accessible only from this class
    
    public function __construct($accountNumber, $initialBalance, $pin) {
        $this->accountNumber = $accountNumber;
        $this->balance = $initialBalance;
        $this->pin = $pin;
    }
    
    public function getBalance() {
        return $this->balance;
    }
    
    public function deposit($amount) {
        if ($amount > 0) {
            $this->balance += $amount;
            return true;
        }
        return false;
    }
    
    public function withdraw($amount, $enteredPin) {
        if ($this->validatePin($enteredPin) && $amount > 0 && $amount <= $this->balance) {
            $this->balance -= $amount;
            return true;
        }
        return false;
    }
    
    private function validatePin($enteredPin) {
        return $this->pin === $enteredPin;
    }
    
    protected function calculateInterest($rate) {
        return $this->balance * $rate;
    }
}

$account = new BankAccount("12345", 1000, "1234");

echo $account->accountNumber;  // OK (public)
echo $account->getBalance();   // OK (public method)

// These would cause errors:
// echo $account->balance;     // Error (protected)
// echo $account->pin;         // Error (private)
// $account->validatePin("1234"); // Error (private method)
?>

Static Properties and Methods

php
<?php
class Counter {
    private static $count = 0;
    public static $instances = [];
    
    public $id;
    
    public function __construct() {
        self::$count++;
        $this->id = self::$count;
        self::$instances[] = $this;
    }
    
    public static function getCount() {
        return self::$count;
    }
    
    public static function resetCount() {
        self::$count = 0;
        self::$instances = [];
    }
    
    public function getId() {
        return $this->id;
    }
}

// Using static methods and properties
echo Counter::getCount(); // 0

$counter1 = new Counter();
$counter2 = new Counter();
$counter3 = new Counter();

echo Counter::getCount(); // 3
echo $counter2->getId();  // 2

print_r(Counter::$instances); // Array of Counter objects

Counter::resetCount();
echo Counter::getCount(); // 0
?>

Magic Methods

php
<?php
class MagicExample {
    private $data = [];
    
    // Constructor and destructor
    public function __construct($initialData = []) {
        $this->data = $initialData;
        echo "Object created\n";
    }
    
    public function __destruct() {
        echo "Object destroyed\n";
    }
    
    // Property access
    public function __get($name) {
        return $this->data[$name] ?? null;
    }
    
    public function __set($name, $value) {
        $this->data[$name] = $value;
    }
    
    public function __isset($name) {
        return isset($this->data[$name]);
    }
    
    public function __unset($name) {
        unset($this->data[$name]);
    }
    
    // Method calls
    public function __call($method, $args) {
        echo "Calling method '$method' with arguments: " . implode(', ', $args) . "\n";
    }
    
    public static function __callStatic($method, $args) {
        echo "Calling static method '$method' with arguments: " . implode(', ', $args) . "\n";
    }
    
    // String conversion
    public function __toString() {
        return json_encode($this->data);
    }
    
    // Array access
    public function __invoke($arg) {
        echo "Object called as function with argument: $arg\n";
    }
}

$obj = new MagicExample(["name" => "Zhang San"]);

// Property access
echo $obj->name;        // "Zhang San" (calls __get)
$obj->age = 30;         // Calls __set
echo isset($obj->age);  // true (calls __isset)

// Method calls
$obj->nonExistentMethod("arg1", "arg2"); // Calls __call

// String conversion
echo $obj; // Calls __toString, outputs JSON

// Function call
$obj("hello"); // Calls __invoke
?>

Object-Oriented Programming Concepts

Inheritance

php
<?php
// Base class
class Animal {
    protected $name;
    protected $species;
    
    public function __construct($name, $species) {
        $this->name = $name;
        $this->species = $species;
    }
    
    public function getName() {
        return $this->name;
    }
    
    public function getSpecies() {
        return $this->species;
    }
    
    public function makeSound() {
        return "Some generic animal sound";
    }
    
    public function sleep() {
        return "{$this->name} is sleeping";
    }
}

// Derived class
class Dog extends Animal {
    private $breed;
    
    public function __construct($name, $breed) {
        parent::__construct($name, "Canine");
        $this->breed = $breed;
    }
    
    public function makeSound() {
        return "Woof! Woof!";
    }
    
    public function fetch() {
        return "{$this->name} is fetching the ball";
    }
    
    public function getBreed() {
        return $this->breed;
    }
}

class Cat extends Animal {
    public function __construct($name) {
        parent::__construct($name, "Feline");
    }
    
    public function makeSound() {
        return "Meow!";
    }
    
    public function purr() {
        return "{$this->name} is purring";
    }
}

// Usage
$dog = new Dog("Xiaobai", "Golden Retriever");
$cat = new Cat("Whiskers");

echo $dog->getName();     // "Xiaobai"
echo $dog->makeSound();   // "Woof! Woof!"
echo $dog->fetch();       // "Xiaobai is fetching the ball"
echo $dog->getBreed();    // "Golden Retriever"

echo $cat->getName();     // "Whiskers"
echo $cat->makeSound();   // "Meow!"
echo $cat->purr();        // "Whiskers is purring"

// Polymorphism
$animals = [$dog, $cat];
foreach ($animals as $animal) {
    echo $animal->getName() . " says: " . $animal->makeSound() . "\n";
}
?>

Abstract Classes and Interfaces

php
<?php
// Abstract class
abstract class Shape {
    protected $color;
    
    public function __construct($color) {
        $this->color = $color;
    }
    
    public function getColor() {
        return $this->color;
    }
    
    // Abstract methods - must be implemented by subclasses
    abstract public function calculateArea();
    abstract public function calculatePerimeter();
}

// Interfaces
interface Drawable {
    public function draw();
}

interface Resizable {
    public function resize($factor);
}

// Concrete classes
class Circle extends Shape implements Drawable, Resizable {
    private $radius;
    
    public function __construct($color, $radius) {
        parent::__construct($color);
        $this->radius = $radius;
    }
    
    public function calculateArea() {
        return pi() * $this->radius * $this->radius;
    }
    
    public function calculatePerimeter() {
        return 2 * pi() * $this->radius;
    }
    
    public function draw() {
        return "Drawing a {$this->color} circle with radius {$this->radius}";
    }
    
    public function resize($factor) {
        $this->radius *= $factor;
    }
}

class Rectangle extends Shape implements Drawable {
    private $width;
    private $height;
    
    public function __construct($color, $width, $height) {
        parent::__construct($color);
        $this->width = $width;
        $this->height = $height;
    }
    
    public function calculateArea() {
        return $this->width * $this->height;
    }
    
    public function calculatePerimeter() {
        return 2 * ($this->width + $this->height);
    }
    
    public function draw() {
        return "Drawing a {$this->color} rectangle ({$this->width}x{$this->height})";
    }
}

// Usage
$circle = new Circle("red", 5);
$rectangle = new Rectangle("blue", 4, 6);

echo $circle->draw();                    // "Drawing a red circle with radius 5"
echo "Area: " . $circle->calculateArea(); // Area: 78.54

$circle->resize(2);
echo "New area: " . $circle->calculateArea(); // New area: 314.16

// Polymorphism using interfaces
$shapes = [$circle, $rectangle];
foreach ($shapes as $shape) {
    if ($shape instanceof Drawable) {
        echo $shape->draw() . "\n";
    }
}
?>

Traits

php
<?php
// Traits - reusable code blocks
trait Timestampable {
    private $createdAt;
    private $updatedAt;
    
    public function setCreatedAt($timestamp = null) {
        $this->createdAt = $timestamp ?: date('Y-m-d H:i:s');
    }
    
    public function setUpdatedAt($timestamp = null) {
        $this->updatedAt = $timestamp ?: date('Y-m-d H:i:s');
    }
    
    public function getCreatedAt() {
        return $this->createdAt;
    }
    
    public function getUpdatedAt() {
        return $this->updatedAt;
    }
}

trait Validatable {
    private $errors = [];
    
    public function addError($field, $message) {
        $this->errors[$field][] = $message;
    }
    
    public function getErrors() {
        return $this->errors;
    }
    
    public function hasErrors() {
        return !empty($this->errors);
    }
    
    public function clearErrors() {
        $this->errors = [];
    }
}

// Using traits
class User {
    use Timestampable, Validatable;
    
    private $name;
    private $email;
    
    public function __construct($name, $email) {
        $this->name = $name;
        $this->email = $email;
        $this->setCreatedAt();
        $this->validate();
    }
    
    private function validate() {
        if (empty($this->name)) {
            $this->addError('name', 'Name is required');
        }
        
        if (!filter_var($this->email, FILTER_VALIDATE_EMAIL)) {
            $this->addError('email', 'Invalid email format');
        }
    }
    
    public function getName() {
        return $this->name;
    }
    
    public function getEmail() {
        return $this->email;
    }
    
    public function setName($name) {
        $this->name = $name;
        $this->setUpdatedAt();
        $this->validate();
    }
}

$user = new User("Zhang San", "zhangsan@example.com");

echo "Created at: " . $user->getCreatedAt();
echo "Has errors: " . ($user->hasErrors() ? 'Yes' : 'No');

$user->setName("");
if ($user->hasErrors()) {
    print_r($user->getErrors());
}
?>

Handling Complex Data Structures

Nested Arrays and Objects

php
<?php
// Complex nested structure
$company = [
    "name" => "Tech Company",
    "founded" => 2010,
    "departments" => [
        "engineering" => [
            "manager" => "Manager Zhang",
            "employees" => [
                ["name" => "Developer Li", "role" => "Senior Developer", "salary" => 90000],
                ["name" => "Designer Wang", "role" => "Junior Developer", "salary" => 60000],
                ["name" => "DevOps Zhao", "role" => "DevOps Engineer", "salary" => 85000]
            ]
        ],
        "marketing" => [
            "manager" => "Manager Liu",
            "employees" => [
                ["name" => "Manager Chen", "role" => "Marketing Manager", "salary" => 75000],
                ["name" => "Creator Sun", "role" => "Content Creator", "salary" => 55000]
            ]
        ]
    ]
];

// Access nested data
echo $company["name"]; // "Tech Company"
echo $company["departments"]["engineering"]["manager"]; // "Manager Zhang"
echo $company["departments"]["engineering"]["employees"][0]["name"]; // "Developer Li"

// Process nested data
function calculateDepartmentPayroll($department) {
    $total = 0;
    foreach ($department["employees"] as $employee) {
        $total += $employee["salary"];
    }
    return $total;
}

function getCompanyStats($company) {
    $stats = [
        "total_employees" => 0,
        "total_payroll" => 0,
        "departments" => []
    ];
    
    foreach ($company["departments"] as $deptName => $department) {
        $employeeCount = count($department["employees"]);
        $payroll = calculateDepartmentPayroll($department);
        
        $stats["departments"][$deptName] = [
            "manager" => $department["manager"],
            "employee_count" => $employeeCount,
            "payroll" => $payroll
        ];
        
        $stats["total_employees"] += $employeeCount;
        $stats["total_payroll"] += $payroll;
    }
    
    return $stats;
}

$stats = getCompanyStats($company);
print_r($stats);
?>

Array and Object Conversion

php
<?php
// Array to object conversion
$array = [
    "name" => "Zhang San",
    "age" => 30,
    "address" => [
        "street" => "Main Street 123",
        "city" => "Beijing"
    ]
];

// Simple conversion (shallow)
$obj = (object) $array;
echo $obj->name; // "Zhang San"
echo $obj->address["street"]; // "Main Street 123" (still array)

// Deep conversion function
function arrayToObject($array) {
    if (is_array($array)) {
        $obj = new stdClass();
        foreach ($array as $key => $value) {
            $obj->$key = arrayToObject($value);
        }
        return $obj;
    }
    return $array;
}

$deepObj = arrayToObject($array);
echo $deepObj->name; // "Zhang San"
echo $deepObj->address->street; // "Main Street 123" (now object property)

// Object to array conversion
function objectToArray($obj) {
    if (is_object($obj)) {
        $array = [];
        foreach (get_object_vars($obj) as $key => $value) {
            $array[$key] = objectToArray($value);
        }
        return $array;
    }
    return $obj;
}

$backToArray = objectToArray($deepObj);
print_r($backToArray);

// JSON conversion (handles nested structures)
$jsonString = json_encode($array);
$objFromJson = json_decode($jsonString); // Object
$arrayFromJson = json_decode($jsonString, true); // Array
?>

Data Manipulation Patterns

php
<?php
// Repository pattern for data management
class UserRepository {
    private $users = [];
    
    public function add($user) {
        $this->users[] = $user;
    }
    
    public function findById($id) {
        foreach ($this->users as $user) {
            if ($user['id'] === $id) {
                return $user;
            }
        }
        return null;
    }
    
    public function findByEmail($email) {
        return array_filter($this->users, function($user) use ($email) {
            return $user['email'] === $email;
        });
    }
    
    public function update($id, $data) {
        foreach ($this->users as &$user) {
            if ($user['id'] === $id) {
                $user = array_merge($user, $data);
                return true;
            }
        }
        return false;
    }
    
    public function delete($id) {
        foreach ($this->users as $index => $user) {
            if ($user['id'] === $id) {
                unset($this->users[$index]);
                $this->users = array_values($this->users); // Reindex
                return true;
            }
        }
        return false;
    }
    
    public function getAll() {
        return $this->users;
    }
    
    public function filter($callback) {
        return array_filter($this->users, $callback);
    }
    
    public function map($callback) {
        return array_map($callback, $this->users);
    }
}

// Usage
$repo = new UserRepository();

$repo->add(['id' => 1, 'name' => 'Zhang San', 'email' => 'zhangsan@example.com', 'active' => true]);
$repo->add(['id' => 2, 'name' => 'Li Si', 'email' => 'lisi@example.com', 'active' => false]);
$repo->add(['id' => 3, 'name' => 'Wang Wu', 'email' => 'wangwu@example.com', 'active' => true]);

// Find operations
$user = $repo->findById(2);
echo "Found user: " . $user['name'];

$activeUsers = $repo->filter(function($user) {
    return $user['active'];
});
echo "Active users count: " . count($activeUsers);

// Transform data
$userNames = $repo->map(function($user) {
    return $user['name'];
});
print_r($userNames); // ['Zhang San', 'Li Si', 'Wang Wu']

// Update and delete
$repo->update(2, ['active' => true]);
$repo->delete(3);

print_r($repo->getAll());
?>

Next Steps

Now that you understand arrays and objects, let's explore APIs and interfaces in APIs and Interfaces.

Practice Exercises

  1. Create a shopping cart system using arrays and objects
  2. Build a simple database system with CRUD operations
  3. Implement a class hierarchy for different types of vehicles
  4. Create a data processing pipeline using array functions
  5. Build a configuration management system using nested arrays

Understanding arrays and objects is fundamental to building complex PHP applications!

Content is for learning and research only.