Var visibility when including file - php

How to make variables visible when including some file. For example:
code.php:
<?php
global $var; $var = "green";
?>
index.php:
<?php
include("code.php");
Function index(){
echo "The apple is $var";
}
?>
Please note that in code.php there are a lot of global variables (~150 variables) and all variables are used in many different functions inside the index.php.

This is an issue to do with variable scope, plus you do not need to be defining $var as a global.
When you include a file, you can imagine in your head that it is just copy-pasting the contents of the other file into the current file.
E.g.
code.php
$includedName = 'Tom';
index.php
include 'code.php';
function sayHello($name)
{
echo 'Hello ' . $name;
}
sayHello($includedName); // Hello Tom

You've mentioned you are working with legacy code, so it may be worthwhile to preserve the use of globals for the sake of consistency - though using globals is generally considered to be very bad practice, I'd generally consider inconsistently using globals to be worse.
To break function scope and pull in variables from the global scope you must invoke the global keyword from within the function:
<?php
$var = "green";
Function index(){
global $var;
echo "The apple is $var";
}
?>
This answer sums up why global variables are considered to be bad practice:
There's no indication that this function has any side effects, yet it
does. This very easily becomes a tangled mess as some functions keep
modifying and requiring some global state. You want functions to be
stateless, acting only on their inputs and returning defined output,
however many times you call them.
However, in this specific example, you are not modifying $var's state - only reading it. So the issues are minimal.
The problems with global state can be read about in more depth on Programmers.SE.

Related

Can global variables be created with the keyword global and through a superglobal variable within a function in PHP?

I have heard using global variables is not good, however I am just trying to understand how the PHP language works. I am a beginner in the coding world.
Why can global variables be created within functions? Whether it is through the use of the global keyword or through a superglobal variable. I thought these two actions were used to access global variables in a function. I thought the only way you can create a global variable is to create it outside a function; in the global scope. I have looked at many different websites including w3schools.com and php.net
This is just some simple code I created to try and understand the way global variables work with functions:
<?php
function sample1() {
global $a;
echo $a = "this ";
}
sample1();
function sample2() {
echo $GLOBALS['$b'] = "is ";
}
sample2();
function sample3() {
global $c;
$c = "an ";
}
sample3();
echo $c;
function sample4() {
$GLOBALS['$d'] = "example ";
}
sample4();
echo $GLOBALS['$d'];
?>
This is the result of the code:
this is an example
All of the code works, but I don't understand how I created a global variable on any of these blocks of code? The global variables were not created outside of the functions. How can they be created inside of a function? What am I missing? Any response is appreciated - If possible, please keep the answer simple - I would like to discuss this further in the comment section, because I'm sure I will have follow up questions - Thank you
Variables can be created in the global scope in the two ways you just did - there's nothing saying that a function can't create (or change) a variable in the global scope - WHEN you explicitly ask for it through $GLOBALS or the global keyword.
The issue is that your belief "I thought the only way you can create a global variable is to create it outside a function; in the global scope." is not an exact statement. When you're using $GLOBALS and global, you're referring to the global scope. You're introducing a reference to the global scope inside your function.
With global you're in effect linking the local reference to the global reference, while with $GLOBALS you're explicitly referencing the global scope (which internally inside PHP can be introduced to the local scope in the same way).
In that case you're explicitly saying "I want this variable to be available in the global scope, make it so!" and PHP does what you're asking it to. This behaviour differ between languages, but as you've discovered for PHP, it's allowed.
It's not something I would recommend using in any way - it makes your code very hard to follow and argue around, so consider it an esoteric detail.

Include HTML inside partial and inside function

