tags:

views:

518

answers:

10

I am experimenting with PHP OOP

what i'm trying to find out is, Is it possible to access a object instance from withing a object that was created in this object instance?

sounds confusing, so here is a example:

contents of index


    class mainclass {
        var $data;
        function __construct($data){
            $this->data = $data;
        }
        function echodata(){
            echo $this->data;
        }
        function start($classname){
            include $classname.'.php';
            $inner = new $classname();
            $inner->show();
        }

    }

    $mainclass = new mainclass('maininfostuff');
    $mainclass->start('innerclass');



    //i want it to echo "maininfostuff"

contents of innerclass.php


class innerclass{
        function show(){
            mainclass->echodata();//the problem is here
        }
}

the purpose of this test case is to make the inner class decide if/when to run the mainclass echodata function

how can the above example be accomplished? (without relying on static classes or singletons or extended classes)

edit: due to some confusion in answers i have edited the example

+1  A: 

No. When you create an object as a member of another object:

$this->my_new_object = new classname(a,b,c);

there is to my knowledge no way to access the parent element. You would have to pass a reference to the parent element to the object when you create it:

class innerclass(){

  private $parent; // Reference to the parent object

 function __construct(&$parent)
   {
   $this->parent = $parent; 
   }

function show(){
   $this->parent->echodata();
  }
 }

A class definition, though, should never ever reside in a function, even though it may be possible. Class definitions can have a hierarchy - they can extend each other. But that is invoked using extends. A class can extend another. Their definition is still side by side, they are not nested in the code.

I don't know what you are trying to do, but maybe what you are looking for is extending a class. In that case, you can access functions and variables defined in the parent using the parent keyword:

function show(){
parent::echodata();
}

that is, however, something fundamentally different from what you're doing right now.

Pekka
yes, it definitely is different.
YuriKolovsky
+3  A: 

The only way for the inner class to have access to the outer class is for the outer instance to be passed to the inner class's constructor and for it to be saved in an instance variable.

Ignacio Vazquez-Abrams
+1  A: 

I've personally never seen a class defined inside another class's methods before, so if it actually works at all, I'm greatly surprised. (I'm even more surprised about why you'd want/need this, but anyway...)

Just pass the current (outer) object to the inner object when you construct it.

class InnerClass {
    var $outer;
    function __construct(&$outer) {
        $this->outer = $outer;
    }
    function someStuff() {
        $this->outer->doStuff();
    }
}

$innerObj = new InnerClass($this);
nickf
yep, thats what i will do.
YuriKolovsky
+1  A: 

It seems you should do:

class mainclass {
    var $data;
    function __construct($data){
        $this->data = $data;
    }
    function echodata(){
        echo $this->data;
    }
    function start(){
        class innerclass(){
            var $mainclass;
            function __construct($mainclass) {
                $this->mainclass = $mainclass;
            }
            function show(){
                $this->mainclass->echodata();//the problem is here
            }
        }
        $inner = new innerclass($this);
        $inner->show();
    }

}

$mainclass = new mainclass('maininfostuff');
$mainclass->start();

But it seems you can't do that in PHP:

Fatal error: Class declarations may not be nested in test.php on line 11

So extract your inner class out of the mainclass.

Peter Stuifzand
excellent answer, just what i was looking for.
YuriKolovsky
+3  A: 

Inner classes are not possible in PHP. So you cannot declare your innerclass within mainclass. And since you can't do that, there's no way to access the outer classes variables as you can in, for example, Java.

You can do this instead:

 class mainclass {
     var $data;
     function __construct($data){
         $this->data = $data;
     }
     function echodata(){
         echo $this->data;
     }
     function start(){
         $inner = new innerclass();
         $inner->show($this);
     }

 }
 class innerclass{
     function show($mainclass){
         $mainclass->echodata();//the problem is here
     }
 }

 $mainclass = new mainclass('maininfostuff');
 $mainclass->start();
Scott Saunders
even better answer!
YuriKolovsky
+1  A: 

Let me address one important line:

mainclass->echodata();//the problem is here

In PHP, in order to use the infix object-access operator (->) the left-side argument must be a variable (prepended by at least one $) and must be an instance of a class, e.g. $myClass->whatever or $this->foo.

If you are coming from another language and you are thinking of static access, you must use the correct operator, which is ::, e.g. someClass::$someValue or someClass::SOME_CONST.

Now then, if you are adamantly opposed to passing the "parent" object to the child's constructor, you could consider a singleton pattern, which would allow you to statically access the (only) instance of the parent class from anywhere in the code, including the child object.

