🧰 PHP Class Features: Your Toolbox of Superpowers
Imagine you’re building a LEGO robot. You have your main instruction book (your class), but sometimes you want to:
- Borrow cool tricks from other builders (Traits)
- Share tools that everyone can use without making new copies (Static stuff)
- Set rules that never change (Constants)
- Pack everything faster (Constructor Property Promotion)
Let’s open this magical toolbox! 🎒
🎭 Traits: Borrowing Superpowers
The Story
Think of traits like recipe cards you can share.
You have a Pizza Shop and a Burger Shop. Both need to know how to deliver food. Instead of writing delivery instructions twice, you make ONE recipe card called “DeliveryTrait” and share it with both!
What is a Trait?
A trait is a bundle of methods you can drop into any class. PHP classes can only have ONE parent, but they can use MANY traits!
trait CanFly {
public function fly() {
return "I'm flying! 🦅";
}
}
trait CanSwim {
public function swim() {
return "I'm swimming! 🐟";
}
}
class Duck {
use CanFly, CanSwim;
}
$duck = new Duck();
echo $duck->fly(); // I'm flying! 🦅
echo $duck->swim(); // I'm swimming! 🐟
Key Point: Use use TraitName; inside a class to borrow its powers!
⚔️ Trait Conflict Resolution: When Powers Collide
The Story
What if BOTH your recipe cards say how to make sauce, but with different recipes? 🍅 vs 🧀
You need to pick ONE or rename them!
How Conflicts Happen
Two traits have methods with the same name.
trait Ninja {
public function attack() {
return "Silent strike! 🥷";
}
}
trait Warrior {
public function attack() {
return "Sword slash! ⚔️";
}
}
Resolving the Fight
Option 1: Pick a Winner
class Fighter {
use Ninja, Warrior {
Ninja::attack insteadof Warrior;
}
}
// Uses Ninja's attack only
Option 2: Keep Both with New Names
class Fighter {
use Ninja, Warrior {
Ninja::attack insteadof Warrior;
Warrior::attack as warriorAttack;
}
}
$f = new Fighter();
echo $f->attack(); // Silent strike!
echo $f->warriorAttack(); // Sword slash!
🏠 Static Properties: Shared Storage
The Story
Imagine a classroom whiteboard.
Every student (object) can see the SAME whiteboard. When one student writes on it, everyone sees the change. That’s a static property!
What Makes It “Static”?
- Belongs to the CLASS itself, not individual objects
- All objects share the same value
- Access with
ClassName::$property
class Counter {
public static int $count = 0;
public function increment() {
self::$count++;
}
}
$a = new Counter();
$b = new Counter();
$a->increment();
$b->increment();
echo Counter::$count; // 2 (both added!)
🔧 Static Methods: Tools Without Creating Objects
The Story
A vending machine doesn’t need you to build a new machine to get a soda. You just press a button on THE machine!
Static methods work the same way — call them directly on the class.
When to Use Static Methods
- Utility functions (math helpers, formatters)
- Factory patterns
- Actions that don’t need object data
class Calculator {
public static function add($a, $b) {
return $a + $b;
}
}
// No "new Calculator()" needed!
echo Calculator::add(5, 3); // 8
Inside the class, use self:: to call static members:
class Helper {
public static function greet($name) {
return self::format($name);
}
private static function format($name) {
return "Hello, $name!";
}
}
📌 Class Constants: Values Set in Stone
The Story
The number of days in a week is ALWAYS 7. The value of PI is ALWAYS 3.14159…
Some values should never change. That’s what constants are for!
How Constants Work
class Game {
public const MAX_PLAYERS = 4;
private const SECRET_CODE = 'xyz123';
public function showMax() {
return self::MAX_PLAYERS;
}
}
echo Game::MAX_PLAYERS; // 4
// Game::MAX_PLAYERS = 5; ❌ ERROR!
Key differences from variables:
- No
$sign - UPPERCASE by convention
- Cannot be changed after definition
🎯 Late Static Binding: Who Am I, Really?
The Story
You’re a shapeshifter. When someone asks “Who are you?”, you answer based on your CURRENT form, not your original form!
self:: always points to where code is written.
static:: points to what the object ACTUALLY is.
The Problem with self::
class Animal {
public static function create() {
return new self(); // Always creates Animal!
}
}
class Dog extends Animal {}
$pet = Dog::create();
// $pet is Animal, not Dog! 😕
The Solution: static::
class Animal {
public static function create() {
return new static(); // Creates actual class!
}
}
class Dog extends Animal {}
$pet = Dog::create();
// $pet is Dog! 🐕
Quick Reference
| Keyword | Refers To |
|---|---|
self:: |
Class where code is written |
static:: |
Class that was actually called |
parent:: |
Parent class |
🔒 Readonly Properties: Set Once, Read Forever
The Story
Think of a birth certificate. Once your birthday is written, it should NEVER change. But anyone can read it!
Readonly properties can be:
- Set once (usually in constructor)
- Read anytime
- Never modified after
Syntax (PHP 8.1+)
class User {
public readonly string $id;
public function __construct(string $id) {
$this->id = $id;
}
}
$user = new User('abc123');
echo $user->id; // abc123 ✅
// $user->id = 'xyz'; ❌ ERROR!
Readonly Classes (PHP 8.2+)
readonly class Point {
public function __construct(
public int $x,
public int $y
) {}
}
// All properties are automatically readonly!
🚀 Constructor Property Promotion: The Shortcut
The Story
Instead of writing your shopping list THREE times (list it, carry it, put it away), you do it ONCE and everything happens automatically!
The Old Way (Too Much Typing!)
class Product {
private string $name;
private float $price;
public function __construct(
string $name,
float $price
) {
$this->name = $name;
$this->price = $price;
}
}
The New Way (PHP 8.0+)
class Product {
public function __construct(
private string $name,
private float $price
) {}
}
// That's it! Properties created AND assigned!
You Can Mix Both Styles
class Order {
private string $id;
public function __construct(
public string $customer,
public readonly float $total
) {
$this->id = uniqid();
}
}
🗺️ How It All Connects
graph TD A["PHP Class"] --> B["Traits"] A --> C["Static Members"] A --> D["Constants"] A --> E["Properties"] B --> B1["Share code between classes"] B --> B2["Resolve conflicts with insteadof/as"] C --> C1["Static Properties<br/>Shared by all objects"] C --> C2["Static Methods<br/>No object needed"] D --> D1["Fixed values<br/>Cannot change"] E --> E1["Readonly<br/>Set once only"] E --> E2["Promoted<br/>Shorthand in constructor"] C2 --> F["Late Static Binding"] F --> F1["self:: = written class"] F --> F2["static:: = called class"]
🎓 Quick Summary
| Feature | What It Does | When To Use |
|---|---|---|
| Traits | Share methods between classes | Need same code in unrelated classes |
| Conflict Resolution | Handle duplicate trait methods | Two traits have same method name |
| Static Properties | One shared value for all objects | Counters, configuration, caches |
| Static Methods | Call without creating object | Utilities, factories |
| Constants | Unchangeable values | Fixed settings, magic numbers |
| Late Static Binding | static:: for actual class |
Factory methods, inheritance |
| Readonly Properties | Set once, never change | IDs, timestamps, immutable data |
| Property Promotion | Shorthand constructor | Less boilerplate code |
💡 Pro Tips
- Traits aren’t inheritance — they’re copy-paste at compile time
- Static = Global-ish — use sparingly, can make testing hard
- Constants are cheap — no memory per object
static::saves the day — always use in parent factory methods- Readonly + Promotion = Clean code — combine for maximum power!
You now have a complete toolbox of PHP class features! 🎉
Each tool solves a specific problem. Pick the right one for the job, and your code will be cleaner, safer, and easier to understand.
Happy coding! 🐘✨
