diff --git a/ext/json/json_parser.y b/ext/json/json_parser.y
index 2f37641..aa4ece5 100644
--- a/ext/json/json_parser.y
+++ b/ext/json/json_parser.y
@@ -70,20 +70,9 @@ int json_yydebug = 1;
 %destructor { zend_string_release($$.key); zval_dtor(&$$.val); } <pair>
 
 %code {
-int php_json_yylex(union YYSTYPE *value, php_json_parser *parser);
-void php_json_yyerror(php_json_parser *parser, char const *msg);
-void php_json_parser_object_init(php_json_parser *parser, zval *object);
-int php_json_parser_object_update(php_json_parser *parser, zval *object, zend_string *key, zval *zvalue);
-void php_json_parser_array_init(zval *object);
-void php_json_parser_array_append(zval *array, zval *zvalue);
-
-#define PHP_JSON_DEPTH_DEC --parser->depth
-#define PHP_JSON_DEPTH_INC \
-	if (parser->max_depth && parser->depth >= parser->max_depth) { \
-		parser->scanner.errcode = PHP_JSON_ERROR_DEPTH; \
-		YYERROR; \
-	} \
-	++parser->depth
+static int php_json_yylex(union YYSTYPE *value, php_json_parser *parser);
+static void php_json_yyerror(php_json_parser *parser, char const *msg);
+
 }
 
 %% /* Rules */
@@ -102,10 +91,12 @@ start:
 ;
 
 object:
-		'{' { PHP_JSON_DEPTH_INC; } members object_end
+		'{' { if (FAILURE == parser->methods->on_object_start(parser)) YYERROR; } members object_end
 			{
-				PHP_JSON_DEPTH_DEC;
 				$$ = $3;
+				if (FAILURE == parser->methods->on_object_end(parser, &$$)) {
+					YYERROR;
+				}
 			}
 ;
 
@@ -121,7 +112,7 @@ object_end:
 members:
 		/* empty */
 			{
-				php_json_parser_object_init(parser, &$$);
+				parser->methods->init_object(parser, &$$);
 			}
 	|	member
 ;
@@ -129,13 +120,13 @@ members:
 member:
 		pair
 			{
-				php_json_parser_object_init(parser, &$$);
-				if (php_json_parser_object_update(parser, &$$, $1.key, &$1.val) == FAILURE)
+				parser->methods->init_object(parser, &$$);
+				if (parser->methods->object_update(parser, &$$, $1.key, &$1.val) == FAILURE)
 					YYERROR;
 			}
 	|	member ',' pair
 			{
-				if (php_json_parser_object_update(parser, &$1, $3.key, &$3.val) == FAILURE)
+				if (parser->methods->object_update(parser, &$1, $3.key, &$3.val) == FAILURE)
 					YYERROR;
 				ZVAL_COPY_VALUE(&$$, &$1);
 			}
@@ -158,10 +149,12 @@ pair:
 ;
 
 array:
-		'[' { PHP_JSON_DEPTH_INC; } elements array_end
+		'[' { if (FAILURE == parser->methods->on_array_start(parser)) YYERROR; } elements array_end
 			{
-				PHP_JSON_DEPTH_DEC;
 				ZVAL_COPY_VALUE(&$$, &$3);
+				if (FAILURE == parser->methods->on_array_end(parser, &$$)) {
+					YYERROR;
+				}
 			}
 ;
 
@@ -177,7 +170,7 @@ array_end:
 elements:
 		/* empty */
 			{
-				php_json_parser_array_init(&$$);
+				parser->methods->init_array(parser, &$$);
 			}
 	|	element
 ;
@@ -185,12 +178,12 @@ elements:
 element:
 		value
 			{
-				php_json_parser_array_init(&$$);
-				php_json_parser_array_append(&$$, &$1);
+				parser->methods->init_array(parser, &$$);
+				parser->methods->append_to_array(parser, &$$, &$1);
 			}
 	|	element ',' value
 			{
-				php_json_parser_array_append(&$1, &$3);
+				parser->methods->append_to_array(parser, &$1, &$3);
 				ZVAL_COPY_VALUE(&$$, &$1);
 			}
 	|	element errlex
