Languages like C and even C# (which technically doesn't have a preprocessor) allow you to write code like:
#DEFINE DEBUG
...
string returnedStr = this.SomeFoo();
#if DEBUG
Debug.WriteLine("returned string =" + returnedStr);
#endif
This is something I like to use in my code as a form of scaffolding, and I'm wondering if PHP has something like this. I'm sure I can emulate this with variables, but I imagine the fact that PHP is interpreted in most cases will not make it easy to strip/remove the debugging code (since its not needed) automatically when executing it.
PHP doesn't have anything like this. but you could definitely whip up something quickly (and perhaps a regex parse to strip it out later if you wanted). i'd do it as such:
define('DEBUG', true);
...
if (DEBUG):
$debug->writeLine("stuff");
endif;
of course you'd have to write your own debug module to handle all that. if you wanted to make life easier on regex parsing, perhaps you could use a ternary operator instead:
$str = 'string';
DEBUG ? $debug->writeLine("stuff is ".$str) : null;
which would make removing debug lines pretty trivial.
xdump is one of my personal favorites for debugging.
http://freshmeat.net/projects/xdump/
define(DEBUG, true);
[...]
if(DEBUG) echo xdump::dump($debugOut);
It has a define funciton, documented here: http://us.php.net/manual/en/language.constants.php.
Given the set of differences between variables and constants explained in the documentation, I assume that PHP's define allows the interpreter to eliminate unusable code paths at compile time, but that's just a guess.
-- Douglas Hunter
Related
Is it possible to parse the contents of a constant in PHP?
For example,
define('WHO_AM_I', 'My name is $_SESSION['who_am_i'].'); // setup the constant string
echo eval(WHO_AM_I); // something like this -- but the eval() returns an error
Please note that I do not know the value of the _SESSION var until I actually use the constant later in the script stream.
Thanks.
AMENDED WITH REASON FOR WANTING TO DO THIS
I want to pull "hard coding" out of my script and give the user the ability to configure certain taxonomy in their site. So while I was doing this I also wanted to create a quasi-dynamic constant that I thought I might be able to parse later in the script.
If it can't be done...then it can't be done.
Don't shoot me for asking the question though.
A FINAL COMMENT TO AVOID ALL THIS CONFUSION
The purpose of my question has nothing to do with the eval() function. I am actually regretting having put it in there in the first place.
I put the eval() in the question simply to demonstrate to stackoverflow members that I did a bit if prep on my question rather than asking an open ended -- hey give me a solution without having offered any stab at it myself. So please disregard the eval().
All I want to know is can I somehow craft a define() in an way that makes the assigned value parse-able later in my script. That's it, that's all.
AMENDMENT C
I know I can do the following although I don't want to do it this way:
define('PARSE_ABLE_CONSTANT_PART_A', 'My name is ');
define('PARSE_ABLE_CONSTANT_PART_B', '.');
...later down the script road...
echo PARSE_ABLE_CONSTANT_PART_A . $_SESSION['who_am_i'] . PARSE_ABLE_CONSTANT_PART_B;
I just don't want to do it this way if I can make it slicker using an embedded var in the constant.
This seems really fishy, as other users have pointed out. You could do something like this if you wanted:
define('WHO_AM_I', 'echo \'My name is \'.$_SESSION[\'who_am_i\'];');
eval(WHO_AM_I);
This will always just echo the variable. You need to eval an expression afaik.
Just read your edit. I think you would be better suited with an .ini file, or maybe a static class with static properties. Makes it much more flexible, and you avoid the eval. You are talking user-generated content from what I can see - subjecting that to an eval call seems highly insecure.
A quick example of a static class you could use:
<?php
class myConstants{
public static function _($key){
switch($key){
case "WHO_AM_I":
return "My name is ".$_SESSION['who_am_i'];
break;
case "OTHER_CONSTANT":
// does some other evaluation and returns a string
break;
}
throw new Exception("Constant isn't defined");
}
}
?>
Then you can just echo myConstants::_('WHO_AM_I');
Constants by definition don't allow you to set it with dynamic content.
Here is a quote from the php manual:
As the name suggests, that value cannot change during the execution
of the script
You can see more by going here
You might be thinking of magical constants
I've been going through the code of a Wordpress plugin and found the following:
eval( '?>' . $foo . '<?php ' );
I'm curious if there is some specific situation I'm unaware of that this would be the right way to output the $foo variable. Is this just a case of the plugin author being wacky or is there something I should know? I would have just used echo...
UPDATE:
Thanks for all the great feedback. I'm face palming now that I didn't think of the template scenario. Specifically, this happens in the WP Super Cache plugin. I guess I'll have to have a closer look to see if it's necessary. I thought Super Cache cached the html output by Wordpress after all the PHP had already been processed...
In this instance, $foo is a string that (presumably) can contain in-lined PHP code. As such, to execute this PHP code, the string needs to be eval'ed.
That said, the use of eval is generally frowned upon, apart from in a very narrow set of circumstances, as it can lead to the execution of malicious code. (i.e.: If there's any possibility that $foo is a user-provided string, then use of eval could lead to disastrous consequences.)
See the existing When is eval evil in php? question/answers for more information.
That's not outputting the variable. $foo most likely contains a template, with other <?=$code();?> snippets embbeded.
The closing and opening PHP marker are used in this eval to switch from inline code, back to HTML mode. This eval() more or less amounts to:
include("data:,$foo"); // treat $foo string as if it was include script
Let me repeat it again: c.r.a.p
If eval() is the answer, you're almost
certainly asking the wrong question.
Rasmus Lerdorf
Target is to have something like:
#define sum( f1, f2 ) ( f1 + f2 )
where
sum(2,2)
is 4 in PHP. Is that somehow possible? Even better would be if I could call:
$s = 'first';
APPEND ' and second';
when append will be defined as function/method/something else which is appending to $s so after those 2 lines $s would be 'first and second'.
The point of macros in C is that they are expanded at compile time.
Therefore, using the macros does not have an impact on the speed of your code, which a function doing the same would have.
Therefore, an example of usage is:
#define MYPRINTF(x) printf("MYPRINTF says : %s\n",x)
MYPRINTF("blah");
The code above will be translated by the compiler directly into:
printf("MYPRINTF says : %s\n","blah");
The whole point of it is that it is faster than defining a function, such as this one:
void myprintf(char *x)
{
printf("myprintf says : %s\n","blah");
}
Because there is no overhead (in a function, you need to push arguments to the stack, etc).
In an interpreted language, like PHP, the above doesn't hold, as everything is executed directly during run-time, therefore using a mechanism like C's #define would be absolutely useless -- therefore, to answer your question, simply use ordinary functions instead.
just a thought from your comments
function withVeryLongWroteByAnIdiot() {
....
}
function xFunc() {
return withVeryLongWroteByAnIdiot();
}
PHP doesn't support macros in this sense, the (really quite valid) argument I believe being that there's not much difference between this and a normal function in PHP.
After all, it's not like there's any value in having a concept like this in a run-time interpreted language.
I don't believe PHP supports macros. If you think about it, macros in C aren't fancy constants, rather constants are the world's most boring C macros. PHP only understands the boring form through the define function.
That said, I disagree with the other respondents about their validity. There is a valid reason for them: when you want to use built-in functions to preprocess something. For example:
macro default_if_empty_value(value, default) (empty(value) ? default : value)
If you try to write that as a function and call it:
default_if_empty_value($this->that['something']->or[$other], 'Not here.');
then you'll get a PHP warning if any part of that variable chain is not defined, and the expanded version is harder to read:
empty($this->that['something']->or[$other]) ? 'Not here.' : $this->that['something']->or[$other];
PHP code is compiled, but it is compiled at runtime. A macro like this would be expanded by the PHP interpreter and then compiled into PHP bytecode. This bytecode is often cached by the PHP interpreter or an add-on like APC.
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>
I'm looking to improve my PHP coding and am wondering what PHP-specific techniques other programmers use to improve productivity or workaround PHP limitations.
Some examples:
Class naming convention to handle namespaces: Part1_Part2_ClassName maps to file Part1/Part2/ClassName.php
if ( count($arrayName) ) // handles $arrayName being unset or empty
Variable function names, e.g. $func = 'foo'; $func($bar); // calls foo($bar);
Ultimately, you'll get the most out of PHP first by learning generally good programming practices, before focusing on anything PHP-specific. Having said that...
Apply liberally for fun and profit:
Iterators in foreach loops. There's almost never a wrong time.
Design around class autoloading. Use spl_autoload_register(), not __autoload(). For bonus points, have it scan a directory tree recursively, then feel free to reorganize your classes into a more logical directory structure.
Typehint everywhere. Use assertions for scalars.
function f(SomeClass $x, array $y, $z) {
assert(is_bool($z))
}
Output something other than HTML.
header('Content-type: text/xml'); // or text/css, application/pdf, or...
Learn to use exceptions. Write an error handler that converts errors into exceptions.
Replace your define() global constants with class constants.
Replace your Unix timestamps with a proper Date class.
In long functions, unset() variables when you're done with them.
Use with guilty pleasure:
Loop over an object's data members like an array. Feel guilty that they aren't declared private. This isn't some heathen language like Python or Lisp.
Use output buffers for assembling long strings.
ob_start();
echo "whatever\n";
debug_print_backtrace();
$s = ob_get_clean();
Avoid unless absolutely necessary, and probably not even then, unless you really hate maintenance programmers, and yourself:
Magic methods (__get, __set, __call)
extract()
Structured arrays -- use an object
My experience with PHP has taught me a few things. To name a few:
Always output errors. These are the first two lines of my typical project (in development mode):
ini_set('display_errors', '1');
error_reporting(E_ALL);
Never use automagic. Stuff like autoLoad may bite you in the future.
Always require dependent classes using require_once. That way you can be sure you'll have your dependencies straight.
Use if(isset($array[$key])) instead of if($array[$key]). The second will raise a warning if the key isn't defined.
When defining variables (even with for cycles) give them verbose names ($listIndex instead of $j)
Comment, comment, comment. If a particular snippet of code doesn't seem obvious, leave a comment. Later on you might need to review it and might not remember what it's purpose is.
Other than that, class, function and variable naming conventions are up to you and your team. Lately I've been using Zend Framework's naming conventions because they feel right to me.
Also, and when in development mode, I set an error handler that will output an error page at the slightest error (even warnings), giving me the full backtrace.
Fortunately, namespaces are in 5.3 and 6. I would highly recommend against using the Path_To_ClassName idiom. It makes messy code, and you can never change your library structure... ever.
The SPL's autoload is great. If you're organized, it can save you the typical 20-line block of includes and requires at the top of every file. You can also change things around in your code library, and as long as PHP can include from those directories, nothing breaks.
Make liberal use of === over ==. For instance:
if (array_search('needle',$array) == false) {
// it's not there, i think...
}
will give a false negative if 'needle' is at key zero. Instead:
if (array_search('needle',$array) === false) {
// it's not there!
}
will always be accurate.
See this question: Hidden Features of PHP. It has a lot of really useful PHP tips, the best of which have bubbled up to the top of the list.
There are a few things I do in PHP that tend to be PHP-specific.
Assemble strings with an array.
A lot of string manipulation is expensive in PHP, so I tend to write algorithms that reduce the discrete number of string manipulations I do. The classic example is building a string with a loop. Start with an array(), instead, and do array concatenation in the loop. Then implode() it at the end. (This also neatly solves the trailing-comma problem.)
Array constants are nifty for implementing named parameters to functions.
Enable NOTICE, and if you realy want to STRICT error reporting. It prevents a lot of errors and code smell: ini_set('display_errors', 1); error_reporting(E_ALL && $_STRICT);
Stay away from global variables
Keep as many functions as possible short. It reads easier, and is easy to maintain. Some people say that you should be able to see the whole function on your screen, or, at least, that the beginning and end curly brackets of loops and structures in the function should both be on your screen
Don't trust user input!
I've been developing with PHP (and MySQL) for the last 5 years. Most recently I started using a framework (Zend) with a solid javascript library (Dojo) and it's changed the way I work forever (in a good way, I think).
The thing that made me think of this was your first bullet: Zend framework does exactly this as it's standard way of accessing 'controllers' and 'actions'.
In terms of encapsulating and abstracting issues with different databases, Zend_Db this very well. Dojo does an excellent job of ironing out javascript inconsistencies between different browsers.
Overall, it's worth getting into good OOP techniques and using (and READING ABOUT!) frameworks has been a very hands-on way of getting to understand OOP issues.
For some standalone tools worth using, see also:
Smarty (template engine)
ADODB (database access abstraction)
Declare variables before using them!
Get to know the different types and the === operator, it's essential for some functions like strpos() and you'll start to use return false yourself.