Jump to content

Class -> Global Variable?


Go to solution Solved by Ansego,

Recommended Posts

Hi guys, Having trouble with declaring a global variable, just getting into classes so having fun knocking some junk out; 

 

Q. Am I declaring this global variable correctly?

Q. Should I be using global's to pass variables/values between methods? if NOT what should I be doing?

 

$myvartest seems to get this error: Notice: Undefined variable: myvartest in ........ Line 13.

<?php
class testclassA {
	
	protected $myvartest = "</br>testING PRIVATE</br>";
	
    public function __construct() {
        echo "testA class successfuly!";
    }
	
	public function mytestA($str_passed){
		isset($myvartest);
		echo "test found $str_passed";
		echo "my test string: $myvartest";
		}
}
?>

 

 

 

Link to comment
https://forums.phpfreaks.com/topic/287013-class-global-variable/
Share on other sites

Q. Should I be using global's to pass variables/values between methods? if NOT what should I be doing?

You shouldn't be using globals at all, in any context. You should, instead, use a function's/method's argument list (the part between the parentheses). That's why it's there.

 

The whole point of functions, and especially objects, is to create reusable pieces of code that work when certain conditions are met. Object methods and functions are supposed to be considered black boxes, where data is passed in, something happens, and a result is returned. The 'something happens' phase is not supposed to be aware of the context outside itself. A global creates a tie to that outer context.

 

How is that different than passing in values through the argument list? Every function and method has a signature comprising that function's/method's name, the values it expects to be passed in, and the expected result. Everything required for a function/method to work properly is explicitly mentioned upfront, and it creates something of a contract. "I will only work if the following values are given to me." Globals create an implicit requirement that's essentially hidden because it's not part of the function/method signature. It says something vastly different - "I will only work if the calling environment contains the following values."

 

That implicit connection to the outer environment creates what's known as tight coupling within code. A change to one thing necessitates changes to many other things since they're all so tightly connected. Modularity and reusability (the entire purpose of functions and objects) goes out the window, and you're left with a hard to edit/debug/modify mess. Especially since global variables/values are notoriously easy to overwrite/delete.

 

If you're learning from a resource that uses 'global', ditch it. It's crap, and everything within should be considered suspect. If you're learning in a class, point your instructor to this post. And if your potential instructor balks, they should realize that everyone you/they see with a green, blue, or red badge under their picture is a professional that actually writes code for a living.

 

So, to conclude, never, ever, ever use 'global' or globals. You'll write much better code, and anyone you might work with will be grateful.

Usually you shouldn't directly access a property (even within the class. Normally you should have getter and setter methods for it defined, and they are the only methods that should directly access it.

 

set_exception_handler('exception_handler');
function exception_handler($e) { 
  echo "Error: ".$e->getMessage()." in ".$e->getFile()." on line ".$e->getLine();
}

class FooBar {
  protected $_bar;
  
  public function __construct() {
  
  }

  public function get_bar() {
    return $this->_bar;
  }

  public function set_bar($bar=0) {
    if ( ctype_digit((string)$bar) && ($bar>=0) && ($bar<=200) ) 
      $this->_bar = $bar;
    else
      throw new Exception('number is not within acceptable range'); 
  }

} // end FooBar

$x = new FooBar();

// example 1
$x->_bar = 123; // fails

// example 2
$x->set_bar(250); // fails

// example 3
$x->set_bar(10); // works

So in this code, I want to enforce that $_bar can only be set with a number between 0 and 200.

 

Example 1 fails because I attempt to directly set the property when it's protected. It will give me an error like:

 

Fatal error: Cannot access protected property FooBar::$_bar in /var/www/test.php on line 31
Example 2 fails because I throw an exception when the value doesn't match the validation. I will get an error like this:

 

Error: Number is not within acceptable range in /var/www/test.php on line 31
Example 3 works because I have set $_bar through the setter and it passes validation.

 

 

