Scope issue when using parent::method

Hey,

I have a method called render() which renders some HTML for me. I’m extending from a class that already has a method render() so I would like to use what’s already there plus more. So I did this:


    public function render() {
        $hw = 'Hello World';
        
        parent::render(); //Holds a bunch of requires that calls html files
    }

When I try to echo out the variable $hw in one of my html files, like the header.php for example, it says undefined variable.

The only way I’ve gotten it to work is by overriding the method and including what I need.


    public function render() {
        $hw = 'Hello World';
        
        require_once example1.php;
        require_once example2.php;
    }

the variable now exists and I can use it as I see fit.

Has anyone experienced this before?

I guess my first example was the incorrect one to use. The 2nd post I made is a better illustration of the problem I’m talkig about.

What I meant by going through is that I can’t use the new object unless I override it. Notice that I just said, this works if I override the method. I don’t want to pass the new objects to the parent, I just need to instantiate additional objects based on the class.

Edit:

I’m thinking of making a method called defaults() or something and call that wihin each render method in order to get the result I’m looking for. I was just hoping to avoid this way.


class b extends a{

  public function render(){
      $example = new object(); // based on the class
      parent::defaults();
  }
}

something like that…

You can even tell class A that $data is optional.


public function render($data=array())
{
    ...
}

That way you can call the render function with or without the data parameter, which makes it more flexible.

As long as the code within the render function appropriately handles the data either being there or not, you should be safe.


$index = ''; // default value
if (array_key_exists('index', $data)) {
    $index = $data['index'];
}

The reason that $hw variable is not available in your method is its scope. Because a normal variable that is declared within a function/method will only be available in that function only not with other methods. So either you have to pass as a parameter or do as suggested above.

<?php

class A {
	public $hw;
	
    function render() {
        echo $this->hw;
    }
}

class B extends A {
    function render() {
        $this->hw = 'Hello World';
		parent::render();
    }
}

$b = new B;
$b->render();

?>

Pmw, tha’ts an acceptable solution. It’s a little better than the one I came up with. At least I won’t have to create a 2nd method and apply it in all the other render() methods.

I don’t think this would be an efficient solution for me.

In my parent class where the method render() is first defined, I instantiated 2 objects. I would like to instantiate a 3rd object (or more) based on the class it’s inheriting from. Based on your example, I would have to have a property for all objects that I would need.

To better illustrate:


class A {
  public function render() {
      $user = new User();
      $stats = new Stats();
  }
}

class B extends A {
  public function render() {
      $index = new Index();
      parent::render();
  }

}

If I instantiate from class B $index doesn’t go through.

The only way for a class to gain access to external variables is to either pass them in, to externally change already existing variables from within, or to use the global keyword to reach out and take other variables.

Stay away from the global keyword, as it’s about as polite as my reaching over to tickle your [redacted] with my [redacted].

The class called A only has access to variables that are passed in to it, or ones that already exist within it. If you want $index which is created in the B class, to be available from a function in the A class, there are a limited few options available to you.

Why don’t you pass the data in? Create an array called $data and apply the information to associative keys.

$data[‘index’] = new Index();

Then you can pass it to the render function, so that other parts from within there can retrieve it via $data[‘index’]

It doesn’t go through to class A, which is dead right. The only way that information should go in to class A is via proper channels.

Are you wanting class B to update a value in class A?

There are a couple of different ways to do that, each being more suitable depending on the situation.


class A {
    protected $hw;

    public __construct ()
    {
        $this->hw = 'Hello World';
    }
  
    public function render() {
        $hw = $this->hw;
        
        require_once example1.php;
        require_once example2.php;
    }
}

class B extends A {
    public function render() {
        parent::hw = 'New and improved hello world!';
        parent::render();
    }
}

If you’re using PHP 4 then instead of using protected for $hw you can instead make it public, or better is to create a class A method to update it instead.