# Using PHP explode() to parse multi-part error messages

I am dealing with a system which sends any unexpected errors back to me in a string, for example:

Error Type - Database
Error Message - Error Executing Database Something is wrong.
Error Detail - [Macromedia][SQLServer JDBC Driver][SQLServer]Incorrect syntax near '1'.


Now to create a better UI I am expected to deal with these errors, so I thought about using explode(), and found this user's response in the PHP Manual which helped me delimit the results with two delimiters instead of just one:

Then I needed to get a little deeper into the code because I wanted $key =>$val pairs, so I came across this answer on StackOverflow.

Then I combined both and came across this solution:

function multiexplode ($delimiters,$string) {

$ready = str_replace($delimiters, $delimiters[0],$string);

list($err_typ,$err_typ_cont,
$err_mess,$err_mess_cont,
$err_det,$err_det_cont) = explode($delimiters[0],$ready);

$result[ trim($err_typ) ] = trim($err_typ_cont);$result[ trim($err_mess) ] = trim($err_mess_cont);
$result[ trim($err_det) ] = trim($err_det_cont); return$result;
}


Then I call the function like this:

 multiexplode(array("-", PHP_EOL), $errorMessage)  The response seems to be exactly what I needed: Array ( [Error Type] => Database [Error Message] => Error Executing Database Something is wrong. [Error Detail] => [Macromedia][SQLServer JDBC Driver][SQLServer]Incorrect syntax near '1'. )  My question comes with PHP's best practices, and if there would be a more reliable or a more efficient approach I could take into solving this problem? • which delimeters are you using? I presume not the same from that PHP UCN (i.e. ",",".","|",":") – Sᴀᴍ Onᴇᴌᴀ Nov 7 '17 at 20:29 • @SamOnela No, I am using "-", PHP_EOL The - to separate key from value, and PHP_EOL to create new item from string's new line – Samuel Nov 7 '17 at 20:29 ## 3 Answers A couple of thoughts: • This function is designed to only deal with a very sepcific use case - parsing a formatted error string. For that reason I would recommend changing the function name to be more representative of what is actually happening. Perhaps something like parseErrorString() or similar. • Since you are dealing with a very specific use case here, why would you require the caller to pass in the delimiters? This function should fully encapsulate all the parsing logic. • Using an array for return, seems odd, particularly since you have spaces in your key names. I would consider returning a stdClass or similar object with type, message, detail properties. • Though not strictly required, I would consider using regular expressions here, as I think that can clean things up as well as allow the solution to be less fragile to changes in the string format. • Using PHP_EOL as line break may be fragile. PHP_EOL is good for working with strings within same environment, but may fail if your application is running in a different environment than the environment your string is produced in. • Your function assumes happy path execution. What if you get a poorly/unexpectedly formatted string? Perhaps you are validating this string somewhere else, but if not, you should do it here in your function. A refactoring, with these thoughts in mind, might yield something like the following: function parseErrorString($string) {
if(empty($string) || !is_string($string)) {
throw new InvalidArgumentException('Non-zero length string expected');
}
$lines = preg_split('/\R/',$string);
$error = array_reduce($lines,
function (&$err,$line) {
$regex = '/^Error (Type|Message|Detail) - (.*)$/';
$matches = [];$result = preg_match($regex,$line, $matches); if ($result !== 1) {
// no match.  Is this an error condition?
// at the very least, do nothing
return $err; }$err->{strtolower($matches[1])} =$matches[2];
return $err; }, new stdClass(); ); return$error;
}

• I am getting this error: Fatal error</b>: Cannot use object of type stdClass as array on line <b>268</b> – Samuel Nov 7 '17 at 21:37
• @Samuel code in CR answers isn't meant to be taken as-is (reviewers don't even have to supply code), it's meant to illustrate a point. – Mathieu Guindon Nov 8 '17 at 2:03
• Okay, I was just trying to build off the code you offered; I was testing it to see how it would work. – Samuel Nov 8 '17 at 2:05
• @Samuel Sorry have been writing too much javascript lately I guess, and had syntax error. – Mike Brant Nov 8 '17 at 15:26
• It's alright... I've never been a javascript guy... – Samuel Nov 8 '17 at 15:36

This task seems simple enough to me. I only recommend that you limit the explosion performed on each line, then it won't matter if the delimiter is duplicated later in the line. Clean, reliable, fast.

Code: (Demo)

function parseErrorMessage($string) { foreach(explode(PHP_EOL,$string) as $line){ // split on end of lines list($label,$message)=explode(' - ',$line,2);  // limit the explosion to 2 elements
$result[$label]=$message; // preserve using first half and second half of line } return$result;
}

$string ="Error Type - Database Error Message - Error Executing Database Something is wrong. Error Detail - [Macromedia][SQLServer JDBC Driver][SQLServer]Incorrect syntax near '1'."; print_r(parseErrorMessage($string));


Output:

Array
(
[Error Type] => Database
[Error Message] => Error Executing Database Something is wrong.
[Error Detail] => [Macromedia][SQLServer JDBC Driver][SQLServer]Incorrect syntax near '1'.
)


If you are concerned that your error messsage substring may contain line breaks, then regex is better suited.

The code to follow will break the string into a 1-dimensional array of alternating labels and messages before pairing them with array_chunk() then assigning them as your desired key-value pairs with array_combine().

Code: (Demo)

function parseErrorMessage($string) {$pairs=array_chunk(preg_split('/\R*(Error \w+) - /',$string,NULL,PREG_SPLIT_NO_EMPTY|PREG_SPLIT_DELIM_CAPTURE),2); return array_combine(array_column($pairs,0),array_column($pairs,1)); }$string ="Error Type - Database
Error Message - Error Executing Database Something is wrong.
Error Detail - [Macromedia]
[SQLServer JDBC Driver]
[SQLServer]Incorrect syntax near '1'.";

var_export(parseErrorMessage($string));  Output: array ( 'Error Type' => 'Database', 'Error Message' => 'Error Executing Database Something is wrong.', 'Error Detail' => '[Macromedia] [SQLServer JDBC Driver] [SQLServer]Incorrect syntax near \'1\'.', )  Per your comment: I am using "-", PHP_EOL The - to separate key from value, and PHP_EOL to create new item from string's new line This makes me worry about the cases where one of the lines contains a hyphen (i.e. -), which would yield an incomplete string - see this playground example for an illustration. Mike's answer is good. I agree the name could be made specific for parsing the error message, and that regular expressions could be utilized, though explode() should suffice. function parseErrorMessage ($string) {
$lines = explode(PHP_EOL,$string);
return array_reduce($lines, function($result, $line) {$lineParts = explode(' - ', $line);$key = array_shift($lineParts);$result[trim($key)] = join(' - ',$lineParts);
return \$result;
}, []);
}


This can be demonstrated in this playground example.