Reflection and Attributes

Back

Loading concept...

🔮 PHP Reflection & Attributes: Your Code’s Magic Mirror

The Story Begins…

Imagine you have a magic mirror that can look at any toy in your room and tell you everything about it:

  • What color is it?
  • How many buttons does it have?
  • What can it do?
  • Are there any special stickers on it?

In PHP, Reflection is that magic mirror! It lets your code look at itself and discover its own secrets. And Attributes are like special stickers you put on your toys to give them super powers!


🪞 Reflection Basics: The Magic Mirror

What is Reflection?

Think of a toy robot. Normally, you just play with it. But what if you wanted to know:

  • What parts does it have inside?
  • What buttons make it move?
  • Who made it and when?

Reflection is PHP’s way of asking these questions about code!

// A simple class - like a toy
class Robot {
    public $name = "Beep";
    private $battery = 100;

    public function dance() {
        return "Dancing!";
    }
}

// Using the magic mirror to look at it!
$mirror = new ReflectionClass('Robot');
echo $mirror->getName();  // "Robot"

Why Use Reflection?

Situation Real Life Example Reflection Helps!
Building tools Making a remote control for ALL toys Discover what buttons any toy has
Testing Checking if a toy works properly Peek inside to see hidden parts
Documentation Writing an instruction manual Read what everything does

🏠 ReflectionClass: Looking at the Whole Toy Box

ReflectionClass is like pointing your magic mirror at an entire toy (class) and getting ALL the details!

Creating Your Magic Mirror

// Three ways to create a mirror
class Car {
    public $wheels = 4;
    private $engine = "V8";

    public function drive() {
        return "Vroom!";
    }

    private function startEngine() {
        return "Engine on!";
    }
}

// Way 1: Using class name as string
$mirror1 = new ReflectionClass('Car');

// Way 2: Using an actual object
$myCar = new Car();
$mirror2 = new ReflectionClass($myCar);

// Way 3: Using class constant
$mirror3 = new ReflectionClass(Car::class);

What Can You Discover?

graph TD A["ReflectionClass"] --> B["📦 Properties"] A --> C["⚡ Methods"] A --> D["📋 Class Info"] B --> B1["getName"] B --> B2["getValue"] C --> C1["getParameters"] C --> C2["invoke"] D --> D1["isAbstract"] D --> D2["getParentClass"]

Exploring Properties (What the toy HAS)

$mirror = new ReflectionClass('Car');

// Get ALL properties
$props = $mirror->getProperties();
foreach ($props as $prop) {
    echo $prop->getName() . "\n";
}
// Output: wheels, engine

// Get only PUBLIC properties
$public = $mirror->getProperties(
    ReflectionProperty::IS_PUBLIC
);

Exploring Methods (What the toy DOES)

$mirror = new ReflectionClass('Car');

// Get ALL methods
$methods = $mirror->getMethods();
foreach ($methods as $method) {
    echo $method->getName() . "\n";
}
// Output: drive, startEngine

// Check if method exists
if ($mirror->hasMethod('drive')) {
    echo "Car can drive!";
}

Peek at Private Parts! 🔓

Normally, private things are hidden. But Reflection has a secret key!

class SecretBox {
    private $treasure = "Gold coins!";
}

$box = new SecretBox();
$mirror = new ReflectionClass($box);

// Get the private property
$prop = $mirror->getProperty('treasure');

// Use the secret key!
$prop->setAccessible(true);

// Now we can see it!
echo $prop->getValue($box);
// Output: "Gold coins!"

🏷️ Attributes: Magic Stickers for Your Code

What Are Attributes?

Remember putting stickers on your notebooks to mark them as “IMPORTANT” or “HOMEWORK”?

Attributes in PHP are like those stickers! They add extra information to your code.

// Before PHP 8: We used comments (old way)
/** @deprecated Don't use this! */
function oldWay() { }

// PHP 8+: We use Attributes (new way!)
#[Deprecated("Use newWay() instead")]
function oldWay() { }

Your First Attribute

// The #[...] syntax is like putting a sticker!
#[Attribute]
class MySticker {
    public string $message;

    public function __construct(string $msg) {
        $this->message = $msg;
    }
}

// Using your sticker on a class
#[MySticker("This is special!")]
class SpecialThing {
    // ...
}

Built-in Attributes PHP Gives You

Attribute What It Does Example
#[Deprecated] Marks old code #[Deprecated("Use v2")]
#[AllowDynamicProperties] Lets you add new properties For flexible classes
#[Override] Confirms you’re overriding parent Safety check!
#[SensitiveParameter] Hides sensitive data in errors For passwords
class Animal {
    public function speak() {
        return "...";
    }
}

class Dog extends Animal {
    #[Override]  // Sticker says: "I'm replacing parent!"
    public function speak() {
        return "Woof!";
    }
}

