`self::` vs. `static::` in PHP: A Deep Dive into Late Static Binding
Content
## Introduction
In PHP Object-Oriented Programming (OOP), `self` and `static` are two common keywords used to access static members within a class. However, their differing behaviors in inheritance scenarios often cause confusion for developers and can lead to hard-to-trace bugs if misused. This article, using a classic example from a `wiki.lib00.com` project, will break down their differences and help you fully grasp PHP's **Late Static Binding** mechanism.
---
## The Core Difference at a Glance
Simply put, the difference lies in the timing of the "binding":
* `self::$property`: **Static Binding**. `self` always refers to the class where the code is **defined**. This relationship is determined at compile time.
* `static::$property`: **Late Static Binding**. `static` refers to the class that was actually **called at runtime**. This relationship is determined dynamically when the code is executed.
---
## The Code Example That Explains Everything
The best way to understand late static binding is through a practical example. Let's imagine we're building a simple ORM (Object-Relational Mapping) base model for the `lib00` platform. Each model needs a `$table` property to specify its corresponding database table name.
```php
<?php
namespace WikiLib00\Framework;
abstract class BaseModel {
// Define a default table name in the parent class
protected static string $table = 'base_models';
// Get the table name using `self`
public static function getSelfTable(): string {
// `self` always refers to BaseModel because it's defined here
return self::$table;
}
// Get the table name using `static`
public static function getStaticTable(): string {
// `static` refers to the class called at runtime (e.g., UserModel or ProductModel)
return static::$table;
}
}
class UserModel extends BaseModel {
// Override the parent's static property in the child class
protected static string $table = 'users';
}
class ProductModel extends BaseModel {
// Override the parent's static property in the child class
protected static string $table = 'products';
}
// --- Check the results ---
// Calling from UserModel
echo 'UserModel::getSelfTable(): ' . UserModel::getSelfTable(); // Outputs: base_models
echo "\n";
echo 'UserModel::getStaticTable(): ' . UserModel::getStaticTable(); // Outputs: users
echo "\n\n";
// Calling from ProductModel
echo 'ProductModel::getSelfTable(): ' . ProductModel::getSelfTable(); // Outputs: base_models
echo "\n";
echo 'ProductModel::getStaticTable(): ' . ProductModel::getStaticTable(); // Outputs: products
```
---
## Analyzing the Output
* **`UserModel::getSelfTable()`** returns `'base_models'`. Because the `getSelfTable()` method is defined in `BaseModel`, the `self` keyword is "locked" to the `BaseModel` class. No matter which child class calls it, it will only return the `$table` property defined in `BaseModel`.
* **`UserModel::getStaticTable()`** returns `'users'`. The `static` keyword enables late static binding. It doesn't lock to a class immediately. Instead, it waits until runtime to see who actually **called** the `getStaticTable()` method. In this case, the caller is `UserModel`, so `static` resolves to `UserModel` and returns its `$table` property.
---
## When to Use `self` vs. `static`?
Once you understand the difference, making the choice becomes simple:
* **Use `self`**: When you explicitly need to refer to a constant or static member defined in the **current class itself**, and you do not want it to be changed by the inheritance chain. For example, a fixed version number or a configuration item defined in a base class.
* **Use `static`**: When you are designing **extensible base classes or frameworks** where methods in the parent class need to flexibly use static members overridden in child classes. Table names in an ORM, or class names in a Factory pattern, are classic use cases for `static`. This approach makes the code more flexible and adheres to the Open/Closed Principle.
---
## Conclusion
The `static::` keyword is the key to PHP's Late Static Binding, significantly enhancing code flexibility and reusability. A key recommendation from the author `DP` is to prefer `static` for referencing static members when writing inheritable classes. This will allow you to build more powerful and adaptable systems.
Related Contents
Resolving PHP "could not find driver" Error: Ultimate Guide to Missing PDO Database Drivers
Duration: 00:00 | DP | 2026-07-04 08:03:00VS Code PHP Guide: How to Trace Function Definitions Like PHPStorm
Duration: 00:00 | DP | 2026-07-04 20:27:00Resolving Nginx Permission Denied (13) Errors for WebP Images Generated by PHP Imagick
Duration: 00:00 | DP | 2026-07-05 21:17:00Fixing Nginx 500 Error: Internal Redirection Cycle (SPA vs PHP Config)
Duration: 00:00 | DP | 2026-07-02 21:45:50Stop Making Timezone Mistakes in PHP: The Ultimate Guide to time() and UTC
Duration: 00:00 | DP | 2026-06-25 11:29:00Beyond 99.9%: A Deep Dive into a User-Centric Weighted Sampling Algorithm for Availability
Duration: 00:00 | DP | 2026-06-26 12:57:00PHP Log Aggregation Performance Tuning: Database vs. Application Layer - The Ultimate Showdown for Millions of Records
Duration: 00:00 | DP | 2026-01-06 08:05:09MySQL TIMESTAMP vs. DATETIME: The Ultimate Showdown on Time Zones, UTC, and Storage
Duration: 00:00 | DP | 2025-12-02 08:31:40The Ultimate 'Connection Refused' Guide: A PHP PDO & Docker Debugging Saga of a Forgotten Port
Duration: 00:00 | DP | 2025-12-03 09:03:20The Ultimate PHP Guide: How to Correctly Handle and Store Markdown Line Breaks from a Textarea
Duration: 00:00 | DP | 2025-11-20 08:08:00Stop Mixing Code and User Uploads! The Ultimate Guide to a Secure and Scalable PHP MVC Project Structure
Duration: 00:00 | DP | 2026-01-13 08:14:11Mastering PHP: How to Elegantly Filter an Array by Keys Using Values from Another Array
Duration: 00:00 | DP | 2026-01-14 08:15:29Stop Manual Debugging: A Practical Guide to Automated Testing in PHP MVC & CRUD Applications
Duration: 00:00 | DP | 2025-11-16 16:32:33Mastering PHP Switch: How to Handle Multiple Conditions for a Single Case
Duration: 00:00 | DP | 2025-11-17 09:35:40PHP String Magic: Why `{static::$table}` Fails and 3 Ways to Fix It (Plus Security Tips)
Duration: 00:00 | DP | 2025-11-18 11:10:21Can SHA256 Be "Decrypted"? A Deep Dive into Hash Function Determinism and One-Way Properties
Duration: 00:00 | DP | 2025-11-19 04:13:29The Magic of PHP Enums: Elegantly Convert an Enum to a Key-Value Array with One Line of Code
Duration: 00:00 | DP | 2025-12-16 03:39:10One-Click Code Cleanup: The Ultimate Guide to PhpStorm's Reformat Code Shortcut
Duration: 00:00 | DP | 2026-02-03 09:34:00Recommended
The Ultimate Guide to MySQL Partitioning: From Creation and Automation to Avoiding Pitfalls
00:00 | 141Is database performance becoming a bottleneck with...
The Ultimate MinIO Docker Deployment Guide: From Public Access to Nginx Reverse Proxy Pitfalls
00:00 | 113This article is a comprehensive, hands-on guide de...
NVM/Node Command Not Found in New macOS Terminals? A Two-Step Permanent Fix!
00:00 | 167A comprehensive guide to fixing the common "comman...
PHP Dependency Injection in Practice: Resolving the 'Too Few Arguments' Fatal Error in Controllers
00:00 | 83Injecting the Request object via the constructor i...