__call & __callStatic
Part of the Object Oriented Programming section of Coddy's PHP journey — lesson 47 of 91.
Just as __get() and __set() intercept property access, the __call() and __callStatic() methods intercept method calls. They're triggered when you call a method that doesn't exist or is inaccessible on an object or class.
The __call() method handles instance method calls. It receives the method name and an array of arguments:
<?php
class Messenger {
public function __call(string $name, array $arguments): string {
return "Called '$name' with: " . implode(", ", $arguments);
}
}
$msg = new Messenger();
echo $msg->sendEmail("Hello", "World");
Output:
Called 'sendEmail' with: Hello, WorldFor static method calls, use __callStatic(). Notice it must be declared as static:
<?php
class QueryBuilder {
public static function __callStatic(string $name, array $arguments): string {
if (str_starts_with($name, "findBy")) {
$field = substr($name, 6);
return "Finding by $field: " . $arguments[0];
}
return "Unknown method: $name";
}
}
echo QueryBuilder::findByEmail("test@example.com");
Output:
Finding by Email: test@example.comThese magic methods are powerful for creating fluent APIs, implementing method forwarding, or building dynamic query builders where method names translate into database operations. They let your objects respond intelligently to any method call, even ones you haven't explicitly defined.
Challenge
EasyLet's build a dynamic API client that uses magic methods to handle method calls flexibly. You'll create a class that intercepts both instance and static method calls, translating them into meaningful API-like responses without defining each method explicitly.
You'll organize your code across two files:
ApiClient.php— Create anApiClientclass that simulates API interactions using magic methods. Your class should have a private$baseUrlproperty set through the constructor. Implement two magic methods:__call()— Handles instance method calls. When a method starting withgetis called (likegetUsersorgetPosts), extract the resource name (the part after "get") and return"GET [baseUrl]/[resource]: [arguments joined by comma]". The resource name should be converted to lowercase. If the method doesn't start with "get", return"Unknown action: [methodName]".__callStatic()— Handles static method calls. When a method starting withcreateis called (likecreateUser), extract the resource name and return"POST /[resource]: [arguments joined by comma]". The resource name should be lowercase. For methods starting withdelete, return"DELETE /[resource]: [first argument]". For any other method, return"Static action not supported: [methodName]".
main.php— Include the ApiClient file. You'll receive three inputs: a base URL, a resource identifier, and a value. Create anApiClientinstance with the base URL. Then print four lines:- Call a dynamic
getmethod using the resource identifier as the method name suffix (e.g., if resource is "Users", callgetUsers) with the value as an argument - Call
getProductswith two arguments:"electronics"and"active" - Call the static method
createOrderwith the value as an argument - Call the static method
deleteItemwith the resource identifier as an argument
- Call a dynamic
The magic methods let your API client respond to any method call dynamically. Instead of defining getUsers(), getPosts(), getProducts(), and dozens more, a single __call() method handles them all by examining the method name and extracting the relevant information.
Cheat sheet
The __call() method intercepts instance method calls that don't exist or are inaccessible. It receives the method name and an array of arguments:
<?php
class Messenger {
public function __call(string $name, array $arguments): string {
return "Called '$name' with: " . implode(", ", $arguments);
}
}
$msg = new Messenger();
echo $msg->sendEmail("Hello", "World");
// Output: Called 'sendEmail' with: Hello, World
The __callStatic() method intercepts static method calls. It must be declared as static:
<?php
class QueryBuilder {
public static function __callStatic(string $name, array $arguments): string {
if (str_starts_with($name, "findBy")) {
$field = substr($name, 6);
return "Finding by $field: " . $arguments[0];
}
return "Unknown method: $name";
}
}
echo QueryBuilder::findByEmail("test@example.com");
// Output: Finding by Email: test@example.com
These magic methods are useful for creating fluent APIs, implementing method forwarding, or building dynamic query builders where method names translate into operations.
Try it yourself
<?php
require_once 'ApiClient.php';
// Read inputs
$baseUrl = trim(fgets(STDIN));
$resource = trim(fgets(STDIN));
$value = trim(fgets(STDIN));
// TODO: Create an ApiClient instance with the base URL
// TODO: Call a dynamic get method using the resource as method name suffix
// Hint: Use variable method calls like $api->{"get" . $resource}($value)
// TODO: Call getProducts with two arguments: "electronics" and "active"
// TODO: Call static method createOrder with the value as argument
// Hint: Use ApiClient::createOrder($value)
// TODO: Call static method deleteItem with the resource as argument
?>This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Fundamentals of OOP
External FilesIntroduction to OOPClasses vs ObjectsThe $this KeywordMethodsPropertiesConstructor (__construct)Destructor (__destruct)Recap - Simple Calculator4Inheritance
Basic InheritanceThe parent:: KeywordMethod OverridingThe final KeywordAbstract ClassesRecap - Employee Hierarchy7Encapsulation
Public, Protected, PrivateAccess Modifiers in DepthGetters and SettersInformation HidingConstructor Promotion (8.0)Recap - Student Records System2Namespaces & Autoloading
Introduction to NamespacesThe use KeywordPSR-4 Autoloading StandardComposer AutoloaderRecap - Organized Project5Interfaces & Contracts
Introduction to InterfacesImplementing InterfacesMultiple Interface ImplementInterface vs Abstract ClassType Hinting with InterfacesRecap - Shape Calculator8Magic Methods
Magic Methods Introduction__toString & __debugInfo__get, __set, __isset, __unset__call & __callStatic__clone & Object Cloning__serialize & __unserializeRecap - Custom Collection11Type System & Error Handling
Type DeclarationsNullable TypesUnion & Intersection TypesException ClassesCustom Exception HierarchyTry, Catch, FinallyRecap - Form Validator14Project: Library Management
Project OverviewBook and User Classes3Class Properties
Instance vs Static PropertiesConstants in ClassesStatic Methods & PropertiesPrivate & Protected PropertiesReadonly Properties (PHP 8.1)Recap - Bank Account Manager6Polymorphism
Method Overriding RevisitedPolymorphism via InterfacesType Hinting & Union TypesLate Static BindingRecap - Payment Processor9Traits
Introduction to TraitsUsing Multiple TraitsTrait Conflict ResolutionAbstract Methods in TraitsTraits vs Inheritance12Design Patterns Part 1
Intro to Design PatternsSingleton PatternFactory PatternObserver PatternStrategy Pattern