Re: [PHP] Re: poll: howto do informative error handling without the fatalities

[email protected] (Rene Veerman)
Newsgroups php.general
Message-ID <[email protected]>
Well, i've thought of a few ways to allow localized overriding of
values returned by functions in case of an error.

I have yet to figure out what the exact advantages are of this
code-standard, but the overhead seems acceptable and i recon this,
when done, will beat the "trigger_error()-try-catch" paradigm.
I'd like to hear your comments.

// imo unsafe & prone to fatalities:
$r = funcA ( funcB ( funcC ($p) ), funcD ($q) );

// "safe"; make all notices, warnings and errors from any level
// in the call-chain fully visible, identifiable, and "survivable/fudgeable"
// by code at (all) higher levels in the call-chain.
// [disclaimer] the code below here doesn't pass 3rd-level (funcC())
// (meta-)results back to the first level (funcA()) yet, but this code
// is a start towards that;
$r = funcA (defaults(array(0=>'[funcB failed]',1=>'funcD failed'))),
	funcB (defaults($onError_cCallvalue),
		funcC (defaults($onError_pValue), $p)
	),
	funcD (defaults($onError_qValue), $q)
);

function funcA ($defaults, $returnedByFuncB, $returnedByFuncD) {
	$returnedByFuncB = workWith ($defaults, $returnedByFuncB, 0);
	$returnedByFuncD = workWith ($defaults, $returnedByFuncD, 1);
	//all parameters (with idx>0) are meta-arrays containing the
"parameter-value" and all meta-info.
	// workWith() always returns the actual parameter-value in $p['workValue'];

	//if any parameter $p (with idx>0) is not a meta-array,
	//	workWith($d, $r, $n) turns it into a meta array(
	//		'workValue' => $p
	//	);

	//if a param is a meta-array $p, and it contains an ['errors'] subarray,
	//	workWith() sets by-reference $p['workValue'] to one of these
(order of trying):
	//		$defaults['onError'][$n] (localized override)
	//		$p['onErrorDefault'], (functions own default value for when an
error occurs)

	//first call to workWith(,,0) will call beginErrorContext()

	//beginErrorContext() will increase a global idx $callID (int),
	//  used to list all notices, warnings and errors, and their details in
	//	the global variable $callsErrors[$callID][$errorIdx++] = array(
	//		'errorMsg' => 'for coders'
	//		(optional:)'userErrorMsg' => 'for laymen'
	//		'backtrace' => array(....)
	//	)

	// the never-fatal error handler specified with set_error_handler() will
	//	call getDebugInfo() and append full error info into
	//	$callsErrors[$callID][$errorIdx++]





	//forwardDefaults() clones all meta-details for
	//	re-used parameters into a new $defaults array to be used
	//	by funcE().
	//the 2nd parameter for forwardDefaults lists which parameter
	//	passed deeper refers to which parameter received by this here function.
	//the 3rd parameter for forwardDefaults is used to specify new defaults.
	$returnedByFuncF = funcF('blablasetting');
	$x = funcE (
		forwardDefaults($defaults, array(0=>0,2=>1), array(1 => 'defaultblabla')),
		$returnedByFuncB, $returnedByFuncF, $returnedByFuncD
	);
	return goodResult($x);
}

function funcE ($defaults, $returnedByFuncB, $returnedByFuncF,
$returnedByFuncD) {
	$returnedByFuncB = workWith ($defaults, $returnedByFuncB, 0);
	$returnedByFuncF = workWith ($defaults, $returnedByFuncF, 2);
	$returnedByFuncD = workWith ($defaults, $returnedByFuncD, 2);

	// do a call that might raise E_WARNINGS or other crap;
	// safeCall() is only a try-except struct to call in this case
	// str_replace('xx','yy', ...) and if it fails,
	// return the default instead of the actual result.
	$x = safeCall (
		defaults('returnedByFuncB not a string'),
		'str_replace', 'xx','yy',$returnedByFuncB
	);


	if (is_string($returnedByFuncB) && is_string($returnedByFuncD)) {
		return goodResult (
			$returnedByFuncB . $returnedByFuncD . $x
		);
		// goodResult() and badResult() will both call
		//	endErrorContext(), and copy the errors in
		//	$callsErrors[$callID]
		// to the array returned to the calling function.

		// goodResult() and badResult() will call processErrors(),
		//	which is repsonsible for mailing / db-storage of any
		//	notices, warnings, errors, etc.

	} else {
		//	badResult() will call getDebugInfo() to include
		//		a full trace, superglobals, lotsa details.
		return badResult (array(
		'errorMsg' => 'params 1 and 2 must be strings'
		'onErrorDefault' => ''
		));
		//shorthand of the above:
		return badResult ('params 1 and 2 must be strings', '');
	}
}


function defaults () {
	$r = array (
	'isMetaForFuncs' => true
	);

	if (func_num_args()==1) {
		return array_merge_recursive ($r,
array('onError'=>array(0=>func_get_arg(0))));
	} else {
		switch (func_get_arg(0)) {
		case 'onError':
			$p = func_get_arg(1);
			if (is_array($p)) {
				return array_merge_recursive ($r, array('onError'=>$p));
			} else {
				return array_merge_recursive ($r, array('onError'=>array(0=>$p)));
			}
			break;
		}
	}
}


I also considered the following constructs but rejected them for
clumsiness (first) or sheer uselessness (2nd).

  $r = funcA ($bcalldef, funcB($ccalldef, funcC ($pdef, $p)),
$dcalldef, funcD($qdef, $q));

  $r = funcA ( funcB ( funcC ( $p ) ), funcD ($q), array (
    'isMetaForFuncs' => true,
    0 => array (
      'onError' => $bCallDefaultOnError,
      0 => array (
	'onError' => $cCallDefaultOnError,
	0 => array (
	  'onError' => $pDefaultOnError,
	)
      )
    ),
    1 => array (
      'onError' => $qDefaultOnError
    )
  );
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.