In PHP, depending on your error reporting level, if you don't define a constant and then call it like so:
<?= MESSAGE ?>
It may print the name of the constant instead of the value!
So, I wrote the following function to get around this problem, but I wanted to know if you know a way to do it in faster code? I mean, when I did a speed test without this function, I can define and dump 500 constants in .0073 seconds. But use this function below, and this switches to anywhere from .0159 to .0238 seconds. So, it would be great to get the microseconds down to as small as possible. And why? Because I want to use this for templating. I'm thinking there simply has to be a better way than toggling the error reporting with every variable I want to display.
function C($constant) {
$nPrev1 = error_reporting(E_ALL);
$sPrev2 = ini_set('display_errors', '0');
$sTest = defined($constant) ? 'defined' : 'not defined';
$oTest = (object) error_get_last();
error_reporting($nPrev1);
ini_set('display_errors', $sPrev2);
if (strpos($oTest->message, 'undefined constant')>0) {
return '';
} else {
return $constant;
}
}
<?= C(MESSAGE) ?>
As long as you don't mind using quotes on your constants, you can do this:
function C($constant) {
return defined($constant) ? constant($constant) : 'Undefined';
}
echo C('MESSAGE') . '<br />';
define('MESSAGE', 'test');
echo C('MESSAGE') . '<br />';
Output:
Undefined
test
Otherwise, there's no way around it without catching the notice thrown by using an undefined constant.
try
if (isset(constant($constant)) ...
This shouldn't trigger any E_NOTICE messages, so you don't have to set and reset error_reporting.
Related
I am trying to write a function to avoid getting variable undefined error. Right now, i have a code like this:
function check($str){
if(isset($str)){
$s = $str;
} else {
$s = "";
}
}
check($_GET['var']);
The get var is not set. I am getting a variable undefined error on my screen. How do i alter my function to not throw this error and just return "" if it is not set? I don't want to have to code 100 if statements to avoid getting variable undefined. Thanks.
We already have in PHP a construct to check that. It is called isset(). With it you can check whether a variable exists. If you would like to create it with some default values if it doesn't exist yet, we also have syntax for it. It's null-coalescing operator.
$_GET['var'] = $_GET['var'] ?? '';
// or since PHP 7.4
$_GET['var'] ??= '';
Although I'm not sure if it is the right way of doing it, for the sake of providing an answer you can pass the variable by reference, this allows you to get away with passing undefined variables and check if it is set inside the function..
function check(&$str){
if(!isset($str)){
$str = "not set";
}
}
check($_GET['var']);
echo $_GET['var'];
I have the following code in PHP
if (is_numeric($args['myargs']['custom_value'])) {
echo 'Yes';
} else {
echo 'No';
}
It runs correctly, but if custom_value is not set then I get the warning in my logs..
PHP Notice: Undefined index: custom_value
I think this is just a notice and not an error so can be safely ignored? Is it bad practice to do it like this?
to avoid the warning you should do something like this
if(isset($args['myargs']['custom_value'])) {
if (is_numeric($args['myargs']['custom_value'])) {
echo 'Yes';
} else {
echo 'No';
}
}
What's happening
PHP sees you are trying to use an array element that is not set, so it helpfully warns you about it. It's not serious in this case, but you want to learn to avoid the messages.
The solution
The function isset will test if the array key is defined.
//You must first of all test isset and then is_numeric,
// else you still get the error. Research 'short circuiting' in php
if ( isset($args['myargs']['custom_value']) && is_numeric($args['myargs']['custom_value'])) {
echo 'Yes';
} else {
echo 'No';
}
This solution will also print "No" if the array key was never defined.
alse you can
error_reporting(0)
in php file beginning
I want to set a PHP variable: $custom, that will be used whenever it is defined.
But I want the output of this variable to be dependant of another variable: $v index, which is used inside while, which gets defined only during the while statement.
I don't know if it's possible to do, right now I have the following code, and for the way I defined $custom[3], it doesn't work.
Only $custom[1] and $custom[2] varibables will work, but they take into account only constant values or variable whose values were already set, so this isn't helpful.
Code:
<?php
$product[1]["price"]=10;
$product[2]["price"]=50;
$product[3]["price"]=70;
$custom[1] = 'Static HTML Block';
$custom[2] = 'Past Variable: '. $product[2]["price"] .'';
$custom[3] = 'Future Variable: '. $product[$v]["price"] .''; // I want this kind of definitoin
?>
<HTML>
// the following part will be used within an include, and shouldn't be modified ///
<?php
$v = 1;
while ($z <= 5) {
?>
<?= $custom[$v] ? $custom[$v] : '$' . $product[$v]["price"] ?>
<?php
$v = $v + 1;
$z = $z + 1;
}
?>
So basically, I want that on the third run (when v=3), that Future Variable: 70 will be the output.
The Rationale:
I want to use the latter code as a constant Include, that will serve as a template for all files. but on occasion, a certain file may require special changes that also require PHP code modification, so I will want to perform them within such specific file, that will affect the original include.
Edit 2:
More Simple example:
<?php
$product[1]["price"]=10;
$product[2]["price"]=50;
$custom[1] = 'I dont modify the PHP code';
$custom[2] = 'I DO mofiy the latter PHP code: '. $product[$v]["price"] .'';
?>
<HTML>
// the following part will be used within an include, and shouldn't be modified ///
<?php $v = 1; while ($v <= 5) { ?>
<?= $custom[$v] ?>
<p>
<?php $v = $v + 1; } ?>
// Expected Output:
//I dont modify the PHP code
//I DO mofiy the latter PHP code: 50
It's a little difficult to tell what you are trying to do, but I think you need to decouple your data from your presentation:
$product[1]['price']=10;
$product[2]['price']=50;
$product[3]['price']=70;
$custom[1] = 'Static HTML Block';
$custom[2] = 'Past Variable: %s';
$custom[3] = 'Future Variable: %s';
$v = 1;
while($z <= 5) {
$price = $product[ $v ]['price'];
printf($custom[ $v ], $price);
$v++;
$z++;
}
In this case, $custom stores the format, but doesn't actually contain the data. You call printf to output the desired format with whatever data you want to pass.
It's not clear to me what you're trying to accomplish, but if I had to guess, you want something known as templates (e.g. Twig), and your question might possibly be a XY problem. If you supply more context maybe someone might be able to help you further.
As to the matter at hand, you cannot define $custom[3] here since $v is not defined yet:
$custom[3] = 'Future Variable: '. $product[$v]["price"] .''; // I want this kind of definitoin
The closest you can get is to use eval (which is rarely recommended), or define a closure, even if it's awkward. Instead of a variable, you define a function:
$custom[3] = function($productData) {
return 'Future Variable: '. $productData["price"] .'';
}
The above you can do in an included file.
Then in the loop you check whether the custom object is a function, and if so, you call it and assign the return value to the reply.
The code below stays the same whatever the include - actually, it even works with the data you have now. Of course, it has to be a little more complicated.
while ($z <= 5) {
// If the $v-th item is customised
if (array_key_exists($v, $custom)) {
// Verify what it is
if (is_callable($custom[$v])) {
// if it's a function, call it.
$reply = $custom[$v]($product);
} else {
$reply = $custom[$v];
}
} else {
// Not customised, just print the price.
$reply = '$' . $product[$v]["price"];
}
print $reply;
Another more "templateish" solution is to define strings and then process them using e.g. preg_replace_callback in order to generate the desired HTML. In this case, too, you need to pass to the templater a fixed variable, such as $product[$v]. You need some kind of 'language' to indicate where you want elements of this fixed variables to be instantiated. Usually, square brackets or curly brackets, often doubled, are used:
$custom[3] = 'Future Variable: {{price}}';
At resolution time, preg_replace_callback may be made to replace {{price}} with the value in $product[$v]['price'], and so on (e.g. {{weight}}, {{description}}...).
(You can also do this server side and populate the HTML page via AJAX using client-side libraries such as Handlebars).
The quick and nasty way to make your own template is to create an array of keys => values and pass it to the where loops as your $custom variable.
While you're in the where(){} loop, use the php function extract to convert the array into $key = 'value' pairs. This is very similar to list without having having to define each variable manually.
http://php.net/manual/en/function.extract.php
Eg.
$data = [
'foo' => 'bar',
];
extract($data);
print $foo; // output: bar
Then after you extract, include your file. Make sure that you wrap this in output buffering mode ob_start() and put it in a function so your local variables can't be overriden.
This is how you make homebrew templating languages.
So I constantly write stuff like
if (!empty($someLongVar['nestedArrayKey'])) echo $someLongVar['nestedArrayKey'];
or
<?= !empty($someLongVar['nestedArrayKey']) ? $someLongVar['nestedArrayKey'] : "" ?>
I feel this is a waste of valuable programmer time. So is there some kind of shorthand for this that I'm missing? A function like
echoIf($someLongVar['nestedArrayKey'])
would save a lot of space and typing for thousands of programmers out there.
It seems impossible to write such a function myself because PHP throws a warning everytime i reference a nonexistant variable.
You can suppress the warnings with the # operator.
function echoIf($variable) {
if(!empty($variable))
echo $variable;
}
echoIf(#$myVariable['test']);
function ifVar($var) {
if(isset($var)) if(!empty($var)) echo $var."\n";
}
When passing a non-existent value by reference, PHP creates the value and sets it to NULL. I noticed it when memory increases were occurring while checking empty values in some functions. Take the following function:
function v(&$v,$d=NULL){return isset($v)?$v:$d;}
$bar = v($foo, $default);
This would be shorthand for:
if(isset($foo))
{
$bar = $foo;
}
else
{
$bar = $default;
}
However, when passing non-existent variables PHP creates them. In the case of variables - they are removed as soon as the method/function ends - but for checking super global arrays like $_GET or $_POST the array element is never removed causing extra memory usage.
$request_with = v($_SERVER['HTTP_X_REQUESTED_WITH']);
Can anyone explain why this happens and if it is a PHP todo fix or a feature for some other crazy use of values?
XeonCross' function v is a shorthand for the often used:
$val= isset($arr['elm']) ? $arr['elm'] : 'default'
to avoid the dreaded 'Undefined index: elm' notice. A nice helper function would be:
function ifset(&$v1, $v2 = null) {
return isset($v1) ? $v1 : $v2;
}
as Xeoncross suggested, so you could write the much nicer
$val = ifset($arr['elm'],'default')
however, this has a lot of interesting (?) quirks in our beloved "language" that we call PHP:
inside the function ifset, $v1 seems UNSET, so it correctly returns the value $v2 and you might conclude that ifset works ok. But afterwards $arr['elm'] is silently set to NULL. So consider the following:
function wtf(&$v) {
if (isset($v))
echo "It is set";
else
echo "It is NOT set";
}
$p=[];
wtf($p['notexist']); => It is NOT set
$p; => [ 'notexist' => NULL ]
But this is another delusion, as the isset() function returns false for NULL values as well:
$x=NULL;
isset($x) => false... huh??
Did we expect this? well.. it is in the documentation, so this is by design as well. Welcome to the wonderful world of php.
The reason you have the memory leak, is because you're telling it to.
When you ask for a reference parameter, PHP will provide you with one. When you are calling a function with an unset variable, PHP will set the variable and then pass the reference to that new variable. When you call it with a superglobal, it creates the missing index. That's because you told it to.
However, I must ask why specifically do you need variable references? 99.9% of the time you don't really need them. I suspect that it'll work just fine to do:
function v($v, $d = null) { return isset($v) ? $v : $d; }
Or, if you really must use references (which you can't get around your original problem with), you should also return a reference:
function &v(&$v, $d = null) {
if (isset($v)) {
return $v;
}
return $d;
}
Otherwise it's pointless to take a reference and not return one...