WordPress and Suppressed Errors

One of the errors found by the Error Reporting plugin was an E_WARNING thrown by the constant() function. Upon investigation, it was discovered that the core file had the function call prefixed with the "@" error control operator. The log file also contained a few database function errors. The corresponding lines for those were found to have the error control operator prefixed to the calls as well.

Curious, I decided to see just how often error suppression was used in WordPress core files. After what proved to be a tedious undertaking, the error control operator was found in 53 files, including 26 under the wp-admin folder, and occurred anywhere from only once up to 146 times per file. No doubt, as the search was not thorough, some were not found.

What does the PHP documentation have to say? From Error Control Operators:

Warning
Currently the "@" error-control operator prefix will even disable error reporting for critical errors that will terminate script execution. Among other things, this means that if you use "@" to suppress errors from a certain function and either it isn't available or has been mistyped, the script will die right there with no indication as to why.

I imagine that if any of the core files caused such an event, there would be a large number of "I get a blank screen" complaints almost as soon as a version was released. Still, the number of variables, objects, PHP functions and WordPress functions is quite extensive.

I agree that it is better to suppress errors than to show them in a live blog. They would only confuse most visitors, and there's no need to help the script kiddies. And I also agree that although it might be preferrable to deal with errors in a better fashion, it is not always possible, especially as WordPress still supports PHP version 4. Yet, I can't help but think that in some cases at least, the code could be written differently without the need to suppress an error. I also have mixed feelings about the use of them in files under the wp-admin folder. On the one hand, presumably only an authorized admin would see them, and could benefit from seeing them, if and when they happened. On the other hand, every level of security, even by obscurity, is a good thing.

@$_GET['attachment_id']
@$_GET['m']
@$_GET['p']
@$_GET['page_id']
@$_POST['_page']
@$_POST['_per_page']
@$_POST['_total']
@$_POST['_url']
@$call['class']
@$datefunc
@$desc
@$fd
@$kellogs
@$mail
@$phpmailer->Send
@$widgets['dashboard_incoming_links']
@$widgets['dashboard_secondary']
@chdir
@chgrp
@chmod
@chown
@closedir
@constant
@copy
@count
@crc32
@date_default_timezone_set
@define
@dir
@dl
@each
@error_log
@exif_read_data
@extract
@fclose
@fetch_feed
@fflush
@fgets
@file
@file_exists
@file_get_contents
@fileatime
@filegroup
@filemtime
@fileowner
@fileperms
@filesize
@fopen
@fputs
@fread
@fseek
@fsockopen
@ftell
@ftp_chdir
@ftp_chmod
@ftp_connect
@ftp_delete
@ftp_fget
@ftp_fput
@ftp_login
@ftp_pasv
@ftp_pwd
@ftp_rawlist
@ftp_rmdir
@ftp_site
@ftp_ssl_connect
@func_get_arg
@func_num_args
@fwrite
@get_magic_quotes_runtime
@getcwd
@gethostbyaddr
@gethostbyname
@getimagesize
@gzclose
@gzdeflate
@gzinflate
@gzopen
@gzputs
@gzread
@gzwrite
@header
@html_entity_decode
@htmlspecialchars
@http_chunked_decode
@http_request
@iconv
@include
@include_once
@ini_get
@ini_set
@is_dir
@is_file
@is_link
@is_readable
@is_uploaded_file
@is_writable
@isset
@mb_convert_encoding
@mb_internal_encoding
@mkdir
@mktime
@move_uploaded_file
@mysql_connect
@mysql_fetch_field
@mysql_fetch_object
@mysql_free_result
@mysql_num_fields
@mysql_query
@mysql_select_db
@ob_end_flush
@opendir
@openssl_pkcs7_sign
@parse_url
@preg_match
@readdir
@rename
@rewind
@rmdir
@set_magic_quotes_runtime
@set_time_limit
@socket_bind
@socket_close
@socket_connect
@socket_create
@socket_getsockname
@socket_listen
@socket_read
@socket_set_option
@socket_write
@ssh2_auth_password
@ssh2_auth_pubkey_file
@ssh2_connect
@ssh2_sftp_rename
@stat
@stream_set_timeout
@strpos
@substr
@touch
@unlink
@unpack
@unserialize
@vsprintf
@wp_mail
@wp_read_image_metadata
@xml_parser_create
Technorati Tags: ,

is_a Conclusion

Errors:

For the majority of WordPress users, the use of is_a in the core files is of little concern. The E_STRICT errors, in PHP versions >= 5.0 < 5.3 only, can be safely ignored and are not a problem if error reporting does not include them.