I am creating some widget for Word Press, but maybe this is standard PHP question, because it is related to some MVC pattern. I have some HTML that i need to output on page but that HTML is for now i inside function, i would like to transfer it to partial, because in the future there can be lots of more HTML, and if I make it like this it will be lots of spaghetti code.Here is what i have for now
class motractrucks extends WP_Widget{
function widget($args, $instance, $defaults){
echo '<p>'.$value1.'<p>';
echo '<p>'.$value2.'<p>';
echo '<p>'.$value3.'<p>';
echo '<p>'.$value4.'<p>';
echo '<p>'.$value5.'<p>';
echo '<p>'.$value6.'<p>';
}
}
This is just simple example, I have modified function easy that you can understand what i need, i was thinking to do something like, but how to pass values form inside function in that view?
class motractrucks extends WP_Widget{
function widget($args, $instance, $defaults){
include 'partials/userValues.php';
}
}
And pass all values to that partial, any good idea and best code practice will be nice.
The part of this question that specifically pertains to PHP is the variable scope. PHP functions have a local scope. So variables used inside those functions are considered to be local variables by default. Unless you explicitly import a variable from the global scope into the function's local scope via the global keyword, it's local. In your examples those variables are all undefined.
Also, using echo inside a function is never considered good practice, but I can't speak specifically to the WordPress aspect of your code as I'm not that familiar with WordPress.
Functions should take inputs as arguments and should return values as output. That's typically what you would consider good practice.
function foo($var1, $var2, $var3) {
return <<<HTML
<p>$var1</p>
<p>$var2</p>
<p>$var3</p>
HTML;
}
As far as including files for use in templates, that's usually fine in PHP. When you're doing those includes inside of a function it becomes easier to contain their scope, because include takes scope into account.
Let's say your partials/userValues.php file looks something like this...
<p><?=$var1?></p>
<p><?=$var2?></p>
<p><?=$var3?></p>
If you want to include it from your function you can. You can also use output buffering with functions like ob_start() and ob_get_clean() to write the output into a buffer and return that from the function instead of just printing directly to standard out.
function foo($var1, $var2, $var3) {
ob_start(); // start the output buffer first
include 'partials/userValues.php'; // include inherits the variable scope
$output = ob_get_clean(); // close the buffer and store it in $output
return $output; // return it to the caller
}

PHP page level variables

Not much of a PHP programmer, so I have a quick question in order to improve the performance of a WP site.
For many pages, the header and the body are handled by a set of completely separate functions.
The body functions do a lot of the same work as the header functions have already done, so is it possible to save the results of the header functions in a set of page level variables? (to avoid doing the same work twice).
Page level variables = variables with a page level scope that separate functions on the same page all have read/write access to.
Thanks!
You're probably looking for global, which is described on this page: http://php.net/manual/en/language.variables.scope.php
Short example:
function do1()
{
global $foo;
$foo = do work ...
}
functio do2()
{
global $foo;
$bar = do work with ($foo); ...
}
do1();
do2();
And one word of adivce; be very careful not to accidentally reuse names for global variables.

Is it possible to declare a variable as "always global"?

Is there any way I can define a variable such a way that I don't need to global $var1; in every function? Just define it in beginning and keep using where ever needed. I know $GLOBALS exist, but don't want to use it.
First let me try to explain why you shouldn't use globals because they are extremely hard to manage. Say a team member overrides an $ADMIN variable in a file to be 1, and then all code that references the $ADMIN variable will now have the value of 1.
globals are so PHP4, so you need to pick a better design pattern, especially if this is new code.
A way to do this without using the ugly global paradigm is to use a class container. This might be known as a "registry" to some people.
class Container {
public static $setting = "foo";
}
echo Container::$setting;
This makes it more clear where this variable is located, however it has the weakness of not being able to dynamically set properties, because in PHP you cannot do that statically.
If you don't mind creating an object, and setting dynamic variables that way, it would work.
You need to pass the variable as a parameter to that function to avoid using GLOBALS.
The Problematic Scenario (Works ! but avoid it at all costs)
<?php
$test = 1;
function test()
{
global $test;
echo $test; // <--- Prints 1
}
test();
The right way...
<?php
$test = 1;
function test($test)
{
echo $test; // <--- Prints 1
}
test($test); //<--- Pass the $test param here
This behaviour called as superglobal variable. But php has limited predefined list of them: Superglobals.
So you cannot add your own superglobal variable.
Variable scope
My suggestions from the most to less radical:
Edit source code of PHP and add your own superglobals.
Do not write code at all.
Do not use PHP (use different language with different variable scope policy).
Do not use functions (write plain script).
Use constants instead of variables.
Use function params instead of using globals.
Use static variables instead of globals. (\G::$variable)

