Why does globalizing an array decrease performance? - php

Let me begin by stating that I know using global variables is not the best practice, this is just a temporary tweak until a more extensive rewrite is completed. That said...
I came across some code that was being duplicated 3 times, like so.
template_1 loads an array, then filters out data, then loads template_part_2. template_part_2 loads the array again and filters out the exact same data, then loads the module_1. module_1 loads the array again and filters out the exact same data as the last two. Resulting in something like this:
include_array.php
function load_array(){
<multidimensional array here>
};
template_1.php
include_once(include_array.php);
$array = load_array();
// code to filter array
include_once(template_1_part_2.php);
template_1_part_2.php
$array = load_array();
// code to filter array
include_once(module_1.php);
module_1.php
$array = load_array();
// code to filter array
This seemed unnecessary to me and a waste of memory, so I changed it to only filter once and then globalize it in the subsequent files like so:
include_array.php
function load_array(){
<multidimensional array here>
};
template_1.php
include_once(include_array.php);
$array = load_array();
// code to filter array
include_once(template_1_part_2.php);
template_1_part_2.php
global $array;
include_once(module_1.php);
module_1.php
global $array;
Now this change saves me 2mb of memory per page load, but the page loads .03 seconds slower. That's about 18% less memory, but loads about 25% slower. I would assume it be more memory efficient and faster since it's doing less processing, but that is not what I'm seeing. I've tried to do some research as to why this is the case but I haven't found anything, can anyone shed some light on this mystery?
Thanks in advance!

