Create and use global variable without the 'global' keyword? - php

As of now I create a variable like this in a file that's loaded on all pages:
<?php
add_action( 'parse_query', 'my_global_vars' );
function my_global_vars() {
/* CUSTOM GLOBAL VARIABLES */
$variable_name = get_query_var('category_name');
}
?>
And every time I want to use it (in other files), I must do it like this:
<?php
global $variable_name;
if( $variable_name = 'news' ){
// Do something
}
?>
And when I need to use the variable multiple times in the same file, I add global $variable_name; at the top of the file, and simply use $variable_name in rest of the instances.
But as the number of variables increase, I find it harder to manage the list of global $variable_names at the top of all files.
Is there a way to define a variable as global at the time of creation and simply use $variable_name everywhere else?
EDIT: One way is to define variable like this:
<?php
add_action( 'parse_query', 'my_global_vars' );
function my_global_vars() {
/* CUSTOM GLOBAL VARIABLES */
global $variable_name;
$variable_name = get_query_var('category_name');
}
?>
And use it like using $GLOBALS[] like this $GLOBALS['variable_name'] elsewhere.

Having a lot of global vars is usually bad. It becomes a mess very quickly.
If you really need global variables the best approach is to use static class variables. They are just as global as the others, but they enforce better naming and pre-declaration so the end result is somewhat better.
If you really need normal global vars you can also use the $GLOBALS variable, it is available in every scope and is basically an array of all the global variables.
global $variable_name;
do_something_with($variable_name);
is the same as
do_something_with($GLOBALS['variable_name']);

You can use a static class for this and keep it OOP:
<?php
class GlobalVariables {
private static $vars = array();
public static function get($name, $default = null) {
return (isset(self::$vars[$name]) ? self::$vars[$name] : $default);
}
public static function set($name, $value) {
self::$vars[$name] = $value;
}
}
function foo() {
GlobalVariables::set('foo', 'oof');
}
function bar() {
var_dump( GlobalVariables::get('foo') );
}
foo();
bar(); //oof
?>
DEMO
Alternatively, you can use a Singleton pattern:
<?php
class GlobalVariables {
private static $instance;
private $vars = array();
public static function get() {
if (empty(self::$instance)) {
self::$instance = new GlobalVariables();
}
return self::$instance;
}
public function __get($name) {
return (isset($this->vars[$name]) ? $this->vars[$name] : null);
}
public function __set($name, $value) {
$this->vars[$name] = $value;
}
}
function foo() {
GlobalVariables::get()->foo = 'oof';
}
function bar() {
var_dump( GlobalVariables::get()->foo );
}
foo();
bar(); //oof
?>
DEMO.
Use whichever you find most readable.
GlobalVariables::set('key', 'value');
GlobalVariables::get('key');
or
GlobalVariables::get()->key = 'value';
GlobalVariables::get()->key;
Completely alternatively, if you hate dynamicness, simply use static variables (this, however, requires you to create all variables beforehand):
<?php
class GlobalVariables {
public static $foo;
}
GlobalVariables::$foo = 'oof';
var_dump( GlobalVariables::$foo );
?>

Using global outside a function doesn't do anything. It's meant for inside functions. You can simply remove your global statements.
Edit: I suggest that you try to reduce the number of global variables you have by structuring them. Group them into arrays or objects. E.g., instead of user_name, user_id, user_is_admin, prefer user['name'], user['id'], user['is_admin'], then you only have one variable (user) to declare as global instead of three.

Related

How to access a loop's variable from a function?

