Current section
Files
Jump to
Current section
Files
src/ephp_lib_error.erl
-module(ephp_lib_error).
-author('manuel@altenwald.com').
-compile([warnings_as_errors]).
-behaviour(ephp_func).
-export([
init_func/0,
init_config/0,
init_const/0,
get_classes/0,
debug_backtrace/4,
debug_print_backtrace/4,
error_reporting/3,
set_error_handler/4,
restore_error_handler/2,
set_exception_handler/3,
restore_exception_handler/2,
error_get_last/2,
error_clear_last/2,
trigger_error/4
]).
-include("ephp.hrl").
-spec init_func() -> ephp_func:php_function_results().
init_func() -> [
{debug_backtrace, [
{args, {0, 2, undefined, [{str_or_int, 1}, {str_or_int, 0}]}}
]},
{debug_print_backtrace, [
{args, {0, 2, undefined, [{str_or_int, 0}, {str_or_int, 0}]}}
]},
{set_error_handler, [
{args, {1, 2, undefined, [mixed, {integer, ?E_ALL bor ?E_STRICT}]}}
]},
restore_error_handler,
set_exception_handler,
restore_exception_handler,
error_get_last,
error_clear_last,
error_reporting,
{trigger_error, [
{args, {1, 2, false, [string, {integer, ?E_USER_NOTICE}]}}
]},
{trigger_error, [
{alias, <<"user_error">>},
{args, {1, 2, false, [string, {integer, ?E_USER_NOTICE}]}}
]}
].
-spec init_config() -> ephp_func:php_config_results().
init_config() -> [].
-spec init_const() -> ephp_func:php_const_results().
init_const() -> [
{<<"E_ERROR">>, ?E_ERROR},
{<<"E_WARNING">>, ?E_WARNING},
{<<"E_PARSE">>, ?E_PARSE},
{<<"E_NOTICE">>, ?E_NOTICE},
{<<"E_CORE_ERROR">>, ?E_CORE_ERROR},
{<<"E_CORE_WARNING">>, ?E_CORE_WARNING},
{<<"E_COMPILE_ERROR">>, ?E_COMPILE_ERROR},
{<<"E_COMPILE_WARNING">>, ?E_COMPILE_WARNING},
{<<"E_USER_ERROR">>, ?E_USER_ERROR},
{<<"E_USER_WARNING">>, ?E_USER_WARNING},
{<<"E_USER_NOTICE">>, ?E_USER_NOTICE},
{<<"E_STRICT">>, ?E_STRICT},
{<<"E_RECOVERABLE_ERROR">>, ?E_RECOVERABLE_ERROR},
{<<"E_DEPRECATED">>, ?E_DEPRECATED},
{<<"E_USER_DEPRECATED">>, ?E_USER_DEPRECATED},
{<<"E_ALL">>, ?E_ALL},
{<<"DEBUG_BACKTRACE_PROVIDE_OBJECT">>, ?DEBUG_BACKTRACE_PROVIDE_OBJECT},
{<<"DEBUG_BACKTRACE_IGNORE_ARGS">>, ?DEBUG_BACKTRACE_IGNORE_ARGS}
].
-spec get_classes() -> [class()].
get_classes() ->
ephp_class_exception:get_classes().
-spec debug_backtrace(context(), line(), var_value(), var_value()) ->
ephp_array().
debug_backtrace(Context, _Line, {_, _Flags}, {_, _Limit}) ->
ephp_stack:get_array(Context, 1).
-spec debug_print_backtrace(context(), line(),
var_value(), var_value()) -> undefined.
debug_print_backtrace(Context, _Line, {_, IncludeArgs}, {_, Limit}) ->
Backtrace = ephp_stack:get_array(Context, 1),
ephp_array:fold(fun
(I, Data, _) when Limit =:= 0 orelse I < Limit ->
Str = iolist_to_binary(trace_to_str(I, Data, Context, IncludeArgs)),
ephp_context:set_output(Context, Str);
(_, _, _) ->
ok
end, [], Backtrace),
undefined.
-spec trace_to_str(pos_integer(), ephp_array(), context(), pos_integer()) ->
iolist().
trace_to_str(I, Array, Ctx, IncludeArgs) ->
{ok, FuncName} = ephp_array:find(<<"function">>, Array),
{ok, Line} = ephp_array:find(<<"line">>, Array),
{ok, File} = ephp_array:find(<<"file">>, Array),
{ok, RawArgList} = ephp_array:find(<<"args">>, Array),
IncArgs = ephp_data:to_int(IncludeArgs),
Args = if
(IncArgs band ?DEBUG_BACKTRACE_IGNORE_ARGS) =:= 0 ->
ArgStrList = lists:map(fun({_, #var_ref{pid = Vars, ref = Var}}) ->
Value = ephp_vars:get(Vars, Var, Ctx),
binary_to_list(ephp_string:escape(Value, $'))
end, ephp_array:to_list(RawArgList)),
string:join(ArgStrList, ",");
true ->
""
end,
io_lib:format(
"#~p ~s(~s) called at [~s:~p]~n", [I, FuncName, Args, File, Line]).
-spec error_reporting(context(), line(), var_value()) -> integer().
error_reporting(Context, _Line, {_, ErrorLevel}) when is_integer(ErrorLevel) ->
ephp_error:error_reporting(Context, ErrorLevel).
-spec set_error_handler(context(), line(), var_value(), var_value()) -> mixed().
set_error_handler(Context, _Line, {_, #function{}=ErrorHandler}, {_, ErrorLevel}) ->
case ephp_error:get_error_handler_func(Context) of
{OldErrorHandler, _} ->
OldErrorHandler;
undefined ->
OldErrorHandler = undefined
end,
ephp_error:set_error_handler_func(Context, ErrorHandler, ErrorLevel),
OldErrorHandler;
set_error_handler(Context, Line, {_, ErrorHandler}, {_, ErrorLevel}) ->
%% FIXME: ErrorHandler maybe could be a callable instead...
case ephp_context:is_defined_function(Context, ErrorHandler) of
true ->
case ephp_error:get_error_handler_func(Context) of
{OldErrorHandler, _} ->
OldErrorHandler;
undefined ->
OldErrorHandler = undefined
end,
ephp_error:set_error_handler_func(Context, ErrorHandler, ErrorLevel),
OldErrorHandler;
false ->
Data = {<<"set_error_handler">>, ephp_data:to_bin(ErrorHandler)},
File = ephp_context:get_active_file(Context),
Error = {error, einvalidcallback, Line, File, ?E_WARNING, Data},
ephp_error:handle_error(Context, Error),
undefined
end.
-spec restore_error_handler(context(), line()) -> true.
restore_error_handler(Context, _Line) ->
ephp_error:remove_error_handler_func(Context),
true.
-spec set_exception_handler(context(), line(), var_value()) -> callable().
set_exception_handler(Context, Line, {_, ExceptionHandler}) ->
%% FIXME: ExceptionHandler maybe could be a callable instead...
case ephp_context:is_defined_function(Context, ExceptionHandler) of
true ->
OldExceptionHandler = ephp_error:get_exception_handler_func(Context),
ephp_error:set_exception_handler_func(Context, ExceptionHandler),
OldExceptionHandler;
false ->
Data = {<<"set_exception_handler">>, ephp_data:to_bin(ExceptionHandler)},
File = ephp_context:get_active_file(Context),
Error = {error, einvalidcallback, Line, File, ?E_WARNING, Data},
ephp_error:handle_error(Context, Error),
undefined
end.
-spec restore_exception_handler(context(), line()) -> true.
restore_exception_handler(Context, _Line) ->
ephp_error:remove_exception_handler_func(Context),
true.
-spec error_get_last(context(), line()) -> ephp_array() | undefined.
error_get_last(Context, _Line) ->
ephp_error:get_last(Context).
-spec error_clear_last(context(), line()) -> undefined.
error_clear_last(Context, _Line) ->
ephp_error:clear_last(Context),
undefined.
-spec trigger_error(context(), line(), ErrStr :: var_value(),
ErrLevel :: var_value()) -> boolean().
trigger_error(Context, Line, _ErrStr, {_, ErrLevel})
when ErrLevel band (bnot ?E_USER) =/= 0 ->
File = ephp_context:get_active_file(Context),
ephp_error:handle_error(Context,
{error, enolevel, Line, File, ?E_WARNING, {}});
trigger_error(Context, Line, {_, ErrStr}, {_, ErrLevel}) ->
File = ephp_context:get_active_file(Context),
ephp_error:handle_error(Context, {error, trigger, Line, File, ErrLevel,
{ErrStr}}).