NiftyHost Forums (Archive)
PHP OOP variable scope problem - Printable Version

+- NiftyHost Forums (Archive) (https://niftyhost.chary.us/support)
+-- Forum: Technology (https://niftyhost.chary.us/support/forum-7.html)
+--- Forum: Coding (https://niftyhost.chary.us/support/forum-12.html)
+--- Thread: PHP OOP variable scope problem (/thread-945.html)



PHP OOP variable scope problem - Vanilla - 12-28-2010

Aight', I've never dug deep into the php OOP thing, as I've always relied on procedural programming or OOP on a very low level...bla...bla...
Silly me, [Image: mr-bean_sq50.jpg?1227175124]
ANYWAY, I've run into a problem, I just can't solve. I donno' whether I should use $this, parent, self, :: (Scope resolution operator). Or whether the static keywords is even supposed to be there.

The case is, that I have a main class, in which I've instantialized(?) two secondary classes (Main -> One and Main -> Two).
Afterwards, through the main class I've changed instance Two's variable $Xenon to be " in ". But I keep getting an:
Code:
Trying to get property of non-object
- error.

Don't mind the resulting sentence, it's just random stuff
Main.php
PHP Code:
class Main
{
    static public 
$One$Two;
    
    function 
Init()
    {
        require(
"child.php");
        require(
"child2.php");
        
        
$this->One = new First;
        
$this->Two = new Second;
        
$this->Two->Xenon " in ";
        
        
$this->One->Activate("the Oven");
    }
}
$Main = new Main;
$Main->Init(); 

child.php
PHP Code:
class First extends Main
{
    function 
Activate($Arg)
    {
        echo(
Second::A().Second::$Xeen.$Two->Xenon.$Arg);
        
//Result i want: Mary's pet was burned in the oven
        //Actual result: Mary's pet was burnedthe oven
    
}


child2.php
PHP Code:
class Second extends Main
{
    static public 
$Xeen " was burned";
    static public 
$Xenon;
    
    function 
A()
    {
        return(
"Mary's Pet");
    }



I've found out, that I can get the result I want if I pinpoint the $Xenon variable from an absolute/global perspective, like this:
PHP Code:
function Activate($Arg)
    {
                      global 
$Main;

        echo(
Second::A().Second::$Xeen.$Main->Two->Xenon.$Arg);
        
    } 
But that kinda sucks, isn't there a relative way to do it? Like where you point to the parent and then point to subject from there? Hope you understand what I mean.

Regards and thanks in advance
- Vanilla


RE: PHP OOP variable scope problem - RichardGv - 12-28-2010

Okay, the problem lays in a single sentence in PHP document:
Quote:When a file is included, the code it contains inherits the variable scope of the line on which the include occurs. Any variables available at that line in the calling file will be available within the called file, from that point forward. However, all functions and classes defined in the included file have the global scope.
Source: http://us3.php.net/manual/en/function.include.php
So, even though the line require('child.php') lays in the body of the method Init() of class Main, the class First declared in child.php actually is in global variable scope instead of Init() variable scope, and may not access any variable in the variable scope of Init() directly, including $Two. (PHP do not allow class definition in another class definition, by the way, so there's no workaround.) The $Two in child.php is actually an undefined variable and should trigger a PHP warning.

And the only possible way to go back from a subclass to its instantiated parent class (well, it should be called an object) is to pass the parent object (or part of it) to the instance of subclass, i.e. change the declaration of Activate() in child.php to something like:
PHP Code:
function Activate($Arg$obj) {
        echo(
Second::A().Second::$Xeen.$obj->Two->Xenon.$Arg);

And change the call of Activate() in main.php to something like:
PHP Code:
$this->One->Activate("the Oven"$this); 
Of course, you may pass $Two directly, which is a lot more easier.

It's not a fault of those lovely PHP developers : PHP is not so smart that it can know which instance of parent class you exactly want to return to, when there's more than one instance.

Also, there's another fatal issue in your script: You are incorrectly using static attributes/methods of classes, all the time.
Quote:Declaring class properties or methods as static makes them accessible without needing an instantiation of the class. A property declared as static can not be accessed with an instantiated class object (though a static method can).
Source: http://php.net/manual/en/language.oop5.static.php
So, if you explicitly conform to PHP standard, within the method Init() of class Main, you may not access $this->One or $this->Two. But currently PHP is only printing a few warning messages in this situation (which you may have oppressed through PHP configuration). But still, PHP tolerates it does not mean you should use it. It generates very puzzling code.
Another problem is the method A() of the class Second is not a static method, and should not be access by Second::A() (:: is for static methods/attributes) in child.php. PHP prints a warning for this, too, but you or your PHP environment ignored it.


RE: PHP OOP variable scope problem - Vanilla - 12-29-2010

Thanks Richard! You're a hero! I give you +1 Positive for that one :)

This was what I was looking for:
PHP Code:
function Activate($Arg$obj) {
        echo(
Second::A().Second::$Xeen.$obj->Two->Xenon.$Arg);

PHP Code:
$this->One->Activate("the Oven"$this); 


I don't know why I forgot that you could pass on an instance as an argument, as I used to do it in AS 3 all the time.



Regarding the static thing, I don't know why PHP doesn't print error messages. I've set php to display all errors in the .ini file.
It's probably a windows fault.

Anyway, I was just wondering. If I had a lot of properties/vars, would it be feasible to load them onto an array, and then pass the array as an argument (To Activate())? Would that be a valid way to do such without generating errors?


RE: PHP OOP variable scope problem - RichardGv - 12-29-2010

(12-29-2010, 12:59 AM)Vanilla Wrote: Regarding the static thing, I don't know why PHP doesn't print error messages. I've set php to display all errors in the .ini file.
It's probably a windows fault.

Hmm, no, it isn't a Windows fault, I just found out. E_STRICT Strict Standard warnings are not enabled by default in PHP. I have it enabled since XAMPP does by default.
To enable E_STRICT warnings, change error_reporting in php.ini to:
Code:
error_reporting = E_ALL | E_STRICT

(12-29-2010, 12:59 AM)Vanilla Wrote: Anyway, I was just wondering. If I had a lot of properties/vars, would it be feasible to load them onto an array, and then pass the array as an argument (To Activate())? Would that be a valid way to do such without generating errors?

  1. In PHP syntax it's perfectly valid.
  2. However it does not sound like a good idea: Packing all the variables to an array will require a lot of extra code, more than even writing all the parameters down.
    Let's imagine packing 3 variables:
    PHP Code:
    // Overall: 335 bytes of code
    // main.php - Packing part
    $packedvars = array('variableOne''variableTwo''variableThree');
    for 
    each($packedvars as $varname)
        
    $pack[$varname] = $$varname;
    Activate("the Oven"$pack);

    // child.php - Unpacking part
    function Activate($Arg$pack) {
        echo 
    $pack['variableOne'];
        echo 
    $pack['variableTwo'];
        echo 
    $pack['variableThree'];

    But if you just write all the variables directly to the parameter list:
    (There's one point to pay attention: You may copy a large part of the first line in main.php directly to the first line in child.php).
    PHP Code:
    // Overall: 253 bytes of code
    // main.php - Calling part
    Activate("the Oven"$variableOne$variableTwo$variableThree);

    // child.php
    function Activate($Arg$variableOne$variableTwo$variableThree) {
        echo 
    $variableOne;
        echo 
    $variableTwo;
        echo 
    $variableThree;

    So, actually, packing all the variables requires you to type more code! Not to mention the memory and CPU time cost of duplicating every variable for 3 times (the first time as $variableOne in main.php, the second time as $pack['variableOne'] in main.php, the third time as $pack['variableOne'] in child.php). Worthy? Not really.
    Passing the whole object (as reference) could be even easier, if possible.



RE: PHP OOP variable scope problem - Vanilla - 12-30-2010

Aight' - that's just what I wanted to know, thanks for the elaboration ;)


RE: PHP OOP variable scope problem - Vanilla - 01-03-2011

[Problem solved - Thread closed]