So, the reason for doing it this way is so that you have a place to enforce what kind of value $_bar can have. This goes towards what KevinM1 was saying about a "contract" between codes. This is how you can guarantee to other pieces of code that something will have an expected value or variable type or whatever.

 

So let's say I have another method in that class that attempts to do something with $_bar but $_bar is set by someone else's code like some plugin or w/e.. I don't want my code to break, so I do this to enforce expected values. Then if someone tries to write code that sets it to something other than what I expect, they get an error and their code won't work.

I appreciate the feed back guys, I would like to recap to make sure I have this in my head correctly:

 

  • Don't ever use globals
  • Wrap it with a function ie get / set 
  • Below I have test code setup, but when I call the getmyvar it does not allow me to echo the var out? Why?

 

Would this be the correct and safe setup?

 

index.php

function __autoload($classname) {
    $filename = "./inc/". $classname .".inc";
    include_once($filename);
}

$myobjA = new testclassA();
$varstring = "test";
$myobjA->setmyvar($varstring);
echo "OUTPUT: " . $myobjA->getmyvar();

inc/testclassA.inc

class testclassA {
	
	protected $myvartest;
	
    public function __construct() {
        echo "testA class successfuly!";
    }
	
	public function setmyvar($varstring){
		$myvartest = $varstring;
		return $myvartest;
		}
		
	public function getmyvar(){
		echo "</br>test found </br>";
		return $this->myvartest;
		}
}

OUTPUT:

testA class successfuly!
test found 
OUTPUT:

public function setmyvar($varstring){
    $myvartest = $varstring;
    return $myvartest;
}
Should be....

public function setmyvar($varstring){
    $this->myvartest = $varstring;
    return $this;
}
And before you get too much further, please take a look at: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-1-basic-coding-standard.md

Your immediate issue is that your setter isn't actually setting the property. But also, generally most people either don't return anything from the setter, or else the return $this, so which allows for method chaining.

 

public function setmyvar($varstring){
  $this->myvartest = $varstring;
  return $this;
}
But as-is, this doesn't do much and there's no real benefit of this over just setting it directly. Ideally you should do some validation to ensure that $varstring contains an expected value, or else throw an exception.

 

But on the sidenote of return $this; :

 

For example this would allow you to do this:

 

echo $myobjA->setmyvar($varstring)->getmyvar();
Another note: I know you are *probably* just doing it for testing purposes but normally you wouldn't echo stuff out in your getter like that. getter/setter methods shouldn't echo things out; you should have other methods that handle presentation.
  • Solution

Hey guys I really appreciate you all and phpfreaks! Won't let me mark all solved so I've quoted all to solve, test code is as follows:

 

Special thanks guys!

TRQ: Thanks for the resource: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-1-basic-coding-standard.md | PHP Is your calling man!

.josh: Thanks mate, always awesome and detailed.
KevinM1: Thanks heaps for the detailed post very helpful.
I will need to reread this post several times to taken in all the great input wow.
 

Index.php

function __autoload($classname) {
    $filename = "./inc/". $classname .".inc";
    include_once($filename);
}

$myobjA = new testclassA();
$varstring = "test";
$myobjA->setmyvar($varstring);
print "OUTPUT: " . $myobjA->getmyvar();

testclassA.inc

class testclassA {
	
	protected $myvartest;
	
    public function __construct() {
        echo "testA class successfuly!";
    }
	
	public function setmyvar($varstring){
		$this->myvartest = $varstring;
		return $this;
		}
		
	public function getmyvar(){
		echo "</br>test found </br>";
		return $this->myvartest;
		}
}

================================================================================================================ All contributed to a solved solution!

 

 

You refer to it like this: $this->myvartest

 

 

You shouldn't be using globals at all, in any context. You should, instead, use a function's/method's argument list (the part between the parentheses). That's why it's there.

The whole point of functions, and especially objects, is to create reusable pieces of code that work when certain conditions are met. Object methods and functions are supposed to be considered black boxes, where data is passed in, something happens, and a result is returned. The 'something happens' phase is not supposed to be aware of the context outside itself. A global creates a tie to that outer context.

