How to enable notices on my development server - Not working - php

I'm referring to How to enable notices on my development server
I expect the following code shall give me some warning, when I execute it through, as my $a is not explicitly declared as array
php a.php
<?php
ini_set('display_errors', 1);
error_reporting(E_NOTICE);
$a['key'] = 123;
echo $a['key'] . "\n";
However, no warning message being printed. Is there anything I had missed?
The PHP I'm using is PHP 5.5.3. I'm not sure this matters?

I expect the following code shall give me some warning, when I execute it through, as my $a is not explicitly declared as array
Wrong... by writing $a['key'] = 123; you declare an array and set the key key to the integer number 123. That's a valid PHP array initialization. (The PHP version does not matter in this case.)
To explicitely produce an error notice for testing purposes…
If you want to provoke an error notice for testing purposes, you could add this line:
count($ThisIsNotDefinedOnPurpose);
which will produce an error notice saying
Notice: Undefined variable: ThisIsNotDefinedOnPurpose in … on line …

Related

Warn on undefined array write

Let's preface this with an example of a script with typo:
$bc = getBaseConcept();
$bs['key'] = doOtherStuff($bc['key']);
return $bc;
Obviously in the middle line is a typo. It should be $bc instead of $bs. (And yes this was a legit typo of mine just minutes ago before writing this question)
This did not produce a warning.
So my question is: Is there a configuration option that lets this produce a warning?
Specifically: Writing to an array key of a name that was previously undefined.
E_ALL does not seem to help. This should not only generate the warnings for $bar but I want also a warning for $foo.
<?php
ini_set('error_reporting', E_ALL);
echo ini_get('error_reporting'), "\n";
$foo['bar'] = $bar['foo'];
32767
PHP Warning: Undefined variable $bar in Standard input code on line 4
PHP Warning: Trying to access array offset on value of type null in Standard input code on line 4
Unfortunately, php is not like other programming languages. If an unknown variable is used, PHP does the initialisation without complaining. Unfortunately, there is nothing you can do about this.
If you are using an IDE like phpstorm or netbeans the IDE will usually show a hint for uninitisalized variables.
It is not necessary to initialize variables in PHP however it is a
very good practice. Uninitialized variables have a default value of
their type depending on the context in which they are used - booleans
default to false, integers and floats default to zero, strings (e.g.
used in echo) are set as an empty string and arrays become to an empty
array.
https://www.php.net/manual/en/language.variables.basics.php

Get all notices of PostgreSQL's RAISE NOTICE

