2

Say I have a class like this:

class Person
{
    private $value;

    public function __construct()
    {
        $this->value = 'new';
    }

    public static function find( $ident )
    {
        $person = new Person();
        $person->value = 'old';

        return $person;
    }
}

How can I keep the constructor from firing, or diverting it in some way to not execute some of itself if I am calling from the static find function?

The context of my example is identical to that of my real code, except the real code has a perfect amount of overhead so long that only one of the functions is ever executed. (Many objects can exist at the same time, however if the static function calls the __construct method, then there is too much overhead and loading time).

Both need to have public accessors.

3
  • 2
    if the overhead of constructing a new instance is too big, then you are likely doing real work in the ctor. you shouldnt. constructors should only put the object into a valid state. move out the initializing code. Commented Feb 23, 2012 at 18:45
  • i don't get it: What is your goal with this find function? To create a new instance of a person, although already one exists? Commented Feb 23, 2012 at 18:47
  • @Gordon instantiation in the constructor is needed more often then not. When declaring a new instance, it means the object is new in my case because of the backend. I need to instantiate in the constructor because it uses a One-To-One relationship design that Propel-ORM provides easy access to. It's not something I can just "move"... Commented Feb 23, 2012 at 18:49

3 Answers 3

3

You can pass a boolean into your constructor to tell it whether it should execute or not

class Person
{
    private $value;

    public function __construct($exec)
    {
        if(!$exec)
            return;
        $this->value = 'new';
        echo $this->value;  //testing
    }

    public static function find( $ident )
    {
        $person = new Person(false);
        $person->value = 'old';

        return $person;
    }
}

//$p = new Person(true);
$p = Person::find(0);

update using static variable

class Person
{
    private $value;
    protected static $exec1 = true;

    public function __construct()
    {
        if(!self::$exec1)
            return;
        $this->value = 'new';
        echo $this->value;
    }

    public static function find( $ident )
    {
        self::$exec1 = false;
        $person = new Person();
        self::$exec1 = true;
        $person->value = 'old';

        return $person;
    }
}

$p = Person::find(0);
Sign up to request clarification or add additional context in comments.

6 Comments

Allowing public access to modify the intention of the constructor is not allowed in my case.
Instead of using a global, I'd suggest using a protected static attribute. Not half as ugly…
@BrianGraham I suppose you could do the same thing using global (see my update). It is bad practice, but..
@rodneyrehm Ah, good suggestion. Thx. I had to make it public tho
If I understood this right, it was meant to disable something from within the static function. So $exec1 may very well be set (and reset!) within the static function and may thus be protected.
|
2

You can make an if statement in your constructor like following

class Person
{
    private $value;

    public function __construct($val)
    {
        $this->value = empty($val)?"new":$val;
        if($this->value == "new") {
          //call function to do more
        }
    }

    public static function find( $ident )
    {
        $person = new Person("old");
        return $person;
    }
}

now you can make new Person("old") and leave your overhead or do new Person() and have it...

3 Comments

The information being initialized cannot be passed to the constructor, and allowing public access to modify the intention of the constructor is not allowed. Privately modifying it, while allowing public access is available, if possible.
hows about extending the class? So you make your own MyPerson extends Person class and override the constructor?
@Neysor sounds logical. This seems like a problem most easily solved by reconsidering the design (or aspects of it), as it appears to be about the implementation itself as opposed to what it should achieve. One may say the OP has coded themselves into a corner.
2

If you can't go with @Neysor's idea, because you cannot - what so ever - change the constructor's signature, give this (ugly hack) a shot. Bear in mind, that this is something you actually do not want to do in production code. This demo is simply supposed to show that it is indeed possible to use the callstack for conditional execution.

<?php

class Dummy {
    public $was_static = null;

    public function __construct() {
        $this->was_static = false;

        // get current call stack
        $stack = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
        // remove __construct() from stack
        array_shift($stack);
        if ($stack) {
            if ($stack[0]['class'] == __CLASS__) {
                // parent function in stack is a function of Dummy
                $this->was_static = true;
            } elseif ($stack[0]['class'] && is_subclass_of($stack[0]['class'], __CLASS__)) {
                // class the function is part of is a descendent of this class
                $this->was_static = true;
            }            
        }
    }

    public static function make() {
        return new self();
    }
}

class Dummy2 extends Dummy {
    public static function make2() {
        return new self();
    }
}

$d = new Dummy();
var_dump($d->was_static);
$d = Dummy::make();
var_dump($d->was_static);
$d = Dummy2::make2();
var_dump($d->was_static);

/*  OUTPUT:

    bool(false)
    bool(true)
    bool(true)
*/

Although this is possible - DO NOT DO THIS, EVER! If you need to even think about things like these, your API / architecture clearly needs a redesign.

2 Comments

The use of debug_backtrace() had crossed my mind, but I thought it better to pretend that it hadn't. :-)
looking at the result, I whish I hadn't thought of it either :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.