Classes and Objects in PHP
Object-Oriented Programming (OOP) allows organizing code into classes that define types of objects and their behaviors. A class is a template, and an object is an instance of a class.
Why use classes and objects?
- Improves the structure and organization of code.
- Allows code reuse by instantiating multiple objects.
- Facilitates maintenance and extension of large applications.
Defining a class and creating an object
Simple example of a class describing a user:
<?php
// Defining the class
class User {
// Properties
public $name;
public $email;
// Method to display information
public function showInfo() {
echo "Name: $this->name, Email: $this->email <br>";
}
}
// Creating an object
$user1 = new User();
$user1->name = "John Smith";
$user1->email = "john.smith@example.com";
// Calling the method
$user1->showInfo();
?>
Step-by-step explanation
- We created a class
Userwith two properties:$nameand$email. - We defined a method
showInfo()that displays the object's properties. - We instantiated an object
$user1using the keywordnew. - We set the values of the object's properties.
- We called the method
showInfo()to display the information.
This is the foundation of OOP in PHP: classes define the structure and behavior, while objects are instances of those classes.
Properties & Methods in PHP
In OOP, properties are the variables inside a class that define the state of an object, and methods are the functions that define the behavior of the object.
Defining properties and methods
<?php
class User {
// Properties
public $name;
public $email;
private $password; // private property
// Public method
public function setPassword($pass) {
$this->password = password_hash($pass, PASSWORD_DEFAULT);
}
// Public method for display
public function showInfo() {
echo "Name: $this->name, Email: $this->email <br>";
}
// Private method (cannot be called from outside the class)
private function getPassword() {
return $this->password;
}
}
// Creating the object
$user = new User();
$user->name = "Mary Ionella";
$user->email = "maria.ionescu@example.com";
$user->setPassword("password123");
// Calling the public method
$user->showInfo();
// We cannot do:
echo $user->password; // error, private property
?>
Step-by-step explanation
$nameand$emailare public - they can be accessed and modified directly from outside the class.$passwordis private - it can only be accessed from inside the class.- The
setPassword()method encrypts the password usingpassword_hash()and sets the private property$password. - The
showInfo()method displays the public information of the object. - Trying to access a private property directly from outside the class will generate an error.
Thus, visibility (public, private) helps with encapsulation, meaning protecting the internal data of objects and controlling access.
Constructor & Destructor in PHP
In object-oriented programming, constructors and destructors are special methods of a class:
- Constructor (__construct) - is automatically called when an object is created. It is useful for initializing properties or performing actions at the moment the object is created.
- Destructor (__destruct) - is automatically called when the object is destroyed or the script ends. It is used for cleaning up resources, closing connections, etc.
Practical example: constructor and destructor
<?php
class User {
public $name;
private $email;
// Constructor
public function __construct($name, $email) {
$this->name = $name;
$this->email = $email;
echo "✅ The User object has been created for $name.<br>";
}
// Destructor
public function __destruct() {
echo "🗑️ The User object for $this->name has been destroyed.<br>";
}
public function getEmail() {
return $this->email;
}
}
// Creating objects
$user1 = new User("John Smith", "john.smith@example.com");
$user2 = new User("Mary Ionella", "maria.ionescu@example.com");
// Accessing the email through the public method
echo "$user1->name's email is: " . $user1->getEmail() . "<br>";
echo "$user2->name's email is: " . $user2->getEmail() . "<br>";
// At the end of the script or when the objects are deleted, the destructor will be called automatically
?>
Observations:
- The constructor (__construct) was automatically called when each object was created.
- The destructor (__destruct) will be automatically called at the end of the script or when the objects are destroyed.
- Access to private properties is done only through public methods (e.g.:
getEmail()), demonstrating encapsulation.
Inheritance & Visibility in PHP
In PHP, classes can inherit properties and methods from other classes, which allows code reuse and extending functionalities. Also, visibility defines access to properties and methods:
- public - accessible everywhere, in the class, in subclasses, and from outside;
- protected - accessible in the class and in subclasses, but not from outside;
- private - accessible only in the class where it is defined.
Practical example: inheritance and visibility
<?php
// Base class (Parent)
class User {
public $name;
protected $role;
private $password;
public function __construct($name, $password) {
$this->name = $name;
$this->password = $password;
$this->role = "User";
}
public function getRole() {
return $this->role;
}
public function checkPassword($input) {
return $this->password === $input;
}
}
// Child class that inherits User
class Admin extends User {
public function __construct($name, $password) {
parent::__construct($name, $password);
$this->role = "Administrator"; // modifying the protected property
}
public function displayInfo() {
echo "<p>Name: $this->name, Role: $this->role</p>";
// We cannot access $this->password directly, it is private
}
}
// Creating objects
$user = new User("John Smith", "password123");
$admin = new Admin("Mary Ionella", "adminpass");
// Accessing methods
echo "<p>User Role: " . $user->getRole() . "</p>";
echo "<p>Correct password? " . ($user->checkPassword("password123") ? "✅" : "❌") . "</p>";
$admin->displayInfo();
?>
Observations:
- The
Adminclass inherits all public/protected properties and methods fromUser. privateproperties are not accessible in the subclass.- By using the correct visibility, we can control what can be modified or accessed from outside and what must remain protected.
Interfaces & Traits in PHP
In PHP, Interfaces and Traits are powerful tools that help with organizing code and reusing functionality without classical inheritance:
- Interface - defines a set of methods that any class implementing the interface must include. It contains no implementations, only method signatures.
- Trait - allows reusing code across multiple classes, providing concrete method implementations without using classical inheritance.
Practical Example: Interface
<?php
interface Logger {
public function log($message);
}
class FileLogger implements Logger {
public function log($message) {
echo "Saved to file: $message<br>";
}
}
class DatabaseLogger implements Logger {
public function log($message) {
echo "Saved to DB: $message<br>";
}
}
$fileLogger = new FileLogger();
$fileLogger->log("Test message for file");
$dbLogger = new DatabaseLogger();
$dbLogger->log("Test message for database");
?>
Practical Example: Trait
<?php
trait Timestamp {
public function createdAt() {
return date("Y-m-d H:i:s");
}
}
class Post {
use Timestamp;
public $title;
public function __construct($title) {
$this->title = $title;
}
public function show() {
echo "<p>Post: $this->title (Created at: " . $this->createdAt() . ")</p>";
}
}
$post = new Post("First article");
$post->show();
?>
Observations:
- Interfaces are excellent for ensuring that certain methods exist in different classes without enforcing their implementation details.
- Traits allow reusing code across multiple classes without altering the class hierarchy.
- We can combine inheritance, interfaces, and traits to build flexible and easily maintainable OOP applications.
Namespaces in PHP
In large applications, conflicts may occur between classes, functions, or constants with the same name. Namespaces allow us to organize code and avoid these conflicts by grouping elements under a specific "name space."
Namespace syntax
<?php
namespace App\Models;
class User {
public $name;
public function __construct($name) {
$this->name = $name;
}
public function greet() {
echo "Hello, $this->name!<br>";
}
}
?>
Using a namespace
<?php
require 'User.php'; // file that contains the User class with namespace App\Models
// we use the class with the namespace prefix
$user = new App\Models\User("John Smith");
$user->greet();
?>
Alias for namespace
<?php
use App\Models\User as AppUser;
$user = new AppUser("Mary Ionella");
$user->greet();
?>
Notes:
- Namespaces allow organizing code into modules or components.
- They help avoid name conflicts between classes with the same name, for example `User` in different modules.
- Aliases can be created to simplify the usage of classes from long namespaces.
Practical Example: User class + Database class
This example shows how to use OOP to manage users in a MySQL database. We will have two classes: Database for the connection and User for CRUD operations.
<?php
// Class for database connection
class Database {
private $host = "localhost";
private $db = "traffice-test";
private $user = "root";
private $pass = "";
public $pdo;
public function __construct() {
try {
$this->pdo = new PDO("mysql:host={$this->host};dbname={$this->db}", $this->user, $this->pass);
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
die("❌ Connection failed: " . $e->getMessage());
}
}
}
// User class with CRUD operations
class User {
private $db;
public function __construct($database) {
$this->db = $database->pdo;
}
public function create($name, $email) {
$stmt = $this->db->prepare("INSERT INTO users (name, email) VALUES (:name, :email)");
$stmt->execute([':name' => $name, ':email' => $email]);
}
public function readAll() {
$stmt = $this->db->query("SELECT * FROM users");
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
public function update($id, $name, $email) {
$stmt = $this->db->prepare("UPDATE users SET name=:name, email=:email WHERE id=:id");
$stmt->execute([':name' => $name, ':email' => $email, ':id' => $id]);
}
public function delete($id) {
$stmt = $this->db->prepare("DELETE FROM users WHERE id=:id");
$stmt->execute([':id' => $id]);
}
}
// Instantiate database and User class
$db = new Database();
$user = new User($db);
// Example of adding a user (you can use the HTML form below)
if (isset($_POST['create'])) {
$user->create($_POST['name'], $_POST['email']);
}
// Example of update
if (isset($_POST['update'])) {
$user->update($_POST['id'], $_POST['name'], $_POST['email']);
}
// Example of delete
if (isset($_POST['delete'])) {
$user->delete($_POST['id']);
}
// Read all users for display
$users = $user->readAll();
?>
Simple CRUD Form
<form method="post">
<h4>Add User</h4>
name: <input type="text" name="name" required>
Email: <input type="email" name="email" required>
<button type="submit" name="create">Add</button>
</form>
<h4>User List</h4>
<table border="1" cellpadding="5">
<tr><th>ID</th><th>name</th><th>Email</th><th>Actions</th></tr>
<?php foreach ($users as $u): ?>
<tr>
<form method="post">
<td><?php echo $u['id']; ?></td>
<td><input type="text" name="name" value="<?php echo htmlspecialchars($u['name']); ?>"></td>
<td><input type="email" name="email" value="<?php echo htmlspecialchars($u['email']); ?>"></td>
<td>
<input type="hidden" name="id" value="<?php echo $u['id']; ?>">
<button type="submit" name="update">Update</button>
<button type="submit" name="delete">Delete</button>
</td>
</form>
</tr>
<?php endforeach; ?>
</table>
<?php
// Class for database connection
class Database {
private $host = "localhost";
private $db = "traffice-test";
private $user = "traffice_php";
private $pass = "!@y3Ge-Z!WQI";
public $pdo;
public function __construct() {
try {
$this->pdo = new PDO("mysql:host={$this->host};dbname={$this->db}", $this->user, $this->pass);
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
die("❌ Connection failed: " . $e->getMessage());
}
}
}
// User class with CRUD operations
class User {
private $db;
public function __construct($database) {
$this->db = $database->pdo;
}
public function create($name, $email) {
$stmt = $this->db->prepare("INSERT INTO users (name, email) VALUES (:name, :email)");
$stmt->execute([':name' => $name, ':email' => $email]);
}
public function readAll() {
$stmt = $this->db->query("SELECT * FROM users");
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
public function update($id, $name, $email) {
$stmt = $this->db->prepare("UPDATE users SET name=:name, email=:email WHERE id=:id");
$stmt->execute([':name' => $name, ':email' => $email, ':id' => $id]);
}
public function delete($id) {
$stmt = $this->db->prepare("DELETE FROM users WHERE id=:id");
$stmt->execute([':id' => $id]);
}
}
// Instantiate database and User class
$db = new Database();
$user = new User($db);
// Example of adding a user (you can use the HTML form below)
if (isset($_POST['create'])) {
$user->create($_POST['name'], $_POST['email']);
}
// Example of update
if (isset($_POST['update'])) {
$user->update($_POST['id'], $_POST['name'], $_POST['email']);
}
// Example of delete
if (isset($_POST['delete'])) {
$user->delete($_POST['id']);
}
// Read all users for display
$users = $user->readAll();
?>
<form method="post">
<h4>Add User</h4>
Name: <input type="text" name="name" required>
Email: <input type="email" name="email" required>
<button type="submit" name="create">Add</button>
</form>
<h4>User List</h4>
<table border="1" cellpadding="5">
<tr><th>ID</th><th>Name</th><th>Email</th><th>Actions</th></tr>
<?php foreach ($users as $u): ?>
<tr>
<form method="post">
<td><?php echo $u['id']; ?></td>
<td><input type="text" name="name" value="<?php echo htmlspecialchars($u['name']); ?>"></td>
<td><input type="email" name="email" value="<?php echo htmlspecialchars($u['email']); ?>"></td>
<td>
<input type="hidden" name="id" value="<?php echo $u['id']; ?>">
<button type="submit" name="update">Update</button>
<button type="submit" name="delete">Delete</button>
</td>
</form>
</tr>
<?php endforeach; ?>
</table>