I have big DB function which has multiple lines like this
RAISE NOTICE 'some step completed';
I want to get all this notices in my PHP application. I found only pg_last_notice() function which only returns the very last notice.
Is there any way I can get all notices?
Example:
DB function:
CREATE OR REPLACE FUNCTION do_smth()
RETURNS void AS
$BODY$
BEGIN
-- some actions
RAISE NOTICE 'Result of the actions:...';
-- some other actions
RAISE NOTICE 'Result of the other actions..';
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
PHP code:
<?php
// ...
$db->exec("SELECT do_smth()"); // executing DB function
$last_notice = pg_last_notice($db_connection);
// returns 'NOTICE: Result of the other actions..'
According to the libpq notice documentation "The default notice handling function prints the message on stderr, but the application can override this behavior by supplying its own handling function."
In your case the "application" (php itself) is overriding this behavior by specifying custom notice handler, called _php_pgsql_notice_handler:
Line #1367: PQsetNoticeProcessor(pgsql, _php_pgsql_notice_handler, (void*)Z_RESVAL_P(return_value));
That means that PostgreSQL notices are not propagated further into stderr, but are captured and processed by that handler.
In the handler itself (line #827) you can see that every time a notice is issued, php updates the variable holding it, and does not append the value to some array. Hence at the end only the last notice is present in that variable, obtainable by calling pg_last_notice().
So, it looks like it is not possible to obtain previous PostgreSQL notices from within PHP.
However, if you look further into the same notice handler, you would see that it is writing the notices to the error log, in case pgsql.ignore_notices = 0, pgsql.log_notices = 1 and E_NOTICE is included into the error_reporting. I guess with some php error handling functions juggling you will be able to obtain something.
pg_last_notice() now accepts an optional parameter to specify an operation.
This can be done with one of the following new constants:
PGSQL_NOTICE_LAST: to return last notice
PGSQL_NOTICE_ALL: to return all notices
PGSQL_NOTICE_CLEAR: to clear notices
More info for Changed Functions in version 7.1 HERE.

PHP doesn't give me error when I use a variable name without dollar sign

I am having the following code in a php web page:
if (bInserted) echo "abc";
I would expect PHP to give me a syntax error since I forget to add the dollar sign before the variable name. Howver, the page doesn't produce any errors. Instead, it even echoes the "abc" string. I am not really able to understand this.
Your bInserted is interpreted as a constant and, since is not defined (I presume), it is then treated as the string "bInserted", which evaluates to true hence your "abc" is printed.
Anyway, such implicit conversion from constant to string should raise a notice, see the manual.
If you use an undefined constant, PHP assumes that you mean the name
of the constant itself, just as if you called it as a string (CONSTANT
vs "CONSTANT"). An error of level E_NOTICE will be issued when this
happens.
If you really do not see any message, nor on screen nor in the logs, make sure you have set the correct error reporting level, you could for example try
ini_set('display_errors', 1);
error_reporting(E_ALL);
And, by the way, E_ALL is a defined constant in this case!

No E_NOTICE for undefined variables in array?

So.. I'm still confused by this, when creating an array with $array = array(); and then manually setting variables like:
<?php
$array[] = 1;
$array['type'] = 2;
$array['number'] = 3;
I know, this is OK for PHP to do, but then when I echo something like $array['none'] it won't show a E_NOTICE for undefined variables.
Can someone explain me, why?
It will. If you have turned on error reporting, it should display a warning similar to the one below:
Notice: Undefined index: none in /path/to/script.php line X.
To check, try the following:
<?php
ini_set('display_errors',1);
error_reporting(E_ALL);
$array = array();
echo $array['none'];
And, if you want to actually make sure they exist before trying to use them in your code, use isset():
if(isset($array['none'])) {
// do stuff ...
}
See it live!
All this is explained on the config doc page, too:
Enabling E_NOTICE during development has some benefits.
For debugging purposes: NOTICE messages will warn you about possible bugs in your code. For example, use of unassigned values is warned. It is extremely useful to find typos and to save time for debugging.
NOTICE messages will warn you about bad style. For example, $arr[item] is better to be written as $arr['item'] since PHP tries to treat "item" as constant. If it is not a constant, PHP assumes it is a string index for the array.
It's quite simple: When you access a key that doesn't exist, and assign it a new value, PHP will create that key, and add it to the list (or array). But when you try to access a non-existing key, and attempt to echo it's value, PHP won't crash, but it'll let you know that your code contains a possible bug:
$arr = array('foo' => 'bar');
echo $arr['fo'];
This issues a notice because my code may contain a typo. I may expect the key fo to exist, while clearly it doesn't, so I need to work on my code some more.
Another reason why this notice is issued is because lookups for non existing properties/keys are "slow". In order for PHP to know for a fact that the key doesn't exist, the entire array has to be scanned. That, too, is not ideal, though inevitable at times. If you have code that issues tons of E_NOTICE's, chances are that some simple if's, like:
if (!isset($arr['fo']))
{
$arr['fo'] = '';
}
echo $arr['fo'];
Will, though adding more code, effectively speed up your code. Not in the least because issueing notices isn't free (it's not that expensive, but not free either).
Other benefits:
Notices also let you know when you forgot to quote array keys, for example
echo $arr[foo];
echo $arr['foo'];
Initially, both will echo bar, but let's add 1 line of code to this:
define('foo', 'bar');
echo $arr[foo];
echo $arr['foo'];
This won't, because foo is now a constant, so $arr[foo] amounts to $arr['bar'];, which is an undefined index. Turning off notices, will just echo the string representation of NULL, which is an empty string.
Basically, notices help you. Use them, listen to them, and fix them. If your site is broken, fix it. If you get into the habbit of ignoring these notices, you'll probably set your ini files to a more "forgiving" setting, and grow lazy.
As time progresses, your code will become ever more messy/smelly, until such time you actually have a difficult to trace bug. You'll decide to turn your error reporting to E_STRICT | E_ALL, and won't be able to see the actual notice/warning that points out where your bug actually is, because your screen will be cluttered with E_NOTICE undefined index/variable...

How can I identify PHP unused variables (in Emacs)?