I have a loop which will make calls to the function. Variables are defined (and reassigned on each iteration) in the first loop which are required for the function to function.
Loop:
if ($something) {
while (!$recordSet->EOF) {
$variable1 = TRUE;
$variable2 = FALSE;
...
function1()
}
}
Function:
function function1() {
if ($variable1 && !$variable2) {
...
}
}
The variables will have boolean values, and the environment is limited to PHP 4.
I'm currently considering using global $variable1; in the while loop and function1, but I know globals are almost always frowned upon.
Usually I'd use define("variable1","a value"), but the values will be changed multiple times.
Any suggestions, or is global defining the best solution in this case?
Thanks.
EDIT: Totally forgot to mention. This file is actually a spaghetti legacy code, and function1 is called in a hundred different places, all with varying bits of information. Otherwise, I would have used arguments.
In the main scope, define global $variable1 and global $varible2.
Also do it in the function.
But this is the worst solution. You will confuse, if these variables changes somewhere else.
The best way I think is to refactore your code, and pass varables as parameters.
The other solution could be create a class for these 2 variables, and set/get them statically.
class variablesPlaceHolder {
private static $variable1;
private static $variable2;
public static function getVariable1() {
return self::$variable1;
}
public static function getVariable2() {
return self::$variable2;
}
public static function setVariable1($variable1) {
self::$variable1 = $variable1;
}
public static function setVariable2($variable2) {
self::$variable2 = $variable2;
}
}
And the include this class in file, where you want to use them, and call variablesPlaceHolder::setVariable1(anyValue) variablesPlaceHolder::getVariable1()

PHP - architecture, issue with variables scope

I'm writing now an app, which is supposed to be as simple as possible. My controllers implement the render($Layout) method which just does the following:
public function render($Layout) {
$this->Layout = $Layout;
include( ... .php)
}
I don't really understand the following problem: in my controller, I define a variable:
public function somethingAction() {
$someVariable = "something";
$this->render('someLayout');
}
in the php view file (same I have included in the render function) I try to echo the variable, but there is nothing. However, if I declare my action method like this:
public function somethingAction() {
global $someVariable;
$someVariable = "something";
$this->render('someLayout');
}
and in my view like this:
global $someVariable;
echo $someVariable;
it does work. Still it is annoying to write the word global each time.
How can I do this? I'd rather not use the $_GLOBAL arrays. In Cake PHP, for example, there is a method like $this->set('varName', $value). Then I can just access the variable in the view as $varName. How is it done?
From the PHP Manual on include:
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.
When you do
public function somethingAction() {
$someVariable = "something";
$this->render('someLayout');
}
the $someVariable variable is limited to the somethingAction() scope. Calling your render() method will not magically make the variable available in render(), because the render() method has it's own variable scope. A possible solution would be to do
public function somethingAction() {
$this->render(
'someLayout',
array(
'someVariable' => 'something'
)
);
}
and then change render() to
public function render($Layout, array $viewData) {
$this->Layout = $Layout;
include( ... .php)
}
You will then have access to $viewData in the included file, given that you are not trying to use it in some other function or method, e.g. if your included file looks like this:
<h1><?php echo $viewData['someVariable']; ?></h1>
it will work, but if it is looks like this:
function foo() {
return $viewData['someVariable'];
}
echo foo();
it will not work, because foo() has it's own variable scope.
However, a controller's sole responsibility is to handle input. Rendering is the responsibility of the View. Thus, your controller should not have a render() method at all. Consider moving the method to your View class and then do
public function somethingAction() {
$view = new View('someLayout');
$view->setData('someVariable', 'something');
$view->render();
}
The render() method of your View object could then be implemented like this:
class View
…
$private $viewData = array();
public function setData($key, $value)
{
$this->viewData[$key] = $data;
}
public function render()
{
extract($this->viewData, EXTR_SKIP);
include sprintf('/path/to/layouts/%s.php', $this->layout);
}
The extract function will import the values of an array in the current scope using their keys as the name. This will allow you to use data in the viewData as $someVariable instead of $this->viewData['someVariable']. Make sure you understand the security implications of extract before using it though.
Note that this is just one possible alternative to your current way of doing things. You could also move out the View completely from the controller.
Using global you're implicitly using the $_GLOBALS array.
A not recommended example, because globals are never a good thing:
function something() {
global $var;
$var = 'data';
}
// now these lines are the same result:
echo $_GLOBALS['var'];
global $var; echo $var;
Why don't you use simply the $this->set function?
public function render($Layout) {
$this->Layout = $Layout;
include( ... .php)
}
public function somethingAction() {
$this->set('someVariable', "something");
$this->render('someLayout');
}
// in a framework's managed view:
echo $someVariable;
I'm sorry not to know your framework in detail, but that makes perfectly sense.
Actually how it's done: There is a native extract function, that loads an associative array into the current symbol table:
array( 'var0' => 'val0', 'var1' => 'val1')
becomes
echo $var0; // val0
echo $var1; // val1
That's most likely 'what happens'.

