From the php manual
Include_once may help avoid problems such as function redefinitions, variable value reassignments, etc.
Ok, so include_once solves issues with function redefinitions, variable value reassignments, etc. but why are they an issue in the first place ?
I'm trying to understand what kind of risks are involved in redefining functions or reassigning variable values except for a decline in performance due to additional input/output and processing ?
Is it because php parser gets confused which version of function to load/use or is the original version of the function lost once redefined? What else and what about variable reassignments?
I do understand where to use include vs include_once.
Imagine the following include file, hello.php:
function hello()
{
return 'Hello World';
}
$a = 0;
Now imagine the following file, index.php:
include 'hello.php';
$a = 1;
hello();
include 'hello.php';
hello();
echo $a; // $a = 0, not 1
Your code would now have a fatal error, since the function has been defined twice. Using include_once would avert this, since it would only include hello.php once. Also, to do with variable value reassignment, $a (should the code compile) would be reset to 0.
From the comments, please consider this a side answer - If you're looking for something where resetting a set of variables many times was required, I'd look to use a class for this with a method like Reset, you can even make it static if you didn't want to have to instantiate it, like so:
public class MyVariables
{
public static $MyVariable = "Hello";
public static $AnotherVariable = 5;
public static function Reset()
{
self::$MyVariable = "Hello";
self::$AnotherVariable = 5;
}
}
Usage like:
MyVariables::$MyVariable = "Goodbye";
MyVariables::Reset();
echo MyVariables::$MyVariable; // Hello
Let's say you have an include script vars.inc.php:
<?php
$firstname = 'Mike';
$lastname = 'Smith';
?>
And then you have a script script.php:
<?php
echo "$firstname $lastname"; // no output
include('vars.inc.php');
echo "$firstname $lastname"; // Mike Smith
$firstname = "Tim";
$lastname = "Young";
echo "$firstname $lastname"; // Tim Young
include('vars.inc.php');
echo "$firstname $lastname"; // Mike Smith
?>
What happens is that if you modify your vars in code exection and then you include once again the file defining them, you are changing their content. include_once will ensure that this will never happens throwing an error.
It will stop you loading pages more than once. Typically you'll use this at the top of your pages to bring in your init, function, class files etc.
Especially useful if you are loading pages within pages dynamically.
Related
I would like to create a multiple language website but I have a problem!
I will explain it to you with an example:
lang-en.php
<?php
$lang = [];
$lang['hello'] = "Wellcome $userName to our website!";
?>
index.php
<?php
$useName = "Amir";
require_once("lang-en.php");
echo $lang['hello'];
?>
Now, I would like to see this output in my page:
Welcome Amir to our website!
How can i do this?
It might be smart to make it a bit more complicated, to look to the future. If you remove the implementation part to a separate class, you can have your actual usage and the implementation of the translation separate. If you plan to use gettext (po/mo files) later, you can switch easier.
A simple, but untested, example would be
class translate{
private $translations = [
'hello' => "Wellcome %s to our website!",
]
public function trans($key, $value)
{
return sprintf($this->translations[$key], $value);
}
}
Mind you, this is a quick example, and probably needs some work -> for instance, it presumes always a single variable, etc etc. But the idea is that you create class with an internal implementation, and a function that you call. If you can keep the function call's footprint the same, you can change the working of your translation system!
You'll call this like so
$trans = new Translate();
echo $trans->trans('hello', 'Amir');
(again, I typed this in the answer box, no check for syntax, testing etc has been done, so this is probably not a copy-paste ready class, but it is about the idea)
edit: as requested, a bit more example. Again, not tested, probably some syntax errors etc, but to help you with the idea:
class translate{
private $translations = [
'hello' => array('test' =>"Welcome %s to our website!", 'vars' => 1),
'greet' => array('test' =>"I'd like to say $s to %s ", 'vars' => 2),
]
public function trans($key, array $values)
{
// no translation
if(!isset($this->translations[$key])){
return false; // or exception if you want
}
// translation needs more (or less) variables
if($this->translations[$key][vars] !== count($values)){
return false; // or exception if you want
}
// note: now using vsprintf
return vsprintf($this->translations[$key], $values);
}
}
Make a function one in lang-en.php
<?php
function lang($username)
{
$lang['hello'] = $username;
echo $lang['hello'];
}
?>
In index.php call that function
<?php
require_once("lang-en.php");
lang('arun');
?>
you nearly had it
langen.php
<?php
//declare array
$lang = array();
$templang['hello1'] = "Wellcome ";
$templang['hello2'] = " to our website!";
//add new item in array
array_push($lang,$templang);
?>
index.php
<?php
$useName = "Amir";
require_once("langen.php");
//it is first entry of array row so [0] is 0
echo $lang[0]['hello1'];
echo $userName;
echo $lang[0]['hello2'];
//out is welcome amir to our website
?>
this is a easy way too see how to pass variables a little long way but i didn't want to combine so that you can see how it works you can also do some reading about sessions for passing variables between pages that is not included
Amir Agha,
When you call another .php file by include or require php acts as if the contents of the included file is inserted in the same line and the same scope (except for classes and functions) so your code in the view of php interpreter looks like this:
<?php
$userName = "Amir";
$lang = [];
$lang['hello'] = "Wellcome $userName to our website!";
echo $lang['hello'];
?>
So this code must display:
Wellcome Amir to our website!
But why it doesn't work? Simply because you wrote $useName instead of $userName in your index.php file.
p.s.: Other answers made it very complicated. only change $useName to $userName
i am trying to find out a way to pass non global variables to included document.
page1.php
function foo()
{
$tst =1;
include "page2.php";
}
page2.php
echo $tst;
How can i make that variable be visible ? and how would i do this php templating so i can split header body and footer for html pages. like in a wordpress it has custom wp functions but i dont see them declaring external files to use them.
big thanks in advance.
I think you are not exactly understanding what is going on. Page 1 should probably be doing the echoing. So you include page 2 and the foo function is now available. You need to call it so that it actually executes. Use the global keyword to bring a global variable into the function scope. Then you can echo it.
page1:
include "page2.php";
foo();
echo $test;
page 2:
function foo()
{
global $test;
$test =1;
}
Variables in a function are not seen outside of them when they are not global. But an include in a function should be seen inside the second file.
$test="Big thing";
echo "before testFoo=".$test;
// now call the function testFoo();
testFoo();
echo "after testFoo=".$test;
Result : *after testFoo=Big thing*
function testFoo(){
// the varuiable $test is not known in the function as it's not global
echo "in testFoo before modification =".$test;
// Result :*Notice: Undefined variable: test in test.php
// in testFoo before modification =*
// now inside the function define a variable test.
$test="Tooo Big thing";
echo "in testFoo before include =".$test;
// Result :*in testFoo before include =Tooo Big thing*
// now including the file test2.php
include('test2.php');
echo "in testFoo after include =".$test;
// we are still in the function testFoo() so we can see the result of test2.php
// Result :in testFoo after include =small thing
}
in test2.php
echo $test;
/* Result : Tooo Big thing
as we are still in testFoo() we know $test
now modify $test
*/
$test = "small thing";
I hope that made the things more clear.
I have a class with this function:
public function loadTemplate($template)
{
return require "templates/$template.php";
}
It's fine, but I have a problem with it.
Let's say I have this code:
require('class.php');
$class = new ClassName; // ClassName is the class which contains the function loadTemplate()
$name = 'Jerry';
$class->loadTemplate('myname');
And "myname.php" is:
<?php
echo "My name is $name.";
In this case I get an error because "myname.php" is actually included in the file of the class and so $name is undefined.
How do I overcome this problem?
Not discussing whether that's the best design, here's how you can do it.
public function loadTemplate($template, $vars)
{
extract($vars);
ob_start();
require "templates/$template.php";
$viewContent = ob_get_contents();
ob_get_clean();
return $viewContent;
}
Pass your variables as an associative array:
$vars = ['name' => 'Jerry']
And then output it:
echo $class->loadTemplate('myname', $vars);
What this does is, it creates variables from the array and loads the view, but with the "ob_" functions we are capturing the output buffer and then echoing it if we want.
You could probably get away without using ob_ just by echoing the require method as you were trying. I'd say give it a go and use what you prefer.
Upon executing a script, sometimes the variable will be set, and sometimes it won't. The times that it isn't, I'm given a notice that the variable is not defined.
In efforts to clear the notice, I simple added the following code
if(!isset($var)) {
$var = NULL;
}
That works just as needed because it tests if the variable isn't already set so that we don't set something that we need to NULL. But in a file where there are over 60 variables that are of this case and more to come, I thought creating a simple function to do so would be easier. So I started with this:
function init($var) {
if(!isset($var)) {
return $var = NULL;
}
}
Obviously that doesn't work and is also riddled with errors that will annoy most programmers out there (such as the !isset() inside a function, not supplying a return statement in case the if statement is false, etc.) but that's just to give you the basic jist of what I need so in the code I can just call init($var); to test if the variable isn't already set, and then creates one and sets it to NULL to avoid the notice.
Is this even possible? To use a function to test if a variable is already set outside of the function? Thanks in advance :)
You can't use a function to check if a variable exists without it being initialized in the process of passing it to the function as an argument. You can, however, define an array of variable names your script requires then loop through them and check if they exist one by one. Such as:
foreach(array('username','userid','userrole','posts','dob','friends') as $var)
{
if(!isset($$var))$$var=NULL;
}
Edit: Simplifying user4035's approach, you could get the function down to:
<?php
function init(&$var){}
init($myVariable);
var_dump($myVariable);
Or even avoid a function altogether:
<?php
array(&$var1,&$var2,&$var3);//define several variables in one shot as NULL if not already defined.
var_dump($var1);
var_dump($var2);
var_dump($var3);
Another approach would be to use extract:
<?php
$defaults=array('username'=>NULL,'userid'=>0,'userrole'=>'guest','posts'=>0,'dob'=>0,'friends'=>array());
$userid=24334;
$username='bob';
$friends=array(2,5,7);
extract($defaults, EXTR_SKIP);
echo '<pre>';
print_r(
array(
'userid'=>$userid,
'username'=>$username,
'friends'=>$friends,
'userrole'=>$userrole,
'posts'=>$posts,
'dob'=>$dob)
);
echo '</pre>';
Another approach would be to temporarily disable error reporting:
<?php
$v=ini_get("error_reporting");
error_reporting(0);
echo 'One';
echo $doh;//Use an undefined variable
echo ' Two';
error_reporting($v);
I'd advise against this approach though because it is just hiding the errors rather than fixing them and will also hide errors worthy of your attention.
And my personal favorite would be to take advantage of namespaces.
Usually you'd put these into separate files but I put them into a single snippet for your convenience:
<?php
namespace //This is the global namespace
{
$config=array('production'=>0);
}
namespace MyScript
{
//Initialize all variables for our script
//anything not defined here will be inherited from the global namespace
$username=NULL;
$userid=NULL;
$userrole=NULL;
$posts=NULL;
$dob=NULL;
$friends=NULL;
}
namespace MyScript\Main
{
//Define only two variables for our script
//Everything else will be inherited from the parent namespace if not defined
$username='Ultimater';
$userid=4;
echo '<pre>';
print_r(
array(
'userid'=>$userid,
'username'=>$username,
'friends'=>$friends,
'userrole'=>$userrole,
'posts'=>$posts,
'dob'=>$dob,
'config'=>$config)
);
echo '</pre>';
}
If your intention is this:
if(variable is not set)
set variable to NULL
then it's quite easy to implement, using a reference:
function init(&$var) {
if(!isset($var)) {
$var = NULL;
}
}
Testing:
<?php
error_reporting(E_ALL);
function init(&$var) {
if(!isset($var)) {
$var = NULL;
}
}
init($x);
var_dump($x);
Output:
NULL
So the senario is that I want to have a custom function for requiring libraries. Something like:
define('E_ROOT', str_replace('//','/',dirname(__FILE__)));
/* ... */
function e_load($fn, $allowReloading = FALSE) {
$inc = E_ROOT.'/path/here/'.$fn.'.php';
if($allowReloading)
require $inc; // !!!
else
require_once $inc; // !!!
}
The problem being that require and require_once will load the files into the namespace of the function, which doesn't help for libraries of functions, classes, et cetera. So is there a way to do this?
(Something avoiding require and require_once altogether is fine, as long as it doesn't use eval since it's banned on so many hosts.)
Thanks!
Technically include() is meant to act as though you're inserting the text of included script at that point in your PHP. Thus:
includeMe.php:
<?php
$test = "Hello, World!";
?>
includeIt.php:
<?php
include('includeMe.php');
echo $test;
?>
Should be the exact same as:
<?php
/* INSERTED FROM includeMe.php */
$test = "Hello, World!";
/* END INSERTED PORTION */
echo $test;
?>
Realizing this, the idea of making a function for dynamically including files makes about as much sense (and is about as easy to do) as having dynamic code all-together. It's possible, but it will involve a lot of meta-variables.
I'd look into Variable Variables in PHP as well as the get_defined_vars function for bringing variables into the global scope. This could be done with something like:
<?php
define('E_ROOT', str_replace('//','/',dirname(__FILE__)));
/* ... */
function e_load($fn, $allowReloading = FALSE) {
$prev_defined_vars = get_defined_vars();
$inc = E_ROOT.'/path/here/'.$fn.'.php';
if($allowReloading)
require $inc; // !!!
else
require_once $inc; // !!!
$now_defined_vars = get_defined_vars();
$new_vars = array_diff($now_defined_vars, $prev_defined_vars);
for($i = 0; $i < count($new_vars); $i++){
// Pull new variables into the global scope
global $$newvars[$i];
}
}
?>
It may be more convenient to just use require() and require_once() in place of e_load()
Note that functions and constants should always be in the global scope, so no matter where they are defined they should be callable from anywhere in your code.
The one exception to this is functions defined within a class. These are only callable within the namespace of the class.
EDIT:
I just tested this myself. Functions are declared in the global scope. I ran the following code:
<?php
function test(){
function test2(){
echo "Test2 was called!";
}
}
//test2(); <-- failed
test();
test2(); // <-- succeeded this time
?>
So the function was only defined after test() had been run, but the function was then callable from outside of test(). Therefore the only thing you should need to pull into the global scope are your variables, via the script I provided earlier.
require_once E_ROOT.$libName.'.php';
KISS
Instead of doing this...
$test = "Hello, World!";
... you could consider doing this ...
$GLOBALS[ 'test' ] = "Hello, World!";
Which is safe and consistent in both local function context, and global include context. Probably not harmful to visually remind the reader that you are expecting $test to become global. If you have a large number of globals being dragged in by your libraries maybe there's justification for wrapping it in a class (then you have the benefit of spl_autoload_register which kind of does what you are doing anyhow).