Is it somehow possible to identify unused variables in a PHP file in Emacs?
With other languages, this is possible by using tools such as Flymake.
I've already enabled Flymake to show syntax errors for my PHP files on the fly, but still it's frustrating that PHP logic errors are sometimes due to situations like:
<?php
$foo = whatever();
$bar = something($fo);
...
Note the typo on $foo that will contribute to the developer's headache and to his/her exorbitant use of coffee.
After the hints by Pascal and viam0Zah, I set this in my php.ini file:
error_reporting = E_ALL | E_STRICT
When I run php from the command line, I'm now able to see the notice about the undefined variable (with or without the -l option):
php -r '$foo = 3; echo $fo;'
PHP Notice: Undefined variable: fo in Command line code on line 1
php -r '$foo = 3; echo $fo;' -l
PHP Notice: Undefined variable: fo in Command line code on line 1
This is what I'm currently using in my .emacs file. It works perfectly fine with parse errors, but I'm still not able to match on the notices, though :(
;; Flymake for PHP
(require 'flymake)
(defun flymake-php-init ()
"Use php to check the syntax of the current file."
(let* ((temp (flymake-init-create-temp-buffer-copy 'flymake-create-temp-inplace))
(local (file-relative-name temp (file-name-directory buffer-file-name))))
(list "php" (list "-f" local "-l"))))
(add-to-list 'flymake-err-line-patterns
'("\\(Parse\\|Fatal\\) error: +\\(.*?\\) in \\(.*?\\) on line \\([0-9]+\\)$" 3 4 nil 2))
(add-to-list 'flymake-err-line-patterns
'("Notice: \\(.*\\) in \\(.*\\) on line \\([0-9]+\\)" 2 3 nil 1))
(add-to-list 'flymake-allowed-file-name-masks '("\\.php$" flymake-php-init))
I've also tried Gabor's configuration, but with the same result. It is fine with errors, but bad with notices.
Please note that from the command line, parse errors look like:
php -r '$fo o = 3; echo $fo;' -l
PHP Parse error: syntax error, unexpected T_STRING in Command line code on line 1
I don't get why Notices are not matched. I've tried the regular expression separately and it seems to match correctly:
(search-forward-regexp "Notice: \\(.*\\) in \\(.*\\) on line \\([0-9]+\\)")
PHP Notice: Undefined variable: fo in Command line code on line 1
(C-x C-e will jump to the end of the lines).
Finally, I disabled Xdebug for now, since the notices were originally reported as:
PHP Notice: Undefined variable: fo in Command line code on line 1
PHP Stack trace:
PHP 1. {main}() Command line code:0
So, I guess I should slightly change the regexp to match the multiline errors. Any hint about this?
It's not really an answer to your question, as it's not working in Emacs, but PHP can raise notices, when you are trying to read from a variable that's not been initialized.
For more informations, see:
error_reporting, which should include E_NOTICE
display_errors to have those notices (and other errors) displayed
which is useful when developing,
but it should not be enabled on a production server.
For example, with error_reporting set to report E_NOTICE (and others), the following portion of code:
$aa = 'glop';
echo strlen($a);
Raises this notice:
Notice: Undefined variable: a in /.../temp/temp.php on line 5
It's not as simple as getting it in your editor, I admit -- but it will still help finding out why something doesn't work ;-)
Since Flymake uses the php binary's syntax check option (-l) for highlighting parse errors, there is no obvious way to catch notices and other errors without running or lexical parsing the code. If it's not a problem to not only lint but execute your script, then you can do the following.
Unfortunately, flymake-php defines error line patterns as constant (at least in the bundle shipped with Emacs Starter Kit), and even the flymake command is hard-coded. There is a few ways to achieve our goal and each is a pain. May be it's a quick and not so dirty solution to define our flymake-php-init function based on the original one.
(defun my-flymake-php-init ()
;; add a new error pattern to catch notices
(add-to-list 'flymake-err-line-patterns
'("\\(Notice\\): \\(.*\\) in \\(.*\\) on line \\([0-9]+\\)"
3 4 nil 2))
(let* ((temp-file (flymake-init-create-temp-buffer-copy
'flymake-create-temp-inplace))
(local-file (file-relative-name
temp-file
(file-name-directory buffer-file-name))))
;; here we removed the "-l" switch
(list "php" (list "-f" local-file))))
Then customize flymake-allowed-php-file-name-masks to use my-flymake-php-init function for initializing flymake-php instead of the original one. And so it works:
(source: flickr.com)
Decent IDE's will give you the names of the variables in the current scope when you are typing them via Intellisense.
This should severely cut down on the number of times you misspell a variable name. It also allows your variable names to be more descriptive than $foo
Furthermore, you should always pay attention to undefined variable warnings, as they immediately tell you when you have made a misspelling.

Categories