I think you don't understand how including a file works in PHP. Basically when you include a file its like the code just gets appended to the one doing the include. Any variable that's defined outside of all functions is automatically accessible to the code (that's outside all functions) from all the files. So only inside functions would you have to use the global keyword to gain access to a global variable. You don't use the global keyword to make a variable from one file accessible in other files: you included the files all into one already so you don't have to do anything special to let them share.
The docs say it like:
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.
However:
If the include occurs inside a function within the calling file, then
all of the code contained in the called file will behave as though it
had been defined inside that function.
Make your includes global, i.e. outside all functions, and you shouldn't have to jump through all these hoops.

Related

PHP eval in eval cannot read predifined variables

Before I explain the issue, I know the risks of using eval, but there is no realy other way to do it on how my system is build, and it also is for a personal project only. (its a custom cms which when I publish it makes the physical files for me, I just made it though db so I don't need to upload files when not working remote and it is just easy).
Lets explain my issue, I have a main php file which handles all pages, all pages are stored in the db with code and all and is being executed through eval.
And the system also has a function include_db which basicly does the same as include from php normaly just from the db.
But when I access a variable defined in the first eval (main page) it can not be read out in the included eval from the db.
Weird thing is that functions can be read out though the second eval.
Any way to access variables normaly from the included eval that is being generated in the eval of the main page?
(I think it has to do because those variables are not global and its being executed in a function but I do not know a way to make every variable global :( )
Thanks in advance!
The code that is being evalled on the main page:
$skill = isset($_REQUEST['skill']) && is_string($_REQUEST['skill']) && isValidSkill($_REQUEST['skill']) ? $_REQUEST['skill'] : 'overall';
if(!isset($_REQUEST['player']))
include_db('highscore_overview');
else
include_db('highscore_player');
And inside the include of overview I dump the get_defined_vars() and that doesn't return the $skill I set before the include only the variables that are declared in the main index.php (database and such)
First of all a disclaimer: You should never ever execute code from a database. That is a big security risk. It means that whenever someone is successful in gaining access to your database (using sql-injection for example) is now also capable of executing arbitrary code in php by changing the code in your database. You really should not do that!
If you are using code from the database to implement custom (email-)templates, please consider using a templating-engine for that like twig. Most syntaxes of template-engines are built in a way that you cannot break out of them and execute arbitrary code like you could with raw php code.
That said, i now try to answer the original question (because i cannot stop you doing things you should not do anyways). In terms of variable-scope, eval behaves like a function. If you want the variables defined inside it global, you have to manually make every variable defined inside the eval global.
You can do that by append a code-snippet to every code executed in eval that takes every local (in eval defined) variable and writes it into global scope.
<?php
function include_db() {
# ... get $code from db here ...
# get's executed after code from db, globalizes all variables
$code .= ';foreach (get_defined_vars()) as $newGlobalName) {';
$code .= ' $GLOBALS[$newGlobalName] = $$newGlobalName;';
$code .= '}';
eval($code);
}

How to pass variables by reference to #include in a blade template?

In a Laravel 4.2 setup, I have a variable in a template that I wish to share across multiple includes:
master.blade
<?php $tabindex = 0; ?>{{--This is the variable--}}
#include('header'){{-- <-in header.blade, I often use ++$tabindex --}}
{{--$tabindex is still 0--}}
#include('content'){{-- <-in content.blade, I often use ++$tabindex --}}
{{--$tabindex is still 0--}}
#include('footer'){{-- <-in footer.blade, I often use ++$tabindex --}}
{{--$tabindex is still 0--}}
$tabindex if used as a tabindex html attribute is clearly a trivial example that I can get around with safety values and a large enough buffer value, but that's hardly elegant or a solution to the actual problem at hand. In regular php includes, it's my understanding that variable assignment in included files would affect the variables in the including file - this is the desired effect.
I tried View::share(), but it presented the same symptoms. Passing the value to the #include as an array is clearly passing by value and produced the same effect as well.
It almost seems like the including scope values are evaluated first in their entirety, and then the included scopes. If this is the case, it would make what I'm trying to do much less feasible if there is any usage in the including scope or further included scopes (even storing by way of some persisting memory) because the order of execution would be different than the order in the code.
Is there some undocumented blade sorcery to prevent a blade #include from cutting itself off from changing the values of its includer's variables or must I fall back on straight php include or some other ugly alternative (Session variables should persist their values across calling include scopes, but that's just a nasty and flimsy approach)?
Using,
#include('view', array('key'=>'value'))
Would be the best way.
I take it from what you said, that you've been doing something like this.
View::share('some_variable',$some_variable);
And maybe initialized the variable in the template. This practice is discouraged, but there-s another way you can do it, which would be to initialize the variable in a php file and share it from there by adding this line to the file.
$some_variable = 0; //Initialize it any way you need to.
View::share('some_variable', $some_variable);
And then in your app/start/global.php you add this line.
require app_path().'/composers.php';
Laravel blade include seem to create a variable scope for every included template you add.
View:share('name', $value)
Does different thing from what you want, it is intended to inject some arbitrary variables to every template rendered, it's usefull to define assets path in bootstrap or entry point of your controller.
To solve your problem, just tell php in the included scope to look up for a variable above via global, so main.blade.php:
<?php $tabIndex = 0 ?>
#include('subform');
and in templates subform.blade.php
<?php
global $tabindex;
$tabindex++;
?>
Note, this might not work if you define the variable not in a main template, I have tried this only at main template (the one that I render to in controller) and it worked.

Is there an equivalent to <jsp:include in PHP that can also handle parameters and default values

I have a PHP page that lists many products that each consist of HTML that -depending on the product- does or does not show certain information. I extracted this "product HTML" into a separate PHP file that I include many times. The external file uses variables for each of the product's attributes and also if statements so that parts of the HTML are not rendered at all when an attribute is not set.
The problem is that many of the attributes have default values that I do not want to set each time I call the include
So is there a mechanism in PHP that lets me include another PHP file in such a way that:
I can provide parameters to the file,
uses a default value for the parameters when I do not provide a value,
can be used multiple times in one file.
(This is the way <jsp:include works.)
Keep in mind that I cannot use simple variables (as far as I know) because they keep their value between two separate include calls.
When you include a file in PHP, that file has access to the current scope. So, we need a "clean" scope with no variables and populate the one we need. The best way to go is using a function and the PHP extract method:
function product($data){
extract($data);
require(....path to file);
}
Now call it:
product(array(
'foo' => 'bar',
....
));
This way, on the included file you got a $foo variable with 'bar' value and nothing else. This is how MVC frameworks deal with views.
Edit:
<?PHP
function product($data){
extract($data);
?>
<HTML content>
<?PHP
}
?>
Now "require_once" the file with this and call it like before.

using includes in overall php rather then each function

i am very new to php, i am used to writing .net, and i am finding the includes hard to understand and was hoping someone could help me understand how to correctly use an include once in a file, rather than inside each function..
take the following as an example
<?php
include 'test.php';
function test($a)
{
echo $value_from_test_php;
}
?>
the above code does not seem to work... however the below does
<?php
function test($a)
{
include 'test.php'
echo $value_from_test_php;
}
?>
i am having a hard time figuring out how to make an include work for all functions inside a file, rather then including it inside each function, any advice is greatly appreciated!
It's the scope of variable which is troubling you rather than includes, in PHP generally includes are used where there's a common page/markup to be included on each page, such as footer, header, etc
There are 4 types
include
include_once
require
require_once
The only difference is include will throw you an error if something goes wrong and will continue to execute the script where require will halt the further execution
You'll get everything here on includes - PHP Documentation
It all depends what is inside the file that you are include-ing! I would never, ever, suggest using include inside a function (or loop, or pretty much anything with brackets). Remember, the contents of the file being included are literally just "plopped in" place, right where the include statement is. So whatever scope (global, class, function, etc.) you're in when you include, is the scope that its contents will be declared in.
Put full class and function definitions in files, and include them at the top of the files where they are going to be used.
Your issue is not related to includes, but rather variable scope. By default a variable defined outside a function is not available within the function.
It's difficult to suggest the best solution without knowing exactly what it is you're trying to do, but the documentation (linked above) should get you started.
First example is not working because you use variable from global scope, if you want to use it then replace $value_from_test_php to $GLOBALS['my_var_name']

Using require_once inside a method

From what I understand using something like require_once will essentially copy and paste the code from one file into another, as if it was in the first file originally.
Meaning if I was to do something like this it would be valid
foo.php
<?php
require_once("bar.php");
?>
bar.php
<?php
print "Hello World!"
?>
running php foo.php will just output "Hello World!"
Now my question is, if I include require_once inside a method, will the file that is included be loaded when the script is loaded, or only when the method is called?.
And if it is only when the method is called, is there any benefit performance wise. Or would it be the same as if I had kept all the code into one big file.
I'm mainly asking as I've created an API file, which handles a large amount of calls, and I wan't to simplify the file. (I know I can do this just be creating separate classes, but I thought this would be good to know)
(Sorry if this has already been asked, I wasn't sure what to search for)
It will only include when the method is called, but have you looked at autoloading?
1) Only when the method is called.
2) I would imagine there's an intangible benefit to loading on the fly so the PHP interpreter doesn't have to parse extra code if it's not being used.
I usually use the include('bar.php'); i use it for when i use databvase information, i have a file called database.php with login info and when the file loads it calls it right up. I don't need to call up the function. It may not be the most effective and efficient but it works for me. You can also use include_once... include basically does what you want it to, it copies the code essencially..
As others have mentioned, yes, it's included just-in-time.
However, watch out for variable definitions (require()ing from a method will only allow access to local variables in that method's scope).
Keep in mind you can also return values (i.e. strings) from the included file, as well as buffer output with ob_start() etc.

Categories