Performance:

For those that have PHP versions >= 5.0 and desire a slight improvement in performance, changing the code to use the instanceof operator, at least in the wp-includes/classes.php file, may be worth the effort. In my crude tests is_a ran in .000023 seconds and instanceof in .0000082 seconds. As the is_wp_error() function is called hundreds of times per page load, this one edit will amount to a saving of roughly .0074 seconds per page load.

Readability:

The use of either is_a or instanceof in conditional tests is readable and it is easy to comprehend the intent. My use of get_class and is_subclass_of, although supported in all versions of PHP, not so much.

Maintainability:

Considering how often new versions of WordPress are released — 2 more in the short time since this series of posts began — making 38 edits in 15 files just to replace the use of is_a with something else could become a chore.

To summarize, several things need to be considered before making any edits to the WordPress core files:

  • Are the E_STRICT errors important?
  • What version of PHP is the server running?
  • How important is performance?
  • How important is code readability?
  • How important is maintainability?
Technique	PHP	Speed	Errors		Readability

is_a		4,5	slow	Strict*		simple
instanceof	5	fast	$var fix**	simple
get_class
is_subclass_of	4,5	mid***	$var fix**	complex

* is_a is only an E_STRICT error for PHP versions >= 5.0 < 5.3 ** Both instanceof and is_subclass_of can cause fatal errors in PHP versions 5.0 < 5.1 unless a work-around is used, in my examples, by using a variable to hold the class name. *** When get_class alone is enough, the conditional approximates the speed of instanceof, but when PHP must test for is_subclass_of the speed is closer to, but a bit faster than, that of is_a

Choices for is a:

is_a($object, 'WP_Class')

( $object instanceof WP_Class )

$class_name = 'WP_Class';
( $object instanceof $class_name )

( ( get_class($object) == 'WP_Class' )
	 || is_subclass_of($object, 'WP_Class') )

$class_name = 'WP_Class';
( ( get_class($object) == 'WP_Class' )
	 || is_subclass_of($object, $class_name) )

Choices for Not is a:

!is_a($object, 'WP_Class')

!( $object instanceof WP_Class )

$class_name = 'WP_Class';
!( $object instanceof $class_name )

( ( get_class($object) != 'WP_Class' )
	 && !is_subclass_of($object, 'WP_Class') )

$class_name = 'WP_Class';
( ( get_class($object) != 'WP_Class' )
	 && !is_subclass_of($object, $class_name) )

WordPress core files containing is_a

Technorati Tags: ,

wp-admin includes template.php

This file causes two is_a E_STRICT errors.

function wp_category_checklist( $post_id = 0, $descendants_and_self = 0, $selected_cats = false, $popular_cats = false, $walker = null ) {
.....
//	if ( empty($walker) || !is_a($walker, 'Walker') )
	$class_name = 'Walker';
	if ( empty($walker)
	 || ( ( get_class($walker) != $class_name )
	 && !is_subclass_of($walker, $class_name) ) )
.....
function user_row( $user_object, $style = '', $role = '' ) {
.....
//	if ( !( is_object( $user_object) && is_a( $user_object, 'WP_User' ) ) )
	$class_name = 'WP_User';
	if ( !( is_object( $user_object)
	 && ( ( get_class($user_object) == $class_name )
	 || is_subclass_of($user_object, $class_name) ) ) )
Technorati Tags: ,

wp-includes Text Diff Renderer.php

One is_a

class Text_Diff_Renderer {
.....
	function render($diff)
.....
//		if (is_a($edit, 'Text_Diff_Op_copy')) {
		$class_name = 'Text_Diff_Op_copy';
		if ( ( get_class($edit) == $class_name )
		 || is_subclass_of($edit, $class_name) ) {
Technorati Tags: ,

wp-includes Text Diff.php

The Text_Diff class has a not is_a and an is_a

class Text_Diff {
.....
	function isEmpty()
.....
//		if (!is_a($edit, 'Text_Diff_Op_copy')) {
		$class_name = 'Text_Diff_Op_copy';
		if ( ( get_class($edit) != $class_name )
		 && !is_subclass_of($edit, $class_name) ) {
.....
	function lcs()
.....
//		if (is_a($edit, 'Text_Diff_Op_copy')) {
		$class_name = 'Text_Diff_Op_copy';
		if ( ( get_class($edit) == $class_name )
		 || is_subclass_of($edit, $class_name) ) {
Technorati Tags: ,