Pastakhov has uploaded a new change for review.
https://gerrit.wikimedia.org/r/154991
Change subject: fix class ErrorHandler for HHVM (v 3.4.3)
......................................................................
fix class ErrorHandler for HHVM (v 3.4.3)
It is a partial solution to the bug 69014
* add private static function ErrorHandler::onPhpError();
* add private static function ErrorHandler::onHhvmError();
* add const PhpTagsException::WARNING_TOO_MANY_ARGUMENTS;
* add const PhpTagsException::FATAL_UNEXPECTED_OBJECT_TYPE;
Change-Id: Ib423619a8116f36a15ee747ca2074cd827e650f6
---
M PhpTags.php
M includes/ErrorHandler.php
M includes/PhpTagsException.php
M includes/Runtime.php
A tests/phpunit/includes/!!!firstInit_Test.php
M tests/phpunit/includes/RuntimeTest.php
6 files changed, 149 insertions(+), 26 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/PhpTags
refs/changes/91/154991/1
diff --git a/PhpTags.php b/PhpTags.php
index 9ad9228..00c413e 100644
--- a/PhpTags.php
+++ b/PhpTags.php
@@ -15,13 +15,13 @@
die( 'This file is an extension to MediaWiki and thus not a valid entry
point.' );
}
-define( 'PHPTAGS_MAJOR_VERSION', 3 );
-define( 'PHPTAGS_MINOR_VERSION', 4 );
-define( 'PHPTAGS_RELEASE_VERSION', 2 );
+const PHPTAGS_MAJOR_VERSION = 3;
+const PHPTAGS_MINOR_VERSION = 4;
+const PHPTAGS_RELEASE_VERSION = 3;
define( 'PHPTAGS_VERSION', PHPTAGS_MAJOR_VERSION . '.' . PHPTAGS_MINOR_VERSION
. '.' . PHPTAGS_RELEASE_VERSION );
-define( 'PHPTAGS_HOOK_RELEASE', 5 );
-define( 'PHPTAGS_RUNTIME_RELEASE', 1 );
+const PHPTAGS_HOOK_RELEASE = 5;
+const PHPTAGS_RUNTIME_RELEASE = 1;
// Register this extension on Special:Version
$wgExtensionCredits['parserhook'][] = array(
diff --git a/includes/ErrorHandler.php b/includes/ErrorHandler.php
index 88e1b52..84f9a47 100644
--- a/includes/ErrorHandler.php
+++ b/includes/ErrorHandler.php
@@ -8,22 +8,35 @@
*/
class ErrorHandler {
- public static function onError( $errno, $errstr, $errfile, $errline,
$object ) {
+ public static function onError( $errno, $errstr, $errfile, $errline,
$errcontext, $object = false ) {
+ if ( $object === false ) {
+ self::$oldErrorHandler = null;
+ $return = self::onPhpError( $errno, $errstr, $errfile,
$errline, $errcontext );
+ } else {
+ $return = self::onHhvmError( $errno, $errstr, $errfile,
$errline, $object );
+ }
+ if ( false === $return && self::$oldErrorHandler !== null ) {
+ $return = call_user_func_array( self::$oldErrorHandler,
func_get_args() );
+ }
+ return $return;
+ }
+
+ private static function onPhpError( $errno, $errstr, $errfile,
$errline, $object) {
$backtrace = debug_backtrace();
$matches = null;
- if ( true === isset($backtrace[0]['file']) && strpos(
$backtrace[0]['file'], 'PhpTags/includes/Runtime.php' ) !== false ) {
+ if ( true === isset($backtrace[1]['file']) && strpos(
$backtrace[1]['file'], 'PhpTags/includes/Runtime.php' ) !== false ) {
return self::onRuntimeError( $errno, $errstr, $errfile,
$errline, $object );
}
if ( strpos( $errstr, 'expects parameter' ) !== false ) {
if (
- false === isset($backtrace[1]['file'])
&&
- $backtrace[2]['function'] ==
"call_user_func_array" &&
- isset($backtrace[3]['class']) &&
is_subclass_of( $backtrace[3]['class'], 'PhpTags\\GenericFunction') &&
+ false === isset($backtrace[2]['file'])
&&
+ $backtrace[3]['function'] ==
"call_user_func_array" &&
+ isset($backtrace[4]['class']) &&
is_subclass_of( $backtrace[4]['class'], 'PhpTags\\GenericFunction') &&
preg_match( '/expects parameter (\\d+)
to be (\\w+), (\\w+) given/', $errstr, $matches )
)
{
- $function = substr( $backtrace[3]['function']
== '__callStatic' ? $backtrace[3]['args'][0] : $backtrace[3]['function'], 2 );
+ $function = substr( $backtrace[4]['function']
== '__callStatic' ? $backtrace[4]['args'][0] : $backtrace[4]['function'], 2 );
Runtime::$transit[PHPTAGS_TRANSIT_EXCEPTION][]
= new PhpTagsException(
PhpTagsException::WARNING_EXPECTS_PARAMETER,
array( $function, $matches[1],
$matches[2], $matches[3])
@@ -32,13 +45,13 @@
}
} elseif( strpos( $errstr, 'expects exactly' ) !== false ) {
if (
- false === isset($backtrace[1]['file'])
&&
- $backtrace[2]['function'] ==
"call_user_func_array" &&
- isset($backtrace[3]['class']) &&
is_subclass_of( $backtrace[3]['class'], 'PhpTags\\GenericFunction') &&
+ false === isset($backtrace[2]['file'])
&&
+ $backtrace[3]['function'] ==
"call_user_func_array" &&
+ isset($backtrace[4]['class']) &&
is_subclass_of( $backtrace[4]['class'], 'PhpTags\\GenericFunction') &&
preg_match( '/expects exactly (\\d+)
(parameter[s]?), (\\d+) given/', $errstr, $matches )
)
{
- $function = substr( $backtrace[3]['function']
== '__callStatic' ? $backtrace[3]['args'][0] : $backtrace[3]['function'], 2 );
+ $function = substr( $backtrace[4]['function']
== '__callStatic' ? $backtrace[4]['args'][0] : $backtrace[4]['function'], 2 );
Runtime::$transit[PHPTAGS_TRANSIT_EXCEPTION][]
= new PhpTagsException(
$matches[2] == 'parameter' ?
PhpTagsException::WARNING_EXPECTS_EXACTLY_PARAMETER :
PhpTagsException::WARNING_EXPECTS_EXACTLY_PARAMETERS,
array( $function, $matches[1],
$matches[3] )
@@ -47,13 +60,13 @@
}
} elseif( strpos( $errstr, 'expects at least' ) !== false ) {
if (
- false === isset($backtrace[1]['file'])
&&
- $backtrace[2]['function'] ==
"call_user_func_array" &&
- isset($backtrace[3]['class']) &&
is_subclass_of( $backtrace[3]['class'], 'PhpTags\\GenericFunction') &&
+ false === isset($backtrace[2]['file'])
&&
+ $backtrace[3]['function'] ==
"call_user_func_array" &&
+ isset($backtrace[4]['class']) &&
is_subclass_of( $backtrace[4]['class'], 'PhpTags\\GenericFunction') &&
preg_match( '/expects at least (\\d+)
(parameter[s]?), (\\d+) given/', $errstr, $matches )
)
{
- $function = substr( $backtrace[3]['function']
== '__callStatic' ? $backtrace[3]['args'][0] : $backtrace[3]['function'], 2 );
+ $function = substr( $backtrace[4]['function']
== '__callStatic' ? $backtrace[4]['args'][0] : $backtrace[4]['function'], 2 );
Runtime::$transit[PHPTAGS_TRANSIT_EXCEPTION][]
= new PhpTagsException(
$matches[2] == 'parameter' ?
PhpTagsException::WARNING_EXPECTS_AT_LEAST_PARAMETER :
PhpTagsException::WARNING_EXPECTS_AT_LEAST_PARAMETERS,
array( $function, $matches[1],
$matches[3] )
@@ -62,9 +75,9 @@
}
} elseif( strpos( $errstr, 'could not be converted' ) !== false
) {
if (
- false === isset($backtrace[1]['file'])
&&
- $backtrace[2]['function'] ==
"call_user_func_array" &&
- isset($backtrace[3]['class']) &&
is_subclass_of( $backtrace[3]['class'], 'PhpTags\\GenericFunction') &&
+ false === isset($backtrace[2]['file'])
&&
+ $backtrace[3]['function'] ==
"call_user_func_array" &&
+ isset($backtrace[4]['class']) &&
is_subclass_of( $backtrace[4]['class'], 'PhpTags\\GenericFunction') &&
preg_match( '/^Object of class
([\\w:\\\\]+) could not be converted to (\\w+).*?/', $errstr, $matches )
)
{
@@ -108,4 +121,101 @@
return true;
}
+ private static function onHhvmError( $errno, $errstr, $errfile,
$errline, $object) {
+ $backtrace = debug_backtrace();
+ $matches = null;
+ if ( false !== strpos( $errfile, 'PhpTags/includes/Runtime.php'
) ) {
+ if ( strpos( $errstr, 'Division by zero' ) !== false ) {
+ Runtime::$transit[PHPTAGS_TRANSIT_EXCEPTION][]
= new PhpTagsException( PhpTagsException::WARNING_DIVISION_BY_ZERO, null );
+ return true;
+ }
+ $matches = null;
+ if ( preg_match('/^Object of class ([\\w:\\\\]+) could
not be converted to (\\w+).*?/', $errstr, $matches) ) {
+ Runtime::$transit[PHPTAGS_TRANSIT_EXCEPTION][]
= new PhpTagsException( PhpTagsException::NOTICE_OBJECT_CONVERTED,
array($matches[1], $matches[2]) );
+ return true;
+ }
+ }
+
+ if ( strpos( $errstr, 'expects parameter' ) !== false ) {
+ if (
+ isset($backtrace[3]['class']) &&
is_subclass_of( $backtrace[3]['class'], 'PhpTags\\GenericFunction') &&
+ preg_match( '/expects parameter (\\d+)
to be (\\w+), (\\w+) given/', $errstr, $matches )
+ )
+ {
+ $function = substr( $backtrace[3]['function']
== '__callStatic' ? $backtrace[3]['args'][0] : $backtrace[3]['function'], 2 );
+ Runtime::$transit[PHPTAGS_TRANSIT_EXCEPTION][]
= new PhpTagsException(
+
PhpTagsException::WARNING_EXPECTS_PARAMETER,
+ array( $function, $matches[1],
$matches[2], $matches[3])
+ );
+ return true;
+ }
+ } elseif( strpos( $errstr, 'expects exactly' ) !== false ) {
+ if (
+ isset($backtrace[3]['class']) &&
is_subclass_of( $backtrace[3]['class'], 'PhpTags\\GenericFunction') &&
+ preg_match( '/expects exactly (\\d+)
(parameter[s]?), (\\d+) given/', $errstr, $matches )
+ )
+ {
+ $function = substr( $backtrace[3]['function']
== '__callStatic' ? $backtrace[3]['args'][0] : $backtrace[3]['function'], 2 );
+ Runtime::$transit[PHPTAGS_TRANSIT_EXCEPTION][]
= new PhpTagsException(
+ $matches[2] == 'parameter' ?
PhpTagsException::WARNING_EXPECTS_EXACTLY_PARAMETER :
PhpTagsException::WARNING_EXPECTS_EXACTLY_PARAMETERS,
+ array( $function, $matches[1],
$matches[3] )
+ );
+ return true;
+ }
+ } elseif( strpos( $errstr, 'expects at least' ) !== false ) {
+ if (
+ isset($backtrace[3]['class']) &&
is_subclass_of( $backtrace[3]['class'], 'PhpTags\\GenericFunction') &&
+ preg_match( '/expects at least (\\d+)
(parameter[s]?), (\\d+) given/', $errstr, $matches )
+ )
+ {
+ $function = substr( $backtrace[3]['function']
== '__callStatic' ? $backtrace[3]['args'][0] : $backtrace[3]['function'], 2 );
+ Runtime::$transit[PHPTAGS_TRANSIT_EXCEPTION][]
= new PhpTagsException(
+ $matches[2] == 'parameter' ?
PhpTagsException::WARNING_EXPECTS_AT_LEAST_PARAMETER :
PhpTagsException::WARNING_EXPECTS_AT_LEAST_PARAMETERS,
+ array( $function, $matches[1],
$matches[3] )
+ );
+ return true;
+ }
+ } elseif( strpos( $errstr, 'Too many arguments for' ) !== false
) { // Too many arguments for date_format(), expected 2
+ if (
+ isset($backtrace[3]['class']) &&
is_subclass_of( $backtrace[3]['class'], 'PhpTags\\GenericFunction') &&
+ preg_match( '/Too many arguments for
\\w+\(\), expected (\\d+)/', $errstr, $matches )
+ )
+ {
+ $function = substr( $backtrace[3]['function']
== '__callStatic' ? $backtrace[3]['args'][0] : $backtrace[3]['function'], 2 );
+ Runtime::$transit[PHPTAGS_TRANSIT_EXCEPTION][]
= new PhpTagsException( PhpTagsException::WARNING_TOO_MANY_ARGUMENTS, array(
$function, $matches[0] ) );
+ return true;
+ }
+ } elseif( strpos( $errstr, 'could not be converted' ) !== false
) {
+ if (
+ isset($object[1]['class']) &&
is_subclass_of( $object[1]['class'], 'PhpTags\\GenericFunction') &&
+ preg_match( '/^Object of class
([\\w:\\\\]+) could not be converted to (\\w+).*?/', $errstr, $matches )
+ )
+ {
+
+ foreach ( $object[0]['args'] as $arg ) {
+ if ( $arg instanceof GenericObject &&
get_class($arg) == $matches[1] ) {
+ $matches[1] = $arg->getName();
+ }
+ }
+ Runtime::$transit[PHPTAGS_TRANSIT_EXCEPTION][]
= new PhpTagsException(
+
PhpTagsException::NOTICE_OBJECT_CONVERTED,
+ array( $matches[1], $matches[2]
)
+ );
+ return true;
+ }
+ } elseif ( strpos( $errstr, 'Unexpected object type' ) !==
false ) {
+ if (
+ isset($object[1]['class']) &&
is_subclass_of( $object[1]['class'], 'PhpTags\\GenericFunction') &&
+ preg_match( '/Unexpected object type
(\\w+)/', $errstr, $matches )
+ )
+ {
+ $function = substr( $object[1]['function'] ==
'__callStatic' ? $object[2]['args'][0][0] : $object[2]['function'], 2 );
+ Runtime::$transit[PHPTAGS_TRANSIT_EXCEPTION][]
= new PhpTagsException( PhpTagsException::FATAL_UNEXPECTED_OBJECT_TYPE, array(
$function, $matches[0] ) );
+ var_dump( 'TRUE' );
+ return true;
+ }
+ }
+ return false;
+ }
+
}
diff --git a/includes/PhpTagsException.php b/includes/PhpTagsException.php
index b5b0eb8..7f597c8 100644
--- a/includes/PhpTagsException.php
+++ b/includes/PhpTagsException.php
@@ -80,6 +80,9 @@
case self::WARNING_EXPECTS_PARAMETER:
$message = "{$arguments[0]}() expects parameter
{$arguments[1]} to be {$arguments[2]}, {$arguments[3]} given";
break;
+ case self::FATAL_UNEXPECTED_OBJECT_TYPE; // = 4021; //
Fatal error: Unexpected object type stdClass. in
+ $message = "{$arguments[0]}() Unexpected object
type {$arguments[1]}";
+ break;
case self::WARNING_EXPECTS_EXACTLY_PARAMETERS:
$message = "{$arguments[0]}() expects exactly
{$arguments[1]} parameters, {$arguments[2]} given";
break;
@@ -91,6 +94,9 @@
break;
case self::WARNING_EXPECTS_AT_LEAST_PARAMETER:
$message = "{$arguments[0]}() expects at least
{$arguments[1]} parameter, {$arguments[2]} given";
+ break;
+ case self::WARNING_TOO_MANY_ARGUMENTS; //Warning: Too
many arguments for date_format(), expected 2
+ $message = "Too many arguments for
{$arguments[0]}(), expected {$arguments[1]}";
break;
case self::NOTICE_OBJECT_CONVERTED:
$message = "Object of class {$arguments[0]}
could not be converted to {$arguments[1]}";
@@ -224,6 +230,7 @@
const WARNING_EXPECTS_AT_LEAST_PARAMETER = 3011; // PHP Warning:
sprintf() expects at least 1 parameter, 0 given
const WARNING_ATTEMPT_TO_ASSIGN_PROPERTY = 3012; // PHP Warning:
Attempt to assign property of non-object
const WARNING_EXPECTS_AT_MOST_PARAMETERS = 3013; // PHP Warning:
round() expects at most 3 parameters, 4 given
+ const WARNING_TOO_MANY_ARGUMENTS = 3014; //Warning: Too many arguments
for date_format(), expected 2
const WARNING_CALLFUNCTION_INVALID_HOOK = 3900;
const WARNING_CALLCONSTANT_INVALID_HOOK = 3901;
@@ -249,6 +256,7 @@
const FATAL_CALLED_MANY_EXPENSIVE_FUNCTION = 4018;
const FATAL_CALL_FUNCTION_ON_NON_OBJECT = 4019; // PHP Fatal error:
Call to a member function doo() on a non-object
const FATAL_ACCESS_TO_UNDECLARED_STATIC_PROPERTY = 4020; // PHP Fatal
error: Access to undeclared static property: F::$rsrr
+ const FATAL_UNEXPECTED_OBJECT_TYPE = 4021; // Fatal error: Unexpected
object type stdClass. in
const FATAL_DENIED_FOR_NAMESPACE = 4500;
diff --git a/includes/Runtime.php b/includes/Runtime.php
index 0804444..b7255ca 100644
--- a/includes/Runtime.php
+++ b/includes/Runtime.php
@@ -666,7 +666,7 @@
}
}
} while( list($code[$codeIndex][PHPTAGS_STACK_RESULT],
$code, $codeIndex, $c, $loopsOwner) = array_pop($memory) );
- } catch ( PhpTagsException $e ) {
+ } catch ( PhpTagsException $e ) {
$e->tokenLine = $value[PHPTAGS_STACK_TOKEN_LINE];
$e->place = $place;
foreach ( self::$transit[PHPTAGS_TRANSIT_EXCEPTION] as
$exc ) {
diff --git "a/tests/phpunit/includes/\041\041\041firstInit_Test.php"
"b/tests/phpunit/includes/\041\041\041firstInit_Test.php"
new file mode 100644
index 0000000..3e77f5e
--- /dev/null
+++ "b/tests/phpunit/includes/\041\041\041firstInit_Test.php"
@@ -0,0 +1,8 @@
+<?php
+
+if ( ! defined( 'PhpTagsRuntimeFirstInit' ) ) {
+ wfRunHooks( 'PhpTagsRuntimeFirstInit' );
+ \PhpTags\Runtime::$loopsLimit = 1000;
+ define( 'PhpTagsRuntimeFirstInit', true );
+}
+
diff --git a/tests/phpunit/includes/RuntimeTest.php
b/tests/phpunit/includes/RuntimeTest.php
index 839f142..740e51c 100644
--- a/tests/phpunit/includes/RuntimeTest.php
+++ b/tests/phpunit/includes/RuntimeTest.php
@@ -1,9 +1,6 @@
<?php
namespace PhpTags;
-\wfRunHooks( 'PhpTagsRuntimeFirstInit' );
-\PhpTags\Runtime::$loopsLimit = 1000;
-
class RuntimeTest extends \PHPUnit_Framework_TestCase {
public function testRun_echo_apostrophe_1() {
--
To view, visit https://gerrit.wikimedia.org/r/154991
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ib423619a8116f36a15ee747ca2074cd827e650f6
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/PhpTags
Gerrit-Branch: master
Gerrit-Owner: Pastakhov <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits