Ansego Posted March 16, 2014 Share Posted March 16, 2014 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"; } } ?> Quote Link to comment Share on other sites More sharing options...
.josh Posted March 16, 2014 Share Posted March 16, 2014 You refer to it like this: $this->myvartest Quote Link to comment Share on other sites More sharing options...
KevinM1 Posted March 16, 2014 Share Posted March 16, 2014 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. Quote Link to comment Share on other sites More sharing options...
.josh Posted March 16, 2014 Share Posted March 16, 2014 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. Quote Link to comment Share on other sites More sharing options...
Ansego Posted March 17, 2014 Author Share Posted March 17, 2014 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: Quote Link to comment Share on other sites More sharing options...
trq Posted March 17, 2014 Share Posted March 17, 2014 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 Quote Link to comment Share on other sites More sharing options...
.josh Posted March 17, 2014 Share Posted March 17, 2014 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. Quote Link to comment Share on other sites More sharing options...
Solution Ansego Posted March 17, 2014 Author Solution Share Posted March 17, 2014 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. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.