PHP Preserve scope when calling a function

I have a function that includes a file based on the string that gets passed to it i.e. the action variable from the query string. I use this for filtering purposes etc so people can't include files they shouldn't be able to and if the file doesn't exist a default file is loaded instead.
The problem is that when the function runs and includes the file scope, is lost because the include ran inside a function. This becomes a problem because I use a global configuration file, then I use specific configuration files for each module on the site.
The way I'm doing it at the moment is defining the variables I want to be able to use as global and then adding them into the top of the filtering function.
Is there any easier way to do this, i.e. by preserving scope when a function call is made or is there such a thing as PHP macros?
Edit: Would it be better to use extract($_GLOBALS); inside my function call instead?
Edit 2:
For anyone that cared. I realised I was over thinking the problem altogether and that instead of using a function I should just use an include, duh! That way I can keep my scope and have my cake too.
Edit: Okay, I've re-read your question and I think I get what you're talking about now:
you want something like this to work:
// myInclude.php
$x = "abc";
// -----------------------
// myRegularFile.php
function doInclude() {
include 'myInclude.php';
}
$x = "A default value";
doInclude();
echo $x; // should be "abc", but actually prints "A default value"
If you are only changing a couple of variables, and you know ahead of time which variables are going to be defined in the include, declare them as global in the doInclude() function.
Alternatively, if each of your includes could define any number of variables, you could put them all into one array:
// myInclude.php
$includedVars['x'] = "abc";
$includedVars['y'] = "def";
// ------------------
// myRegularFile.php
function doInclude() {
global $includedVars;
include 'myInclude.php';
// perhaps filter out any "unexpected" variables here if you want
}
doInclude();
extract($includedVars);
echo $x; // "abc"
echo $y; // "def"
original answer:
this sort of thing is known as "closures" and are being introduced in PHP 5.3
http://steike.com/code/php-closures/
Would it be better to use extract($_GLOBALS); inside my function call instead?
dear lord, no. if you want to access a global variable from inside a function, just use the global keyword. eg:
$x = "foo";
function wrong() {
echo $x;
}
function right() {
global $x;
echo $x;
}
wrong(); // undefined variable $x
right(); // "foo"
When it comes to configuration options (especially file paths and such) I generally just define them with absolute paths using a define(). Something like:
define('MY_CONFIG_PATH', '/home/jschmoe/myfiles/config.inc.php');
That way they're always globally accessible regardless of scope changes and unless I migrate to a different file structure it's always able to find everything.
If I understand correctly, you have a code along the lines of:
function do_include($foo) {
if (is_valid($foo))
include $foo;
}
do_include(#$_GET['foo']);
One solution (which may or may not be simple, depending on the codebase) is to move the include out in the global scope:
if (is_valid(#$_GET['foo']))
include $_GET['foo'];
Other workarounds exists (like you mentioned: declaring globals, working with the $_GLOBALS array directly, etc), but the advantage of this solution is that you don't have to remember such conventions in all the included files.
Why not return a value from your include and then set the value of the include call to a variable:
config.php
return array(
'foo'=>'bar',
'x'=>23,
'y'=>12
);
script.php
$config = require('config.php');
var_dump($config);
No need to mess up the place with global variables
Is there any easier way to do this, i.e. by preserving scope when a function call is made
You could use:
function doInclude($file, $args = array()) {
extract($args);
include($file);
}
If you don't want to explicitly pass the variables, you could call doInclude with get_defined_vars as argument, eg.:
doInclude('test.template.php', get_defined_vars());
Personally I would prefer to pass an explicit array, rather than use this, but it would work.
You can declare variables within the included file as global, ensuring they have global scope:
//inc.php
global $cfg;
$cfg['foo'] = bar;
//index.php
function get_cfg($cfgFile) {
if (valid_cfg_file($cfgFile)) {
include_once($cfgFile);
}
}
...
get_cfg('inc.php');
echo "cfg[foo]: $cfg[foo]\n";

Categories