Published in PHP
PHP Magic Methods Explained
By Atakan Demircioğlu
Fullstack Developer
PHP Magic methods explained. What are the PHP Magic methods?
PHP Magic Methods Explained
Here are my notes about PHP Magic methods.
What are PHP Magic Methods?
- special methods that are called automatically when certain conditions are met
- start with a double underscore ( __ )
- predefined
- neither can be created nor removed
- automatically called
- All magic methods, with the exception of __construct(), __destruct(), and __clone(), must be declared as
public
, otherwise anE_WARNING
is emitted.
__construct Magic Method
- automatically every time the object of a particular class is created
- useful to initialization what the object may need before going further
__destruct Magic Method
- called when the object is destroyed
__call Magic Method
- triggered when we call a method that doesn’t define yet
__callStatic Magic Method
- similar to the __call() method but this is for static context.
__get Magic Method
- called when an inaccessible variable or non-existing variable is used
__set Magic Method
- called when an inaccessible variable or non-existing variable is written
__isset Magic Method
- triggered by calling isset() or empty() on inaccessible (protected or private) or non-existing properties.
__unset Magic Method
- invoked when unset() is used on inaccessible (protected or private) or non-existing properties.
__toString Magic Method
- called when we need to convert the object into a string
__invoke Magic Method
- called when the object is being called as a function
__clone Magic Method
- triggered where cloning objects is done by using the clone keyword
__debugInfo Magic Method
- triggered when the var_dump function is called
__sleep Magic Method
- serialize() function triggers
- should return an array holding all the object’s properties that should be included in the serialized version of that object.
- For resource types, PHP fails at serializing it
__wakeup Magic Method
- need to initialize the value whenever we get a new fresh instance from the unserialize function, and that’s what we’re doing inside the __wakeup method.
__serialize() and __unserialize()
- serialize() checks if the class has a function with the __serialize() magic method. If yes, the function is executed first before any serialization operation.
- If there are both __serialize and _sleep in the same object, just serialize will be called.
Note: For a better understanding of what is happening in __sleep and __wakeup magic methods, you can read this article.
Real Life Example
(__get, __set, __isset, __unset)
<?php
class PSession
{
/**
* @var array
*/
private array $options = [];
/**
* @var array|string[]
*/
private array $phpSessionValidOptions = [
'save_path',
'name',
'save_handler',
'auto_start',
'gc_probability',
'gc_divisor',
'gc_maxlifetime',
'serialize_handler',
'cookie_lifetime',
'cookie_path',
'cookie_domain',
'cookie_secure',
'cookie_httponly',
'cookie_samesite',
'use_strict_mode',
'use_cookies',
'use_only_cookies',
'referer_check',
'cache_limiter',
'cache_expire',
'use_trans_sid',
'trans_sid_tags',
'trans_sid_hosts',
'sid_length',
'sid_bits_per_character',
'upload_progress.enabled',
'upload_progress.cleanup',
'upload_progress.prefix',
'upload_progress.name',
'upload_progress.freq',
'upload_progress.min-freq',
'lazy_write'
];
/**
* @param array $options
* @throws InvalidOption
*/
public function __construct(array $options = [])
{
// if includes non valid php session options
foreach ($options as $key => $value) {
if (!in_array($key, $this->phpSessionValidOptions)) {
throw new InvalidOption($key);
}
}
$this->options = $options;
}
/**
* @return bool
*/
public function start(): bool
{
return session_start($this->options);
}
/**
* @return bool
*/
public function destroy(): bool
{
return session_destroy();
}
/**
*
*/
public function clear(): void
{
session_unset();
}
/**
* @return bool
*/
public function regenerateId(): bool
{
return session_regenerate_id();
}
/**
* @return string
*/
public function getId(): string
{
return session_id();
}
/**
* @param string $id
*/
public function setId(string $id): void
{
session_id($id);
}
/**
* @return string
*/
public function getName(): string
{
return session_name();
}
/**
* @param string $name
*/
public function setName(string $name): void
{
session_name($name);
}
/**
* @return array
*/
public function all(): array
{
return $_SESSION ?? [];
}
/**
* @return bool
*/
public function isStarted(): bool
{
return $this->getStatus() === PHP_SESSION_ACTIVE;
}
/**
* @return int
*/
public function getStatus(): int
{
return session_status();
}
/**
* @return bool
*/
public function isNotStarted(): bool
{
return $this->getStatus() === PHP_SESSION_NONE;
}
/**
* @return bool
*/
public function isDestroyed(): bool
{
return $this->getStatus() === PHP_SESSION_DISABLED;
}
/**
* @param string $key
* @return mixed|null
*/
public function __get(string $key)
{
return $this->get($key, null);
}
/**
* @param string $key
* @param $value
*/
public function __set(string $key, $value): void
{
$this->set($key, $value);
}
/**
* @param string $key
* @param null $defaultValue
* @return mixed|null
*/
public function get(string $key, $defaultValue = null)
{
$keys = explode('.', $key);
$session = $_SESSION;
foreach ($keys as $key) {
// allow both object and array access
if (is_array($session) && isset($session[$key])) {
$session = $session[$key];
} elseif (is_object($session) && isset($session->$key)) {
$session = $session->$key;
} else {
return $defaultValue;
}
}
return $session ?? $defaultValue;
}
/**
* @param string $key
* @param null $value
*/
public function set(string $key, $value = null): void
{
// both object and array access
$keys = explode('.', $key);
$session = &$_SESSION;
foreach ($keys as $key) {
if (is_array($session) && !isset($session[$key])) {
$session[$key] = [];
} elseif (is_object($session) && !isset($session->$key)) {
$session->$key = [];
}
if (is_array($session)) {
$session = &$session[$key];
} elseif (is_object($session)) {
$session = &$session->$key;
}
}
$session = $value;
}
/**
* @param string $key
* @return bool
*/
public function __isset(string $key): bool
{
return $this->has($key);
}
/**
* @param string $key
* @return bool
*/
public function has(string $key): bool
{
return isset($_SESSION[$key]);
}
/**
* @param string $key
*/
public function __unset(string $key): void
{
$this->remove($key);
}
/**
* @param string $key
*/
public function remove(string $key): void
{
unset($_SESSION[$key]);
}
}
Useful video for a better understanding
References
- https://medium.com/@lukaspereyra8/php-sleep-and-wakeup-magic-methods-how-and-when-to-use-them-938591584bdc
- https://www.php.net/manual/en/resource.php
- https://www.geeksforgeeks.org/what-are-magic-methods-and-how-to-use-them-in-php/
Recommended Articles;
How To Secure PHP Sessions?
My notes about how to secure PHP Sessions, what is session hijacking, and so on.atakde.medium.com
PHP Loops — Which is faster?
Foreach vs for in PHP, which is the fastest loop in PHP?atakde.medium.com
JIT Compiler in PHP
Here are my notes about the JIT compiler in PHP.atakde.medium.com