✨ Custom Attributes: Make Your Own Stickers!

Creating Custom Attributes

This is where it gets FUN! You can create your own magic stickers!

// Step 1: Create the sticker template
#[Attribute]
class Route {
    public function __construct(
        public string $path,
        public string $method = 'GET'
    ) {}
}

// Step 2: Use your sticker!
class BlogController {
    #[Route('/posts', 'GET')]
    public function listPosts() {
        return "All posts here!";
    }

    #[Route('/posts/new', 'POST')]
    public function createPost() {
        return "Creating post!";
    }
}

Reading Your Custom Attributes

// Use Reflection to read the stickers!
$mirror = new ReflectionClass(BlogController::class);

foreach ($mirror->getMethods() as $method) {
    $attrs = $method->getAttributes(Route::class);

    foreach ($attrs as $attr) {
        $route = $attr->newInstance();
        echo "Path: {$route->path}\n";
        echo "Method: {$route->method}\n";
    }
}
// Output:
// Path: /posts
// Method: GET
// Path: /posts/new
// Method: POST

Where Can You Put Attributes?

graph TD A["🏷️ Attributes Can Go On..."] --> B["📦 Classes"] A --> C["⚡ Methods"] A --> D["📝 Properties"] A --> E["📥 Parameters"] A --> F["🧩 Functions"] A --> G["📌 Constants"]
#[Attribute(Attribute::TARGET_CLASS)]
class ClassOnly { }  // Only for classes!

#[Attribute(Attribute::TARGET_METHOD)]
class MethodOnly { }  // Only for methods!

#[Attribute(Attribute::TARGET_ALL)]
class Anywhere { }  // Put it anywhere!

Real-World Example: Validation Stickers

#[Attribute(Attribute::TARGET_PROPERTY)]
class Required {
    public string $message;

    public function __construct(
        string $msg = "This field is required!"
    ) {
        $this->message = $msg;
    }
}

#[Attribute(Attribute::TARGET_PROPERTY)]
class MaxLength {
    public function __construct(
        public int $max,
        public string $message = "Too long!"
    ) {}
}

// Using the validation stickers!
class User {
    #[Required]
    #[MaxLength(50)]
    public string $username;

    #[Required("Email is required!")]
    public string $email;
}

Validating with Your Stickers

function validate(object $obj): array {
    $errors = [];
    $mirror = new ReflectionClass($obj);

    foreach ($mirror->getProperties() as $prop) {
        $prop->setAccessible(true);
        $value = $prop->getValue($obj);

        // Check Required
        $required = $prop->getAttributes(Required::class);
        if ($required && empty($value)) {
            $attr = $required[0]->newInstance();
            $errors[] = $attr->message;
        }

        // Check MaxLength
        $maxLen = $prop->getAttributes(MaxLength::class);
        if ($maxLen && strlen($value) > $maxLen[0]->newInstance()->max) {
            $errors[] = $maxLen[0]->newInstance()->message;
        }
    }

    return $errors;
}

🎯 Putting It All Together

The Power Combo: Reflection + Attributes

#[Attribute]
class Inject { }

class Database {
    public function query($sql) {
        return "Results for: $sql";
    }
}

class UserService {
    #[Inject]
    private Database $db;

    public function getUsers() {
        return $this->db->query("SELECT * FROM users");
    }
}

// Auto-inject dependencies!
function createService($className) {
    $mirror = new ReflectionClass($className);
    $obj = $mirror->newInstance();

    foreach ($mirror->getProperties() as $prop) {
        if ($prop->getAttributes(Inject::class)) {
            $type = $prop->getType()->getName();
            $prop->setAccessible(true);
            $prop->setValue($obj, new $type());
        }
    }

    return $obj;
}

$service = createService(UserService::class);

🌟 Key Takeaways

Concept One-Line Summary
Reflection A magic mirror that lets code look at itself
ReflectionClass Shows everything about a class: properties, methods, parents
Attributes Stickers that add metadata to your code
Custom Attributes Your own stickers with your own rules!

🚀 You’re Now a Reflection Wizard!

You’ve learned to:

  • ✅ Use the magic mirror (Reflection) to inspect code
  • ✅ Explore classes with ReflectionClass
  • ✅ Add stickers (Attributes) to your code
  • ✅ Create your own custom stickers!

Think of Reflection as your code’s superpower to understand itself. And Attributes as the labels that give things meaning!

Now go forth and make your PHP code smarter! 🎉

Loading story...

Story - Premium Content

Please sign in to view this story and start learning.

Upgrade to Premium to unlock full access to all stories.

Stay Tuned!

Story is coming soon.

Story Preview

Story - Premium Content

Please sign in to view this concept and start learning.

Upgrade to Premium to unlock full access to all content.