PHP - class forget set variables

I try to create some sort of setup class, like global values for the page.
The PHP-code
class globals
{
public $page;
public function __construct()
{
}
public function set_page($value)
{
$this->page = $value; // Maybe from a database
}
}
class get
{
public function page()
{
$globals = new globals();
return $globals->page;
}
}
$globals = new globals();
$globals->set_page('My value');
echo get::page(); // Short function to be in a template
Question
My class forget the value I set. Why is that?
Do I have to use global variables?
Is this the correct approach for the problem?
The variable is set on an object, not on a class.
For each class, you can instantiate multiple objects. Each of those have their own variable scope.
Edit:
I forgot to include the easiest, and least verbose solution to your problem. AFAIK, you're looking for a way to check what page you're on. Constants will do just that:
defined('MY_CURRENT_PAGE') || define('MY_CURRENT_PAGE','My Value');
//use anywhere like so:
echo 'Currently on page: '.MY_CURRENT_PAGE;
My class forget the value I set. Why is that?
Quite simple: your page member function isn't static, yet you call it as though it is: get::page(). Even if you were to fix this, you're creating a new instance in the page method, but you're not preserving a reference too it anywhere, so each page call will create a new globals instance, that has nothing set.
Do I have to use global variables?
No, unless you're Really desperate, never use globals
Is this the correct approach for the problem?
No, if it doesn't work, it's not correct (IMHO).
Well, what is, you might ask. There are several ways to go about this:
class globals
{
public static $page = null;//make this static, meaning all instances will share this var
public function set_page($value)
{
self::$page = $value; // Maybe from a database
}
}
class get
{
private $_globalsInstance = null;
public function __construct(globals $instance = null)
{
$this->_globalsInstance = $instance;
}
private function _getGlobals()
{
if (!$this->_globalsInstance instanceof globals)
{
$this->_globalsInstance = new globals();
}
return $this->_globalsInstance;
}
public function page()
{
return $this->_getGlobals()::$page;
}
}
Personally, however, I wouldn't work like this, I'd just pass my instances to wherever I need them (as arguments to functions/methods or just instantiate them in a scope that will be accessible:
class globals
{
public $page = null;//make this static, meaning all instances will share this var
public function set_page($value)
{
$this->page = $value; // Maybe from a database
}
}
$page = new globals();
$page->set_page('foobar');
someFunction($page);
$someObject->renderPage($page);
require_once('specificScript.php');
//inside required script:
echo $page->page;
Do I have to use global variables?
Not, if your can use PHP 5.3
Is this the correct approach for the problem?
Better to use a generic class for this, or use static properties of objects
<?php
class globals
{
public static $page;
public function __construct()
{
}
public function set_page($value)
{
self::$page = $value; // Maybe from a database
}
}
class get
{
public static function page()
{
return globals::$page;
}
}
$globals = new globals();
$globals->set_page('My value');
echo get::page(); // Short function to be in a template
P.S.
But this is not a nice approach
$globals there
class get
{
public function page()
{
$globals = new globals();
return $globals->page;
}
}
and there
$globals = new globals();
$globals->set_page('My value');
are different inctances of globals class.
One of the solutions is to make $page var static
public static $page;
I hope this helps
UPD:
Also you might apply Singleton to globals class and request for its insnance instead of creating new one directly:
globals::getInstance()->setPage('Page');
and
return globals::getInstance()->getPage();
In this case $page doesn't have to be static.
I'm not sure the other answers are very clear. You have created 2 classes. As such they have different scopes. As writen you can't access the original variable $page from the get class because it's outside the scope. Your page function in fact creates a new version of the object $globals without $page set. Normally you would place both your set and get functions in the initial object/class. Though it would be possible to use two class by calling the first class from the second and setting the page. Why you would want to do that I'm not sure.
if I were writing the class it would look like this.
class globals
{
public $page;
public function __construct()
{
}
public function set_page($value)
{
$this->page = $value; // Maybe from a database
}
public function get_page()
{
return $this->page;
}
}
Actually I would probably set page to private not public. As public I guess you don't need a get function.
for using methods of the class without object you must use static definition. but anyway you put value for one class object and try to get it from another...
Perhaps this will help you continue on your coarse:
class globals
{
public static $page;
public function set_page($value)
{
self::$page = $value; // Maybe from a database
}
}
class get extends globals
{
public function page()
{
$globals = new globals();
return parent::$page;
}
}
$globals = new globals();
$globals->set_page('My value');
echo get::page();
?>

Converting all vars to global scope

I know I can use $GLOBALS['var'] inside a function to refer to variables in the global scope.
Is there anyway I can use some kind of a declaration inside the function so I will be able to use $var without having to use $GLOBAL['var'] every time?
Joel
Although it's not recommended, but if you do want to, here's what you can do:
If you only want to GET the values from the vars (and not SET the values), just use extract:
extract($GLOBALS);
This will extract and create all the variables in the current scope.
How about using static class?
such as
class example
{
public static $global;
public static function set($arr)
{
foreach ($arr as $key=>$val)
{
self::$global[$key] = $val;
}
}
}
function example_function()
{
var_dump( example::$global );
}
example::set( array('a'=>1, 'b'=>2) );
example_function();
You can use the global keyword, So you can use type $var instead of $GLOBALS['var'] inside a function.
function myFunc() {
global $var;
$var = 3;
}
$var = 1;
myFunc();
echo $var;
Output: 3

Writing to static classes in PHP

Assuming I have a Config class that I use to access the config vars from everywhere (Config::X).
Is it possible to implement a function that can be called from outside the class that adds and/or modifies properties?
Something like this is what I'm thinking of:
class Config
{
const myVar = 'blah';
public static function write( $name, $value )
{
//....
}
}
echo Config::myVar; // Clear
Config::write( 'test', 'foo' );
echo Config::test; // Should be foo
I've seen something similiar in CakePHP but couldn't figure out the solution.
My goal would be being able to write to the base Config class from different files, e.g.: store Database information in a separate file.
You can't achieve this without declaring the variables first unless you ditch static variables and use concrete implementations instead. Even if you do declare the variables first you will have to call them using `$:
class Config {
const $myVar = 'blah';
public static $test;
public static function write( $name, $value )
{
//....
}
}
Config::write( 'test', 'foo' );
echo Config::$test; // Will be foo
If you have a concrete implementation then you can leverage __get and __set so you don't have to declare all your variables.
class Config {
const $myVar = 'blah';
private $vars = array();
public function __set($name, $value) {
$this->vars[$name] = $value;
}
public function __get($name) {
if(isset($this->vars[$name])
return $this->vars[$name];
return null;
}
}
echo Config::myVar; // Still the same
$config = new Config();
$config->test = 'foo';
echo $config->test; // Will be foo
This will mean you'll need to pass around your config object if you need it somewhere. If you find this annoying you might want to look into dependency injection.
You can't modify values of a static class. If you would like to have this functionality, you'll need to make an instance of the class,and store in it session if you need the values to persist over pages.
Your code seems to make the write function bind up a new const called $name .... never seen that done before.

Categories