There are a few ways, the simplest is to simply bust out some functions and abstract out the different layers (this should be done anyway if you find yourself going deep.)
if ( /* Condition */ ) {
value = aFunctionSaysWhat();
} else {
// value = Error 1
}
....
value aFunctionSaysWhat(){
if ( /* Condition */ ) {
return aSecondFunctionHere();
} else {
// return Error 2
}
}
The basic premise is that a function should live on one layer of abstraction if possible, and do one thing.
The next possibility is to flatten it all out, this is superior to your initial nested method, but basically has similar complexity. It could be much cleaner than the functional approach if you only have a few options and you don't plan on adding more.
if(ErrorCondition1){
//Error 1
}else if(ErrorCondition2){
//Error 2
}else if(ErrorCondition3){
//Error 3
}else{
//Superb
}
Finally, you can store a hash or map with the desired answers and remove the if completely, the ability to implement this relies on your ability to hash some result:
Results = {'Result1':'Error1', 'Result2':'Error2', 'Result3':'Error3', 'Success':'Superb'}
return Results[ConditionHash(Condition)];