andrewtweber
andrewtweber

Reputation: 25569

How to track nested object creation

I have a parent class and multiple children that inherit from it.

Some children will call other children within themselves. But they are not always called nested.

class Parent { }

class Child extends Parent {
    public function run() {
        // Kid nested inside Child. Do not open DB transaction
        $a = (new Kid())->run();
    }
}

class Kid extends Parent {
    public function run() {
        // @todo Open DB transaction if not nested
    }
}

// Kid not nested. Open DB transaction
(new Kid())->run();

Is there an efficient way for the Kid object to know (without being manually told by me) whether it was instantiated inside or outside of Child?

Upvotes: 0

Views: 67

Answers (2)

RomanPerekhrest
RomanPerekhrest

Reputation: 92854

Use debug_backtrace function to trace the run method calls.
Among all possible returned elements from debug_backtrace(), class item should be traced in your case.
If there's more than one class item within stack trace - it's a "nested" invocation:

class Parent { }

class Child extends Parent {
    public function run() {
        // Kid nested inside Child. Do not open DB transaction
        $a = (new Kid())->run();
    }
}

class Kid extends Parent {
    public function run() {
        $trace = debug_backtrace();
        // Note that 'array_column' function is available since PHP 5.5        
        if (count(array_column($trace, 'class')) > 1) {
            // Do not open DB transaction
            // do another job
        } else {
            // Open DB transaction
        }
        unset($trace);
    }
}

// Kid not nested. Open DB transaction
(new Kid())->run();

(new Child())->run(); // Kid nested inside Child. Do not open DB transaction  

http://php.net/manual/en/function.debug-backtrace.php

Upvotes: 0

Machavity
Machavity

Reputation: 31654

Without knowing how your code is structured, the only way I could think of is to make two child classes (we'll call them Kid1 and Kid2). All they would do is

class Kid1 extends Kid {}

Then you would call

class Child extends Parent {
    public function run() {
        // Kid nested inside Child. Do not open DB transaction
        $a = (new Kid1())->run();
    }
}

class Kid extends Parent {
    public function run() {
        // @todo Open DB transaction if not nested
        if($this instanceof Kid2) // Open DB
    }
}

Yes, you're still telling Kid what called it, but it fits with OOP practices

Upvotes: 1

Related Questions