Skip to main content

Magic Methods

Chapter Overview

In this chapter you will learn:

  • What magic methods are
  • Why magic methods exist
  • Object lifecycle
  • Dynamic properties
  • Serialization
  • Method overloading
  • Cloning
  • Object invocation
  • Debugging helpers
  • Real-world examples
  • Laravel examples
  • PocketMine examples
  • Enterprise usage

What are Magic Methods?

Magic methods are special methods in PHP that begin with:

__

(two underscores)

Example:

__construct()

They allow PHP to automatically execute code during specific events.

Examples:

Object Creation
Object Destruction
Property Access
Method Calls
Serialization
Cloning
Printing Objects

List of Magic Methods

__construct()
__destruct()

__get()
__set()
__isset()
__unset()

__call()
__callStatic()

__toString()

__invoke()

__clone()

__sleep()
__wakeup()

__serialize()
__unserialize()

__debugInfo()

Object Lifecycle

Create Object

Constructor

Use Object

Destroy Object

Magic methods allow us to control this process.



__construct()


What is Constructor?

Constructor runs automatically when object is created.


Example:

class Player {

public function __construct() {

echo "Player Created";

}

}

Usage:

$player =
new Player();

Output:

Player Created

Constructor with Parameters

class Player {

public function __construct(
private string $name
) {

}

}

Usage:

$player =
new Player(
"Aayan"
);

Why Constructors Exist

To initialize objects.


Examples:

Database Connections
Configurations
Services
Dependency Injection

Real Example

class Database {

public function __construct() {

$this->connect();

}

}

Laravel Example

public function __construct(
UserRepository $users
)

Dependency Injection.



__destruct()


Destructor runs automatically when object is destroyed.


Example:

class Test {

public function __destruct() {

echo "Destroyed";

}

}

Usually runs:

End of Script

or when object has no references.


Real Example

class Database {

public function __destruct() {

$this->connection
->close();

}

}

Use Cases

Closing Files
Closing Database Connections
Logging
Cleanup


__toString()


Called when object is treated as a string.


Example:

class User {

public function __toString()
: string {

return "Aayan";

}

}

Usage:

$user =
new User();

echo $user;

Output:

Aayan

Without __toString():

Fatal Error
Object cannot be converted to string

Real Example

class Position {

public function __toString()
: string {

return
$this->x .
"," .
$this->y .
"," .
$this->z;

}

}

Output:

100,64,200


__get()


Called when accessing inaccessible properties.


Example:

class User {

private array $data = [];

public function __get(
string $name
) {

return
$this->data[$name]
?? null;

}

}

Usage:

echo $user->name;

Even if property doesn't exist.


Real Example

Laravel uses this heavily.

Example:

$user->posts

Internally:

__get()

loads relation.



__set()


Called when assigning inaccessible properties.


Example:

class User {

private array $data = [];

public function __set(
string $name,
mixed $value
) {

$this->data[$name]
= $value;

}

}

Usage:

$user->name =
"Aayan";


__isset()


Called by:

isset()

Example:

public function __isset(
string $name
)
{
return isset(
$this->data[$name]
);
}

Usage:

isset(
$user->name
);


__unset()


Called when:

unset()

is used.


Example:

public function __unset(
string $name
)
{
unset(
$this->data[$name]
);
}


Dynamic Property System

Visualization:

$user->name

__set()

internal array

Laravel models work similarly.



__call()


Called when calling inaccessible methods.


Example:

class User {

public function __call(
string $method,
array $arguments
) {

echo
"Method:
$method";

}

}

Usage:

$user->hello();

Output:

Method: hello

Why Useful?

Create dynamic APIs.


Laravel Example

User::whereName(
"Aayan"
);

Internally uses:

__call()


__callStatic()


Same as __call()

But for:

Static Methods

Example:

class User {

public static function __callStatic(
string $method,
array $arguments
) {

}

}

Usage:

User::findByName();


__invoke()


Makes object callable like a function.


Example:

class Hello {

public function __invoke() {

echo "Hello";

}

}

Usage:

$hello =
new Hello();

$hello();

Output:

Hello

Real Example

Middleware systems often use:

$middleware(
$request
);


__clone()


Called when object is cloned.


Example:

class User {

public function __clone() {

echo "Cloned";

}

}

Usage:

$user2 =
clone $user1;

Why?

Objects are copied.

Sometimes IDs should reset.


Example:

public function __clone() {

$this->id = null;

}


__sleep()


Older serialization method.

Called before:

serialize()

Example:

public function __sleep()
{
return ["name"];
}


__wakeup()


Called after:

unserialize()

Example:

public function __wakeup() {

$this->connect();

}


__serialize()

PHP 7.4+

Modern serialization method.


Example:

public function __serialize()
: array {

return [

"name" =>
$this->name

];

}


__unserialize()


Example:

public function __unserialize(
array $data
)
{
$this->name =
$data["name"];
}


Why Serialization Exists

Examples:

Caching
Sessions
Saving Objects
Queue Systems


__debugInfo()


Called when:

var_dump()

is executed.


Example:

public function __debugInfo()
{
return [

"name" => "Aayan"

];
}

Usage:

var_dump(
$user
);


Real World Example


ORM Models

Laravel models heavily use:

__get()
__set()
__call()

Dependency Containers

Often use:

__invoke()

Service Providers

Use:

__callStatic()

PocketMine Examples


Position Objects

Could implement:

__toString()

Config Wrappers

Can use:

__get()
__set()

Event Dispatchers

Can use:

__invoke()


Visualization

Object

├── __construct()
├── __get()
├── __set()
├── __call()
├── __invoke()
├── __clone()
└── __destruct()

Common Beginner Mistakes


Abusing __get()

Makes debugging difficult.


Creating Everything Dynamically

Static code is easier to understand.


Overusing Magic Methods

Too much magic:

Creates confusing code.

Good Usage

✅ ORMs

✅ Dynamic APIs

✅ Caching

✅ Service Containers


Bad Usage

❌ Everything hidden.

❌ Replacing normal methods.

❌ Making code impossible to understand.


Exercises


Exercise 1

Create:

User

using:

__get()
__set()

Exercise 2

Create:

Position

with:

__toString()

Exercise 3

Create:

Logger

using:

__invoke()

Mini Project

Create:

Zyro User Model

Features:

Dynamic Attributes
Serialization
String Conversion
Method Overloading

Implement:

__get()
__set()
__serialize()
__toString()

Interview Questions


What are magic methods?

Special methods automatically called by PHP.


Which magic method runs when object is created?

__construct()

Which magic method runs when object becomes string?

__toString()

Which method handles unknown properties?

__get()
__set()

Which method makes objects callable?

__invoke()

Which method handles cloning?

__clone()

Summary

Magic Methods allow:

✅ Dynamic APIs

✅ Object Lifecycle Control

✅ Serialization

✅ Method Overloading

✅ Framework Features

✅ ORMs and Containers

They are extremely powerful but should be used carefully.


References

https://www.php.net/manual/en/language.oop5.magic.php


Next Chapter

➡ Enums

➡ Namespaces

➡ Autoloading

➡ Dependency Injection