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

Reply via email to