I have 2 includes on a page. Let's say they're the header and footer:
<?php
include('header.php');
include('footer.php');
I need to use a variable from the footer in the header. Is this possible?
Create another include or put the logic for the var into the main Script.
Unless there's a reason you can't, the simple solution is to set the variable used in inc2 in inc1 instead.
When a script is included outside of any function, the script executes in global scope, so anything it sets or defines that is scoped will have global scope. If a script is included within a local scope (such as in a function), the script executes in the same scope, so anything it defines is local. Note the included script can access variables local to a function.
function foo($x) {
$bar = 'bam';
include 'script.php'; # script.php can access $x and $bar
}
However, global variables can be problematic. A better approach is to break down tasks into separate modules. Most modules are library scripts: they only define things (functions, classes) and don't execute anything directly. The entry point (the top level script) doesn't define anything; instead, it serves to connect everything and as a starting-off point for computation. Here's a simple example with a database connection:
<?php
include_once('DB.php');
include_once('header.php');
include_once('footer.php');
$db = DB::connect();
header($db);
footer($db);
While technically $db is a global variable (note that this is merely sample code, rather than production code), it's not to be accessed anywhere outside this script. Instead, it's passed around according to the rules of capabilities (which was designed for security purposes, but the rules are actually just good OOP principles).
Related
I have a web application which is built in PHP 5.5. A new application has been added to it (in a sub-directory) which is built in Slim Framework v3.
The application is running in an environment whereby any PHP script that is executed has a file, config.php, included automatically using the auto_prepend_file directive in php.ini.
This is equivalent to having the following in all scripts, as far as I understand, but without the need to manually write require_once 'config.php' every time:
<?php
require_once 'config.php';
// Script starts here
?>
config.php contains a number of configuration settings; some of these are set using PHP's define method, (e.g. define('FOO', 'bar')) and others are normal PHP variables (e.g. $ASSETS_VER = '1.0');
Whenever we run PHP scripts that are not part of the Slim application all of the variables in config.php can be read. For example...
<?php
// myscript.php
echo FOO;
echo $ASSETS_VER;
?>
...will output whatever is in the config file ('bar' and '1.0' respectively).
The problem
However in the part of the application which uses Slim Framework - we can only read things from config.php which have been set using define(), whereas regular variables are undefined. So in the example above echo FOO will produce 'bar' whereas echo $ASSETS_VER will not produce anything.
I'm not sure if this is something to do with how Slim Framework works, but wondered if anyone knows why this is the case, and how to fix it?
PHP documentation on variables scopes reads: "For the most part all PHP variables only have a single scope. This single scope spans included and required files as well. ... within user-defined functions a local function scope is introduced. Any variable used inside a function is by default limited to the local function scope."
It seems that your "PHP scripts that are not part of the Slim application" use data from config.php only from code in global scope, i.e. from code that is not located inside method or function. So it sees both PHP constants and variables from config.php that are also in global scope.
Code that uses frameworks, such as Slim Framework usually is located in some kind of callback method or function that is called by framework code (i.e. it is in local scope). So your code sees global scope PHP constants (that are visible from local scope), but doesn't see global scope PHP variables (that are replaced by new-created local scope empty variables with the same names).
In order to use them you can declare them before using with keyword global, like this:
...
global $ASSETS_VER;
echo $ASSETS_VER;
...
I have PHP files a bit like this
public_html/environment.php
public_html/task.php
phpbin/actions.php
phpbin/library.php
environment.php is included by public_html/* before any other php files are included, phpbin/* assumes everything in environment.php is already available.
It defines these two globals
$g_foo = "...";
$g_bar = "...";
task.php includes this logic
function do_stuff ()
{
require_once determine_required_file ();
...
}
In this case, determine_required_file() returns "/path/to/phpbin/actions.php"
actions.php in turn contains
require_once "/path/to/phpbin/library.php"
Finally, library.php contains
$x = $g_foo;
$y = $g_bar;
I get this error:
Undefined variable: $g_bar;
Now, $g_foo and $g_bar are strictly read-only except in environment.php, I have exhaustively grepped and verified that there are no other places which create or modify variables with these names.
I am aware that PHP globals are weird, and doing things like including files from within functions can mess up your scope. I know that I should probably use define() or some other method, yeah yeah.
My question is this (yes, I'm asking you to speculate in the absence of full code, sorry):
Why might $g_bar generate an error but not $g_foo?
I assume the in-function-inclusion is probably responsible, but assuming these globals really are read-only, what should I be looking for as the culprit for why one ends up in global scope in library.php but not the other?
You need to use include_once instead of required_once for your fields that needed your global variables, or define a global $g_bar, $g_foo.
http://php.net/manual/en/language.variables.scope.php
I want a variable to be superglobal, but as am using procedural style I don't think I can make one of my own, so basically the question is that am using a query to retrieve all security control of my website from security table, am checking whether maintenance mode is on/off, if it's on am redirecting it to website under maintenance page, so on each page I need to check the status of variable $maintenance_status, for doing this, i need to call that query on each page, or else am getting an error that undefined variable, moreover if am making a function and including that function file in other pages, it is showing me that $db_connect(which is my db connection variable) is undefined, am including my pages in this sequence
include_once('connection.php');
include_once('functions.php');
/*other scripts goes here*/
Any idea how to pull this status on each page? I thought to make a new file for common queries but is ait a clean solution? moreover I guess am not understanding includes, if I included connection.php before functions.php than why my functions.php is showing undefined variable $db_connect?
You can use a constant for that by using define(). Defines can be set once per script execution and can not be changed during one script execution. They are superglobal - also across files which are being included.
See http://php.net/define or just
define('MY_CONSTANT', 'whatever');
define('MY_OTHER_CONSTANT', false);
function foo() {
if (MY_OTHER_CONSTANT !== true) {
echo MY_CONSTANT;
}
}
foo();
Without more code context on where within your files you are getting the errors, it will be hard to provide any advice. For example, is your reference to $db_connect done from inside a function? If it is, than it will not work unless you have a global $db_connect declaration within that function (to use the $db_connect in the global scope rather than the undefined $db_connect in the function's scope).
While I don't prefer using such global declarations within functions for a number of reasons (I would rather use dependency injection, or get the DB connection via a static singleton function call), that is probably a lesson for another time.
You might be best served anyway to make your query in some sort of init script (like after your connection.php inlcude) and define a constant regarding whether maintenance mode if on or off. Something like this
// assuming you have already made DB query and have a value of true/false on a variable called $is_maint_mode
define('MAINT_MODE', $is_maint_mode);
This would give you a constant MAINT_MODE that is globally available to your code.
So if I have a variable in a php file I just made , if I put it in the same folder as other php files and include it into one of them , I can use any variable from that file right?
Sorry if it's a bit of noobish
Basically yea. Running the include is equivalent to pasting the code.
Specifically, from the PHP manual:
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.
In general the PHP manuals are pretty much self explained. You will find there most answers for basic questions as this one.
In short, yes.
From the documentation
The scope of a variable is the context within which it is defined. For
the most part all PHP variables only have a single scope. This single
scope spans included and required files as well. For example:
<?php
$a = 1;
include 'b.inc';
?>
Here the $a variable will be available within the included b.inc script.
Note that this also works in the other direction:
<?php
/* a.inc */
$a = 1;
?>
<?php
/* b.php */
include 'a.inc';
echo $a;
?>
A pattern I tend to use often in PHP is setting a few globals (such as $page, $user, $db, etc), and then including a file which uses those globals. I've never liked the idea of using globals for this, though, so I'm looking for a better way.
The obvious solution is to define a class or function in the subfile, and call it after the file is included. There are cases where that can't work though, such as this:
// Add entries to a URI table from each section of the site
global $router;
$router = new VirtualFileSystem();
$sections = array('store', 'forum', 'blog');
foreach($sections as $section)
include dirname(__FILE__) . $section . '/routing.php';
// Example contents of 'forum/routing.php'
// implicitly receive $router from caller
$router->add('fourm/topic/', 'topic.php');
$router->add('forum/topic/new/', 'new_topic.php');
// etc
If I tried to wrap each routing.php in a function and call them each with $router as an argument, the same function name would clash after being defined in multiple files.
I'm out of ideas. Is there a better way to pass variables to included files without polluting the global namespace?
include and its siblings are basically just copy-paste helpers, and the code inside them shares scope with the calling block - as if you'd copy & paste it just where the include statement is. The sane way of using them is to think of them the same way you'd use #include in C or using in C# or import in Java: import some code to be referenced later on. If you have code in the included file that needs parameters, then wrap it in a function, put the parameters in the function arguments, use include_once at the top of the including file, and call the function with the parameters you want, wherever you need to. No globals required. As a rule of thumb, in regular operation, putting any code that "does" something (executes statements in the global scope) in an included file is best avoided IMO.
No, there is not. You're not passing variables to included files anyway. The code that is included behaves as if it was written where the include statement is written. As such, you're not passing variables into the included file, the code in the file can simply use the variables that are in scope wherever the include statement is located.
In your case the contents of forum/routing.php are not really standalone code, they're code snippets that depend on a very specifically set up scope to function correctly. That's bad. You should write your includable files in a way that does not couple them to the including code. For example, you could make your Router a static class and call it statically in forum/routing.php:
require_once 'virtual_file_system.class.php';
VirtualFileSystem::add('forum/topic/', 'topic.php');
As long as there is a class VirtualFileSystem in your app, this will work, and won't pollute the namespace any more than it already is anyway.
just isolate includes in a function:
function add_entries_to_router($router, $sections) {
foreach($sections as $section)
include dirname(__FILE__) . $section . '/routing.php';
}
$router = new VirtualFileSystem();
add_entries_to_router($router, array('store', 'forum', 'blog'));
You can try an OOP way by making a Configuration class as a singleton and retrieving it when you need it.
You could define magic methods for __get and __set to add them to an private array var and make the constructor private.
I usually define as constant only the path to my src project in order to load class files quickly and properly (and use some SPL too).
But I agree with #tdammers about the fact that an include keep the environment variables like if you were on the caller file (the one who makes the include).