I have code where I use some variables. Example:
$name = "someName";
$output = sprintf($doingText, $name); // $doingText is here undefined
I want to search the code for surely undefined variables (some sort of static code analysing).
These variables should be all some language text. No problem until there, but I don't want to make manually a list which variables exist: I want to get the variable names and then make some html form where I can see them and put into database in variablename-text pairs.
Question is: how to search them? (I haven't found any script which is able to do this in PHP by googling...)
(p.s.: I don't know what is the best method to search them as there may not be only assignments by =, but also with foreach ($arr as $val) etc.)
Why not use an IDE like NetBeans? That will actively check if you have unused variables. So while your coding it will show you in real time, rather then finish the script and find out you have x amount of errors/unused variables. Just food for thought.
Related
Is there anything wrong with doing this? Ive looked everywhere and it doesnt seem like this is a common thing? is there a built in function im not aware of that does this? Im using PDO for inputs so I am assuming this is fine.
thanks for ANY help!!
foreach($_POST as $post => $var){
${$post} = $var;
}
Warning
As #Gumbo stated, this is, in no way, what you want to do. You
should avoid doing anything like this with super globals in any sense.
You're better off controlling each aspect as best as possible and
assigning the variables properly, as best practice permits. i.e.
$a = 'derp';
What you're doing is called Variable Variable and is built into PHP. It essentially allows you to dynamically create variables for use within the current scope.
Take a $_POST array of the following:
Array (
[a] => 'derp'
)
Now with your current code, you'll be dynamically creating & assigning a variable:
foreach($_POST as $post => $var){
${$post} = $var;
}
Which in turn, allows you to access said variable as the key:
echo $a; // would echo out derp
From personal experience, this isn't always necessary and an issue you could potentially run into is overwriting a variable that has already been set, in turn, producing unwanted/unexplained output.
You'd be best to have a read of these answers to gain a wider understanding of what you're currently doing:
Dynamic variable names in PHP
PHP Variables - Concatenate variable name
php variable variables problem (especially worth a read if trying to harness superglobals)
Firstly - some background. We have a config.php file which lists several variables and settings in this format:
$MY_EMAIL_ADDRESS = 'test#test.com';
$MY_WEBSITE = 'www.test.com';
$SOMETHING_ELSE = 'foobar';
I would like to replace them with more sensible (and secure) names as part of an array, throughout the entire PHP project. Mostly so we can do this more securely: Get PHP variable value via Ajax with variable name as parameter
We have also forgotten some of these variables names, so that they are used throughout the project, but possibly not documented - hence doing a search one-by-one will prove difficult.
Is there a way I can search the php files for any values that start with a dollar sign ($) and then are made up of only upper case letters and possibly underscores?
$MY_SETTING_NAME
We could then either build a list and update manually, or build some kind of script to replace things with a more sensible way of working:
$CONFIG['MY_SETTING_NAME']
Thank you!
You can use get_defined_vars function which will return all variables as array.
Please look at php.net website for example
In some code I'm working on I have noticed that several variables are being accessed from outside of foreach loops.
This is seen in codeigniter view files of this particular app.
For example, a view file:
<?php
foreach ($items as $row):
endforeach;
// HTML / PHP code...
<td>
<?php echo form_checkbox('option_1','1', FALSE); ?>
<?php echo form_hidden('weight_unit', $row->weight_unit); ?>
</td>
// etc...
This works (ie, no errors) but I wonder if this would be considered a bad practice and if so, why? (scope, etc)
Does anyone have an opinion on this and should variables only be called inside their corresponding loops?
Another issue I've noticed is if a variable is required in several parts of a view file: should I refactor to have multiple loops or should there be a single foreach / endforeach and the begin / end of the file.
Any suggestions are much appreciated. Thanks.
The only reason I could think of doing that is to seek to the end of the array so you can store its last member in a variable.
You can do this clearer with end().
$row = end($items);
$row will be the last item in the array, or unset, when it reaches your other code.
Is that want you want? If so, then it's not bad practice, per se. But you should at least document that the behavior is intended, because it's not intuitive.
Better practice is something like:
foreach ($foo as $bar)
{
// do something
}
$last_bar = isset($bar) ? $bar : null;
There it's obvious that you mean to do something with $last_bar.
Another issue I've noticed is if a variable is required in several parts of a view file
If you must iterate over your loop in different places in your view, then that's okay.
But if you just need a certain piece of information deep inside some array, then you should stick it into an easily accessible variable and use that instead.
This is a bad practice. If the recordset is more than one item long then you are looping through all the records (even though you do nothing in the loop) and then just using the last record. I dont use CI but if this is a recordset object there ought to be someway to access the first/last record or any other index position in the RS. You should use those if youre after a particular record. If its just an array you could use array_pop if you dont need to keep the array intact, or end if you do.
Additionally, in the same context of a lengthy set if its not really the last record your after this could have unforseen consequences if the recordset length changes.
I'd say this is really bad practice - what happens if later (in a few weeks) you come across the same piece of code and you need another foreach on totally different record types between the actual foreach and your table? - your $row variable will then have a totally different meaning - this piece of code is very susceptible to side effects when more code is added.
Also, there is a high possibility that in the future this behavior will not be supported by PHP anymore (this is just an assumption of mine, because, as you mentioned, the $row variable is out of scope where you are using it).
As some general principles:
use as few as possible global variables - they are hard to track, maintain and assure correct values
minimize the scope of the variables as much as possible and use them only in very clear scopes
avoid marginal use cases and so called features that are totally unnatural in other languages
last, but not least, avoid the principle if code was hard to write it should be hard to read - this principle won't secure you the job, only the hate of your coworkers
Solution?
Apparently there isn't a faster way, I'm okay with that.
I am just learning php and I am trying to figure out some good tips and tricks so I don't get into a bad habit and waste time.
I am passing in values into a php script. I am using $_GET so the URL looks like this:
/poll_results.php?Sports=tennis&cat=Sports&question=Pick+your+favorite+sports
Now I know how to accept those values and place them into variables like so:
$sports = $_GET['Sports'];
$cat = $_GET['cat'];
$question = $_GET['question'];
Super simple yet if I am passing 5 - 6 things it can get bothersome and I don't like typing things out for every single variable, that's the only reason. I know there is a better way of doing this. I have tried list($var, $var, $var) = $_GET but that doesn't work with an associative array just indexed ones (i think).
I also tried variable variables like so:
foreach($_GET as $value) {
$$values = $value;
echo $$values;
}
But that gave me a Notice: Undefined variable: values in poll_results.php on line 14. Line 14 is the $$values = $value. I don't know if that's a big deal or not... but I'm not turning off error reporting as I am still in the process of building the script. It does do what I want it to do though...
Any answers will be copied and pasted into my question so the next person knows :D
Thanks guys!
Your second bit of code is wrong. It ought to be like
foreach ($_GET as $key => $value) {
$$key = $value;
}
if i understand your intent. However, you're basically reinventing register_globals, which....eh. That'll get ya hacked.
If you have certain variables you want to get, you could do like
foreach (array('Sports', 'cat', 'question') as $key)
{
$$key = $_GET[$key];
}
which is less likely to overwrite some important variable (whether by accident or because someone was messing around with URLs).
Use parse_url() to extract the query string from a URL you've got in a string, then parse_str() to extract the individual arguments of the query string.
If you want to pollute your script with the contents of the superglobals, then you can use extract(). however, be aware that this is basically replicating the hideous monstrosity known as "register_globals", and opens all kinds of security vulnerabilities.
For instant, what if one of the original query arguments was _GET=haha. You've now trashed the $_GET superglobal by overwriting it via extract().
I am just learning php and I am trying to figure out some good tips and tricks so I don't get into a bad habit and waste time.
If I am passing 5 - 6 things it can get bothersome and I don't like typing things out for every single variable, that's the only reason.
What you are trying to do will, unless curbed, become a bad habit and even before then is a waste of time.
Type out the variables: your digits like exercise and your brain can take it easy when it doesn't have to figure out which variables are available (or not, or maybe; which would be the case when you use variable variables).
You can use
foreach($_GET as $key => $value)
To preserve the key and value associativity.
Variable variables (the $$value) are a bad idea. With your loop above say you had a variable named $password that is already defined from some other source. Now I can send $_GET['password'] and overwrite your variable! All sorts of nastiness can result from this. It's the same reason why PHP abandoned register_globals which essentially does the same thing.
My advice: use $_POST when possible. It keeps your URLs much cleaner for one thing. Secondly there's no real reason to assign the array to variables anyway, just use them where you need them in the program.
One good reason for this, especially in a large program, is that you'll instantly know where they came from, and that their data should not be trusted.
I am a C++ programmer starting with PHP. I find that I lose most of the debugging time (and my selfesteem!) due to undefined variables. From what I know, the only way to deal with them is to watch the output at execution time.
Are other strategies to notice these faults earlier (something like with C++ that a single compile gives you all the clues you need)?
This is a common complaint with PHP. Here are some ideas:
Use a code analysis tool. Many IDEs such as NetBeans will help also.
Just run the code. PHP doesn't have an expensive compilation step like C++ does.
Use unit testing. Common side effects include: better code.
Set error_reporting(-1), or the equivalent in your ini file.
Get xdebug. It's not preventative, but stack traces help with squishing bugs.
isset(), === null (identity operator), and guard clauses are your friends.
Loose and dynamic typing are a feature of the language. Just because PHP isn't strict about typing doesn't mean you can't be. If it really bugs you and you have a choice, you could try Python instead—it's a bit stricter with typing.
Log your E_NOTICE messages to a text file. You can then process logs with automated scripts to indicate files and lines where these are raised.
No. In PHP, you can only know a variable doesn't exist when you try to access it.
Consider:
if ($data = file('my_file.txt')) {
if (count($data) >= 0)
$line = reset($data);
}
var_dump($line);
You have to restructure your code so that all the code paths leads to the variable defined, e.g.:
$line = "default value";
if ($data = file('my_file.txt')) {
if (count($data) >= 0)
$line = reset($data);
}
var_dump($line);
If there isn't any default value that makes sense, this is still better than isset because you'll warned if you have a typo in the variable name in the final if:
$line = null;
if ($data = file('my_file.txt')) {
if (count($data) >= 0)
$line = reset($data);
}
if ($line !== null) { /* ... */ }
Of course, you can use isset1 to check, at a given point, if a variable exists. However, if your code relies on that, it's probably poorly structured. My point is that, contrary to e.g. C/Java, you cannot, at compile time, determine if an access to a variable is valid. This is made worse by the nonexistence of block scope in PHP.
1 Strictly speaking, isset won't tell you whether a variable is set, it tell if it's set and is not null. Otherwise, you'll need get_defined_vars.
From what I know the only way to deal with them is to watch the output at execution time.
Not really: To prevent these notices from popping up, you just need to make sure you initialize variables before accessing them the first time. We (sadly IMO) don't have variable declaration in PHP, but initializing them in the beginning of your code block is just as well:
$my_var = value;
Using phpDocumentor syntax, you can also kind of declare them to be of a certain a type, at least in a way that many IDEs are able to do code lookup with:
/** #desc optional description of what the variable does
#var int */
$my_var = 0;
Also, you can (and sometimes need to) use isset() / empty() / array_key_exists() conditions before trying to access a variable.
I agree this sucks big time sometimes, but it's necessary. There should be no notices in finished production code - they eat up performance even if displaying them is turned off, plus they are very useful to find out typos one may have made when using a variable. (But you already know that.)
Just watch not to do operations that requires the variable value when using it the first time, like the concatenate operator, .=.
If you are a C++ programmer you must be used to declare all variables. Do something similar to this in PHP by zeroing variables or creating empty array if you want to use them.
Pay attention to user input, and be sure you have registered globals off and check inputs from $_GET and $_POST by isset().
You can also try to code classes against structural code, and have every variable created at the beginning of a class declaration with the correct privacy policy.
You can also separate the application logic from the view, by preparing all variables that have to be outputted first, and when it goes to display it, you will be know which variables you prepared.
During development stages use
error_reporting(E_ALL);
which will show every error that has caused, all NOTICE errors, etc.
Keep an eye on your error_log as well. That will show you errors.
Use an error reporting system, example:
http://php.net/manual/en/function.set-error-handler.php
class ErrorReporter
{
public function catch($errno, $errstr, $errfile, $errline)
{
if($errno == E_USER_NOTICE && !defined('DEBUG'))
{
// Catch all output buffer and clear states, redirect or include error page.
}
}
}
set_error_handler(array(new ErrorReporter,'catch'));
A few other tips is always use isset for variables that you may / may not have set because of a if statement let’s say.
Always use if(isset($_POST['key'])) or even better just use if(!empty($_POST['key'])) as this checks if the key exists and if the value is not empty.
Make sure you know your comparison operators as well. Languages like C# use == to check a Boolean state whereas in PHP to check data-types you have to use === and use == to check value states, and single = to assign a value!
Unless I'm missing something, then why is no one suggesting to structure your page properly? I've never really had an ongoing problem with undefined variable errors.
An idea on structuring your page
Define all your variables at the top, assign default values if necessary, and then use those variables from there. That's how I write web pages and I never run into undefined variable problems.
Don't get in the habit of defining variables only when you need them. This quickly creates spaghetti code and can be very difficult to manage.
No one likes spaghetti code
If you show us some of your code we might be able to offer suggestions on how you can better structure it to resolve these sorts of errors. You might be getting confused coming from a C background; the flow may work differently to web pages.
Good practice is to define all variable before use, i.e., set a default value:
$variable = default_value;
This will solve most problems. As suggested before, use Xdebug or built-in debugging tools in editors like NetBeans.
If you want to hide the error of an undefined variable, then use #. Example: #$var
I believe that various of the Code Coverage tools that are available for PHP will highlight this.
Personally, I try and set variables, even if it's with an empty string, array, Boolean, etc. Then I use a function such as isset() before using them. For example:
$page_found = false;
if ($page_found==false) {
// Do page not found stuff here
}
if (isset($_POST['field'])) {
$value = $_POST['field'];
$sql = "UPDATE table SET field = '$value'";
}
And so on. And before some smart-ass says it: I know that query's unsafe. It was just an example of using isset().
I really didn't find a direct answer already here. The actual solution I found to this problem is to use PHP Code Sniffer along with this awesome extension called PHP Code Sniffer Variable Analysis.
Also the regular PHP linter (php -l) is available inside PHP Code Sniffer, so I'm thinking about customizing my configuration for regular PHP linting, detecting unused/uninitialized variables and validating my own code style, all in one step.
My very minimal PHPCS configuration:
<?xml version="1.0"?>
<ruleset name="MyConfig">
<description>Minimal PHP Syntax check</description>
<rule ref="Generic.PHP.Syntax" />
<rule ref="VariableAnalysis" />
</ruleset>