@@ -227,30 +220,16 @@ errlex:
 	
 %% /* Functions */
 
-void php_json_parser_init(php_json_parser *parser, zval *return_value, char *str, size_t str_len, int options, int max_depth)
-{
-	memset(parser, 0, sizeof(php_json_parser));
-	php_json_scanner_init(&parser->scanner, str, str_len, options);
-	parser->depth = 1;
-	parser->max_depth = max_depth;
-	parser->return_value = return_value;
-}
-
-php_json_error_code php_json_parser_error_code(php_json_parser *parser)
-{
-	return parser->scanner.errcode;
-}
-
-void php_json_parser_object_init(php_json_parser *parser, zval *object)
+static int php_json_parser_object_init(php_json_parser *parser, zval *object)
 {
 	if (parser->scanner.options & PHP_JSON_OBJECT_AS_ARRAY) {
-		array_init(object);
+		return array_init(object);
 	} else {
-		object_init(object);
+		return object_init(object);
 	}
 }
 
-int php_json_parser_object_update(php_json_parser *parser, zval *object, zend_string *key, zval *zvalue)
+static int php_json_parser_object_update(php_json_parser *parser, zval *object, zend_string *key, zval *zvalue)
 {
 	/* if JSON_OBJECT_AS_ARRAY is set */
 	if (Z_TYPE_P(object) == IS_ARRAY) {
@@ -279,26 +258,101 @@ int php_json_parser_object_update(php_json_parser *parser, zval *object, zend_st
 	return SUCCESS;
 }
 
-void php_json_parser_array_init(zval *array)
+static int php_json_parser_array_init(php_json_parser *parser, zval *array)
 {
-	array_init(array);
+	return array_init(array);
 }
 
-void php_json_parser_array_append(zval *array, zval *zvalue)
+static int php_json_parser_array_append(php_json_parser *parser, zval *array, zval *zvalue)
 {
 	zend_hash_next_index_insert(Z_ARRVAL_P(array), zvalue);
+	return SUCCESS;
 }
-	
-int php_json_yylex(union YYSTYPE *value, php_json_parser *parser)
+
+
+static int php_json_parser_depth_increase(php_json_parser *parser)
+{
+	if (parser->max_depth && parser->depth >= parser->max_depth) {
+		parser->scanner.errcode = PHP_JSON_ERROR_DEPTH;
+		return FAILURE;
+	}
+	++parser->depth;
+	return SUCCESS;
+}
+
+static int php_json_parser_depth_decrease(php_json_parser *parser)
+{
+	--parser->depth;
+	return SUCCESS;
+}
+
+static int php_json_parser_on_object_start(php_json_parser *parser)
+{
+	return parser->methods->increase_depth(parser);
+}
+
+static int php_json_parser_on_object_end(php_json_parser *parser, zval *object)
+{
+	return parser->methods->decrease_depth(parser);
+}
+
+
+static int php_json_parser_on_array_start(php_json_parser *parser)
+{
+	return parser->methods->increase_depth(parser);
+}
+
+static int php_json_parser_on_array_end(php_json_parser *parser, zval *object)
+{
+	return parser->methods->decrease_depth(parser);
+}
+
+
+static int php_json_yylex(union YYSTYPE *value, php_json_parser *parser)
 {
 	int token = php_json_scan(&parser->scanner);
 	value->value = parser->scanner.value;
 	return token;
 }
 
-void php_json_yyerror(php_json_parser *parser, char const *msg)
+static void php_json_yyerror(php_json_parser *parser, char const *msg)
 {
 	if (!parser->scanner.errcode) {
 		parser->scanner.errcode = PHP_JSON_ERROR_SYNTAX;
 	}
 }
+
+php_json_error_code php_json_parser_error_code(const php_json_parser *parser)
+{
+	return parser->scanner.errcode;
+}
+
+static php_json_parser_methods default_parser_methods =
+{
+	php_json_parser_array_init,
+	php_json_parser_array_append,
+	php_json_parser_object_init,
+	php_json_parser_object_update,
+	php_json_parser_depth_increase,
+	php_json_parser_depth_decrease,
+	php_json_parser_on_object_start,
+	php_json_parser_on_object_end,
+	php_json_parser_on_array_start,
+	php_json_parser_on_array_end,
+};
+
+
+void php_json_parser_init(php_json_parser *parser,
+						  zval *return_value,
+						  char *str,
+						  size_t str_len,
+						  unsigned int options,
+						  unsigned int max_depth)
+{
+	memset(parser, 0, sizeof(php_json_parser));
+	php_json_scanner_init(&parser->scanner, str, str_len, options);
+	parser->depth = 1;
+	parser->max_depth = max_depth;
+	parser->return_value = return_value;
+	parser->methods = &default_parser_methods;
+}
diff --git a/ext/json/php_json_parser.h b/ext/json/php_json_parser.h
index 6964ef8..a66a069 100644
--- a/ext/json/php_json_parser.h
+++ b/ext/json/php_json_parser.h
@@ -22,16 +22,44 @@
 #include <php.h>
 #undef ERROR
 #include "php_json_scanner.h"
 
-typedef struct _php_json_parser {
+typedef struct _php_json_parser php_json_parser;
+
+typedef int (*func_php_json_parser_array_initter)(php_json_parser *parser, zval *array);
+typedef int (*func_php_json_parser_array_appender)(php_json_parser *parser, zval *array, zval *zvalue);
+typedef int (*func_php_json_parser_object_initer)(php_json_parser *parser, zval *object);
+typedef int (*func_php_json_parser_object_updater)(php_json_parser *parser, zval *object, zend_string *key, zval *zvalue);
+typedef int (*func_php_json_parser_depth_increaser)(php_json_parser *parser);
+typedef int (*func_php_json_parser_depth_decreaser)(php_json_parser *parser);
+typedef int (*func_php_json_parser_on_object_start)(php_json_parser *parser);
+typedef int (*func_php_json_parser_on_object_end)(php_json_parser *parser, zval *object);
+typedef int (*func_php_json_parser_on_array_start)(php_json_parser *parser);
+typedef int (*func_php_json_parser_on_array_end)(php_json_parser *parser, zval *object);
+
+typedef struct _php_json_parser_methods {
+	func_php_json_parser_array_initter init_array;
+	func_php_json_parser_array_appender append_to_array;
+	func_php_json_parser_object_initer init_object;
+	func_php_json_parser_object_updater object_update;
+	func_php_json_parser_depth_increaser increase_depth;
+	func_php_json_parser_depth_decreaser decrease_depth;
+	func_php_json_parser_on_object_start on_object_start;
+	func_php_json_parser_on_object_end on_object_end;
+	func_php_json_parser_on_array_start on_array_start;
+	func_php_json_parser_on_array_end on_array_end;
+} php_json_parser_methods;
+
+struct _php_json_parser {
 	php_json_scanner scanner;
 	zval *return_value;
-	int depth;
-	int max_depth;
-} php_json_parser;
+	unsigned int depth:16;
+	unsigned int max_depth:16;
+	const php_json_parser_methods * methods;
+	void * opaque;
+};
 
-void php_json_parser_init(php_json_parser *parser, zval *return_value, char *str, size_t str_len, int options, int max_depth);
+void php_json_parser_init(php_json_parser *parser, zval *return_value, char *str, size_t str_len, unsigned int options, unsigned int max_depth);
 
-php_json_error_code php_json_parser_error_code(php_json_parser *parser);
+php_json_error_code php_json_parser_error_code(const php_json_parser *parser);
 
 int php_json_yyparse(php_json_parser *parser);
 
