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
- Create a shopping cart system using arrays and objects
- Build a simple database system with CRUD operations
- Implement a class hierarchy for different types of vehicles
- Create a data processing pipeline using array functions
- Build a configuration management system using nested arrays
Understanding arrays and objects is fundamental to building complex PHP applications!