But seriously, just pass it as an argument to the constructor, and as someone else said, don't define the class inside of a function, especially if that function is itself a member of another class. If that function is called twice, you will get a fatal error.

EDIT

Here's an example of what I'm talking about:

class mainClass {
    private static $instance = null;
    private $data = null;

    private function __construct($setData) {
        if (!is_null($setData)) {
            $this->data = $setData;
        }
    }

    public static function getInstance($setData = null) {
        if (is_null(self::$instance)) {
            self::$instance = new mainClass($setData);
        }
        return self::$instance; // objects will always be passed by reference
    }

    public function echodata() {
        echo $this->data;
    }

    public function start() {
        $inner = new innerClass;
        $inner->show();
    }
}

class innerClass {
    function show() {
        mainClass::getInstance()->echodata();   
    }
}

Then Run:

$foo = mainClass::getInstance('Foo');
$foo->start(); // prints "Foo"
Dereleased
thank you for your answer, but i need it to work without singletons.
YuriKolovsky
A: 

You are attempting to call a non-static method statically with the code

mainclass->echodata();//the problem is here

Instead, you need to pass in an instance of mainclass to the subclass:

 <?php

 class innerclass(){
     function innerclass($parent) {
         $this->_parent = $parent // hold onto our parent
     }

     function show(){
         $this->_parent->echodata();
     }
  }

  // ....

  $inner = new innerclass($this);
  $inner->show();
  ?>
meagar
+3  A: 

No, inner clases are not in PHP.

"The functionality is already available in other languages, but the question is whether it is needed in PHP. The short answer is no. With PHP execution model, it would further slow down and bloat PHP compilation." -- http://jacobsantos.com/2006/general/dont-advocate-subclasses/comment-page-1/

Don
+1, Good link!!
Dereleased
A: 

I have found more ways to do this

class innerclass{
        function show(){
            mainclass::echodata();
        }
}
class mainclass {
    var $data;
 protected static $_instance;
    function __construct($data){
        $this->data = $data;
        self::$_instance = $this;
    }
    //run previosuly declared mainclass method from anywhere
    public static function echodata(){
    if( self::$_instance === NULL ) {
        self::$_instance = new self();
    }
        self::$_instance->runechodata();
    }
    function runechodata(){
        echo $this->data;
    }
    function start($classname){
        $inner = new $classname();
        $inner->show();
    }

}

$mainclass = new mainclass('maininfostuff');
$mainclass->start('innerclass');




//i want it to echo "maininfostuff"

and this one too, which i prefer, considering its pretty neat.

class sharing {
 protected static $mainclass;
 function echodata(){
  self::$mainclass->echodata(); 
 }
}
class innerclass extends sharing {
        function show(){
            parent::echodata();
        }
}
class mainclass extends sharing {
    var $data;
    function __construct($data){
        $this->data = $data;
  parent::$mainclass = $this;//share $this
    }
    function echodata(){
        echo $this->data;
    }
    function start($classname){
        $inner = new $classname();
        $inner->show();
    }

}

$mainclass = new mainclass('maininfostuff');
$mainclass->start('innerclass');

and here is a object instance sharing class that i just made :)

//PHP Object Sharing 
class sharing {
 //list the classes that you would like to be available for sharing
 protected static $mainclass;


 //run any function that is shared (part of any of the shared objects)
 public function __call($name,$args){
  $shared_objects = get_class_vars(get_class());
  foreach($shared_objects as $sharedObject){
   if (method_exists($sharedObject,$name)){
    $classname = get_class($sharedObject);
    self::$$classname->$name(implode(', ',$args));
    return;
   }
  }
 }
}


class innerclass extends sharing {
        function show(){
   $data = 'inner says hi';
            parent::echodata($data);
        }
}
class mainclass extends sharing {
    var $data;
    function __construct($data){
        $this->data = $data;
  parent::$mainclass = $this;//share mainclass with anything that is a part of sharing
    }
    function echodata($moredata=NULL){
        echo $this->data.'+'.$moredata;
    }
    function start($classname){
        $inner = new $classname();
        $inner->show();
    }

}

$mainclass = new mainclass('maininfostuff');
$mainclass->start('innerclass');

//returns "maininfostuff+inner says hi"

this allows you to run any shared "object instance" functions from any shared object now mainclass can include/run any innerclass it wants, while innerclass has the ability to run mainclass instance functions as if its the already started mainclass object

YuriKolovsky
A: 

YuriKolovsky, you're the man!!! Thanks a lot :)

Buzzer
uh oh, thanks :)
YuriKolovsky