How is that different than passing in values through the argument list? Every function and method has a signature comprising that function's/method's name, the values it expects to be passed in, and the expected result. Everything required for a function/method to work properly is explicitly mentioned upfront, and it creates something of a contract. "I will only work if the following values are given to me." Globals create an implicit requirement that's essentially hidden because it's not part of the function/method signature. It says something vastly different - "I will only work if the calling environment contains the following values."

That implicit connection to the outer environment creates what's known as tight coupling within code. A change to one thing necessitates changes to many other things since they're all so tightly connected. Modularity and reusability (the entire purpose of functions and objects) goes out the window, and you're left with a hard to edit/debug/modify mess. Especially since global variables/values are notoriously easy to overwrite/delete.

If you're learning from a resource that uses 'global', ditch it. It's crap, and everything within should be considered suspect. If you're learning in a class, point your instructor to this post. And if your potential instructor balks, they should realize that everyone you/they see with a green, blue, or red badge under their picture is a professional that actually writes code for a living.

So, to conclude, never, ever, ever use 'global' or globals. You'll write much better code, and anyone you might work with will be grateful.

 

 

Usually you shouldn't directly access a property (even within the class. Normally you should have getter and setter methods for it defined, and they are the only methods that should directly access it.
 

set_exception_handler('exception_handler');
function exception_handler($e) { 
  echo "Error: ".$e->getMessage()." in ".$e->getFile()." on line ".$e->getLine();
}

class FooBar {
  protected $_bar;
  
  public function __construct() {
  
  }

  public function get_bar() {
    return $this->_bar;
  }

  public function set_bar($bar=0) {
    if ( ctype_digit((string)$bar) && ($bar>=0) && ($bar<=200) ) 
      $this->_bar = $bar;
    else
      throw new Exception('number is not within acceptable range'); 
  }

} // end FooBar

$x = new FooBar();

// example 1
$x->_bar = 123; // fails

// example 2
$x->set_bar(250); // fails

// example 3
$x->set_bar(10); // works
So in this code, I want to enforce that $_bar can only be set with a number between 0 and 200.

Example 1 fails because I attempt to directly set the property when it's protected. It will give me an error like:

Fatal error: Cannot access protected property FooBar::$_bar in /var/www/test.php on line 31
Example 2 fails because I throw an exception when the value doesn't match the validation. I will get an error like this:

Error: Number is not within acceptable range in /var/www/test.php on line 31
Example 3 works because I have set $_bar through the setter and it passes validation.


So, the reason for doing it this way is so that you have a place to enforce what kind of value $_bar can have. This goes towards what KevinM1 was saying about a "contract" between codes. This is how you can guarantee to other pieces of code that something will have an expected value or variable type or whatever.

So let's say I have another method in that class that attempts to do something with $_bar but $_bar is set by someone else's code like some plugin or w/e.. I don't want my code to break, so I do this to enforce expected values. Then if someone tries to write code that sets it to something other than what I expect, they get an error and their code won't work.

 

 

 

public function setmyvar($varstring){
    $myvartest = $varstring;
    return $myvartest;
}
Should be....
public function setmyvar($varstring){
    $this->myvartest = $varstring;
    return $this;
}
And before you get too much further, please take a look at: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-1-basic-coding-standard.md

 

 

 

Your immediate issue is that your setter isn't actually setting the property. But also, generally most people either don't return anything from the setter, or else the return $this, so which allows for method chaining.
 

public function setmyvar($varstring){
  $this->myvartest = $varstring;
  return $this;
}
But as-is, this doesn't do much and there's no real benefit of this over just setting it directly. Ideally you should do some validation to ensure that $varstring contains an expected value, or else throw an exception.

But on the sidenote of return $this; :

For example this would allow you to do this:

echo $myobjA->setmyvar($varstring)->getmyvar();
Another note: I know you are *probably* just doing it for testing purposes but normally you wouldn't echo stuff out in your getter like that. getter/setter methods shouldn't echo things out; you should have other methods that handle presentation.

 

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.