Instantiate an Object from Variables
Results 1 to 10 of 10

Thread: Instantiate an Object from Variables

  1. #1
    Code Monkey
    Join Date
    Oct 2002
    Location
    Delaware
    Posts
    308

    Instantiate an Object from Variables

    I'm writing some dependency injection code for a framework and what I'm trying to accomplish is so that, if someone were to type the following code:

    PHP Code:
    $FW->member($arg
    It includes the FW class file (done -- accomplished using spl_autoload_register), then instantiate the FW class. I'm attempting to do that via set_error_handler(). If you try to use a class object that doesn't exist, it throws back error 8. I test for this, get the variable name they were attempting to use (FW) and load the class file.

    Now, let's say I have the string 'FW' in a variable.

    Is it even possible to instantiate it or, for that fact, even have that line of code run again, since I'm just now thinking that the error is going to be given after the line of code executes. Is there maybe a way to have it thrown as a catchable exception instead of an error?

    Hopeless endeavor?
    Lackey @ Large

  2. #2
    Pna lbh ernq guvf¿
    Join Date
    Jul 2004
    Location
    Kansas City area
    Posts
    19,353
    Quote Originally Posted by Wynder View Post
    Now, let's say I have the string 'FW' in a variable.

    Is it even possible to instantiate it or, for that fact, even have that line of code run again, since I'm just now thinking that the error is going to be given after the line of code executes
    You mean like:
    PHP Code:
    <?php

    class Foo {
        function 
    bar() {
            echo 
    "hi!";
        }
    }

    $class 'Foo';
    $method 'bar';

    $obj = new $class;
    $obj->$method();
    ?

    However, it sounds like you're trying to make up for the mistakes of a programmer with code that attempts to do what the programmer should have done. I personally think this is a bad approach... if you've detected poorly written code, halt the execution of that code and make the programmer fix it the right way.

    EDIT: The above wasn't meant to suggestion that dependency injection is in any way a bad design (while I never got comfortable with it, I rather liked the idea). I've seen some clever ways to go about doing it... but I can't think of a use case where what you're describing would be one of them.
    Last edited by bradgrafelman; 02-22-2013 at 12:24 PM.

  3. #3
    Code Monkey
    Join Date
    Oct 2002
    Location
    Delaware
    Posts
    308
    Brad,

    I get what you mean and, for the most part, I agree -- I'm not really sure I'll actually use this, but I thought I'd give due diligence into the research.

    I'm writing this framework for the college where I work -- it's essentially a collection of classes that perform various functions. For instance, a Student class for routines relating to students, and LDAP class for methods that relate to pulling information from Active directory, etc.

    Currently, every time I serve a page, the whole of the framework gets included and loaded, hence the dependency injection. Just from a performance/resource standpoint it makes sense. Trapping the error and trying to include the file, instantiate the object and rerun the code that caused the error is, I guess more to keep the "flow" going when your writing in a zone... to know you can just call a method in one of the established classes and not worry about having to go up to the top of the page and instantiate it.

    But yeah, the more I think about it, the more I think it's probably not a wholly great idea.

    Maybe if I have a class wrapper like $Framework->$Student->method() and $Framework can trap for the child object and instantiate it before going on to that method.

    In any case, I appreciate the feedback and thoughts.
    Lackey @ Large

  4. #4
    Code Monkey
    Join Date
    Oct 2002
    Location
    Delaware
    Posts
    308
    Meh,

    I think I'll still run into issues... if I have something like this:

    Class 1:
    PHP Code:
    class Test
    {
       public function 
    foo()
       {
          echo 
    "Here.";
       }

    Class 2:
    PHP Code:
    class OtherTest
    {
       public function 
    bar()
       {
          global 
    $Test;

          
    $Test->foo();
       }

    Execution Code (using spl_autoload_register w/anonymous function for dependency injection):
    PHP Code:
    $OtherTest = new OtherTest;

    $OtherTest->bar(); 
    Test obviously won't come through on the global scope, and it will never get loaded by autoload function because it's not being instantiated. Is there any logic around this other than testing to see if $Test is an object in every method after I pull it from the global scope?
    Lackey @ Large

  5. #5
    Senior Member Derokorian's Avatar
    Join Date
    Apr 2011
    Location
    Denver
    Posts
    1,740
    I think I'm missing what your saying, but just because a variable is named $Test does not guaruntee that it is referencing the Test class. This is why you need to instantiate the variable first, if you don't want to be calling the construct or you want a SINGLE instantiation of said object, well then that's a candidate for the Singleton Pattern. An example:

    PHP Code:
    class Test
    {

       private function 
    __construct()
       {
          
    // set up the object as required
       
    }
     
       public function 
    getInstance()
       {
          static 
    $_inst NULL;
          if( 
    is_null($_inst) ) $_inst = new Test();
          return 
    $_inst;
       }
    }

    $Test Test::getInstance(); 
    Otherwise you're saying "For every undefined variable, see if that variable name matches a class name and attempt to instantiate that class into the variable" and this seems like bad practice. Instead you should explicitly be saying variable $x is an instance of class Y.
    Sadly, nobody codes for anyone on this forum. People taste your dishes and tell you what is missing, but they don't cook for you. ~anoopmail
    I'd rather be a comma, then a full stop.
    User Authentication in PHP with MySQLi - Don't forget to mark threads resolved - MySQL(i) warning

  6. #6
    Code Monkey
    Join Date
    Oct 2002
    Location
    Delaware
    Posts
    308
    Thanks for all of the feedback, guys. I'm going to wind up overloading the constructor with objects that it may use for a given page load... At least this way, the skeleton of the class properties and constructor will be uniform.

    I have my autoload code in my session file:

    PHP Code:
    spl_autoload_register(function ($class)
    {
        
    $cFilePath _CLASSLIB_ "/class.$class.php";
        
        if(
    file_exists($cFilePath))
        {
            include(
    $cFilePath);
        }
        else
        {
            die(
    "Unable to include the $class class.");
        }
    }); 
    In my index.php (for example), I'll have this:

    PHP Code:
    <?php 
    include('include/session.php');

    $Framework = new Framework();  //Instantiate Framework object.
    $Test = new Test(array('Framework' => $Framework)); //Instantiate Test, pass it the Framework name and object.

    $Test->test(); //Run the test method in the Test class.
    ?>
    And, in the Test class file:

    PHP Code:
    class Test
    {
        protected 
    $Framework null//Have properties setup for any class this class may utilize.
        
            //Overload.
        
    public function __construct()
        {
            
    $args func_get_args(); //Get the array with the name and object.
            
            
    foreach($args as $arg//Iterate through.
            
    {
                foreach(
    $arg as $className => $classObject)
                {
                                    
    //Handle the class library possibilities.
                    
    switch($className)
                            {
                        case 
    'Framework:
                                $this->Framework = $classObject; //Assign it in.
                                break;
                    }
                }
            }
        }
        
        public function test()
        {
            echo $this->Framework->getCampusNameFromID(2); //Voila.
        }

    Lackey @ Large

  7. #7
    Senior Member Derokorian's Avatar
    Join Date
    Apr 2011
    Location
    Denver
    Posts
    1,740
    Note I'd probably not used a named instance pair array, and instead use instanceof in a series of ifs:

    PHP Code:
    // ...
    public function __construct(Array $arr)
    {
       foreach( 
    $arr as $obj ) {
          if( 
    $obj instanceof Framework )
             
    $this->Framework $obj;
          elseif( 
    $obj instanceof Config )
             
    $this->Config $obj;
       }
    }
    // ...

    $F = new Framework();
    $C = new Config();
    $T = new Test(array($F,$C)); 
    If for no other reason than you won't end up with errors if someone did something like new Test(array('Framework',new Config())); or something. And it allows you to use a parent class, and it will work if its inherited from that class (or implements the passed interface).
    Sadly, nobody codes for anyone on this forum. People taste your dishes and tell you what is missing, but they don't cook for you. ~anoopmail
    I'd rather be a comma, then a full stop.
    User Authentication in PHP with MySQLi - Don't forget to mark threads resolved - MySQL(i) warning

  8. #8
    Code Monkey
    Join Date
    Oct 2002
    Location
    Delaware
    Posts
    308
    Nice! I had forgotten about instanceof -- thanks for the reminder.
    Lackey @ Large

  9. #9
    Senior Member Derokorian's Avatar
    Join Date
    Apr 2011
    Location
    Denver
    Posts
    1,740
    Or, if the class is truly dependent on a certain class or classes being passed it, I would make it explicit with typehinting like:

    PHP Code:
    // ...
    public function __construct(Framework $FConfig $CSomething $S)
    {
       
    $this->Framework $F;
       
    $this->Config $C;
       
    $this->Something $S;
    }
    // ... 
    And if the Required classes aren't passed in, you will get an error. Same as if you pass in something of the wrong type. Again giving a specific contract to the class. Because if you specifically say you need class X what happens when you just assume you have it? For example, given your method, if I don't pass in array('Framework', new Framework()) to the constructor then your test method will give you an error a long the lines of "Fatal error: Call to a member function getCampusNameFromID() on a non-object on line #"
    Sadly, nobody codes for anyone on this forum. People taste your dishes and tell you what is missing, but they don't cook for you. ~anoopmail
    I'd rather be a comma, then a full stop.
    User Authentication in PHP with MySQLi - Don't forget to mark threads resolved - MySQL(i) warning

  10. #10
    Code Monkey
    Join Date
    Oct 2002
    Location
    Delaware
    Posts
    308
    After thinking a bit more, I'm thinking I may do a ClassLoader class that all of my other class libraries will extended... pass an array of the Class names I want to instantiate into that constructor which will set the corresponding properties. At least it'll be uniform that way.
    Lackey @ Large

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •