exception-driven development [lightning talk]
TRANSCRIPT
Exception
LogicException RuntimeException
AmbiguousOptionsException
DivideByZeroException
ExpiredException
BadConfigurationException
RecursiveExceptionCorruptDataException
DerpExceptionOver9000Exception
Exception
LogicException RuntimeException
AmbiguousOptionsException
DivideByZeroException
ExpiredException
BadConfigurationException
RecursiveExceptionCorruptDataException
DerpException Over9000Exception
http://knowyourmeme.com/memes/derp http://knowyourmeme.com/memes/its-over-9000
WHAT IS A LOGIC EXCEPTION ?
php.net/manual/en/class.logicexception.php
[An] Exception that represents [an] error in the program logic.
This kind of exception should lead directly to a fix in your code.
WHAT IS A RUNTIME
EXCEPTION ?
[An] Exception thrown if an error
which can only be found on
runtime occurs.
http://php.net/manual/en/class.runtimeexception.php
PREVENT A LOGIC
EXCEPTION …
Cannot divide by zero.
Somebody owes 323 billion Euros
(ie. Greece).
AND MAKE IT A RUNTIME
EXCEPTION .
http://www.bbc.co.uk/news/world-europe-33407742
class MissingInvoiceeException extends \RuntimeException{ }
class DivisionByZeroException extends \LogicException{ }
…WILL BECOME…
class Calculator { public function divide($x, $y) { if (0 === $y) { throw new DivisionByZeroException( 'Cannot divide by zero.’ ); } return $x / $y; } }
LOW-LEVEL API WILL THROW LOGIC EXCEPTION
try { return $this->calculator->divide(100, 0);
} catch (DivisionByZeroException $e) { return INF; }
HIGH-LEVEL API WILL CATCH LOGIC EXCEPTION…
http://math.stackexchange.com/questions/127376/https://en.wikipedia.org/wiki/Division_by_zero#/media/File:Hyperbola_one_over_x.svg
class Till { public function splitBill(Bill $bill, array $customers) { try { $this->calculator->divide($bill->total, count($customers));
} catch (DivisionByZeroException $e) {
throw new MissingInvoiceeException( 'No-one is currently billed for the amount due.’, 5, $e ); }
}}
… OR THROW A RUNTIME EXCEPTION
throw new \Exception( string $message, int $code = 0, \Exception $previous = null );
EXCEPTIONS TAKE 3 ARGUMENTS
http://php.net/manual/en/class.exception.php
ARGUMENT 1
string $message
* Explain why the exception was thrown.
* Never display the message to the end-user.
* This is so they can be translated.
* It may also contain sensitive information.
* Suggest a fix for the exception.
SYMFONY EXCEPTIONS TEND TO MAKE SUGGESTIONS ON HOW TO FIX THEM.
https://github.com/symfony/symfony/blob/2.8/src/Symfony/Component/DependencyInjection/Compiler/CheckReferenceValidityPass.php#L146
https://github.com/symfony/symfony/blob/2.8/src/Symfony/Component/DependencyInjection/Exception/ScopeCrossingInjectionException.php
ARGUMENT 3
\Exception $previous
* When one action cannot be performed because another failed.
* When a high-level API causes errors in a low-level API.
* Mistakes occur as the result of a sequence of failures, which can be easily traced.
try { try { try { charge_bill(); } catch (DivideByZeroException $e) { throw new NoInvoiceeException(‘’, 5, $e); } } catch (NoInvoiceeException $f) { if ($debtor = find_debtor()) { chase_debtor($debtor); }
throw new DebtorNotFoundException(‘’, 6, $f); } } catch (DebtorNotFoundException $g) { write_off_debt(); }
A SEQUENCE OF FAILURES CAN BE AUDITED.
DivideByZeroException
NoInvoiceeException
DebtorNotFoundException
charge_bill()
write_off_debt()
ARGUMENT 2
int $code
* Categorize your exceptions…
* …Or identify them.
* Conditions in which the exception occurred can be quickly determined.
* Logging of exceptions is better handled.
new BadDataException( ‘Oyster card cannot be read’, $code = 1);
new DoubleEntryException( ‘Card already passed through the gates’, $code = 21);
new InsufficientBalanceException( ‘No valid season ticket or not enough funds.’, $code = 36);
IF OYSTER CARDS WERE MANAGED BY PHP…
https://www.whatdotheyknow.com/request/189010/response/471377/attach/4/Gate%20Reject%20Codes%20FOI%20request.pdf
IATA DELAY CODES
> IATA delay codes were created to standardise the reporting by airlines of commercial flight departure delays.
> Previously, every airline had its own system, which made the sharing and aggregation of flight delay information difficult.
> IATA standardised the flight delay reporting format by using codes that attribute cause and responsibility for the delay.
https://en.wikipedia.org/wiki/IATA_delay_codes
IATA DELAY CODES STARTING WITH…
0 — internal issues
1 — passenger/baggage
2 — cargo/mail
3 — handling
4 — technical
5 — damage/failure
6 — operation
7 — weather
8 — air traffic control
9 — miscellaneous
https://www.eurocontrol.int/sites/default/files/content/documents/official-documents/facts-and-figures/coda-reports/standard-iata-delay-codes-ahm730.pdf
Delay Codes starting with 2 (cargo/mail) These Codes are used to describe delays caused by Cargo (21-26) and Mail Handling (27-29).
21 (CD): Documentation, errors, etc. 22 (CP): Late positioning 23 (CC): Late acceptance 24 (CI): Inadequate packing 25 (CO): Oversales, booking errors 26 (CU): Late preparation in warehouse 27 (CE): Mail Oversales, packing, etc. 28 (CL): Mail Late positioning 29 (CA): Mail Late acceptance
Delay Codes starting with 3 (handling) These Codes are used to describe delays caused by aircraft and ramp handling
31 (GD): Aircraft documentation late or inaccurate, weight and balance (Loadsheet), general declaration, passenger manifest, etc. 32 (GL): Loading, Unloading, bulky/special load, cabin load, lack of loading staff 33 (GE): Loading Equipment, lack of or breakdown, e.g. container pallet loader, lack of staff 34 (GS): Servicing Equipment, lack of or breakdown, lack of staff, e.g. steps 35 (GC): Aircraft Cleaning 36 (GF): Fuelling, Defuelling, fuel supplier 37 (GB): Catering, late delivery or loading 38 (GU): ULD, Containers, pallets, lack of or breakdown 39 (GT): Technical equipment, lack of or breakdown, lack of staff, e.g. pushback
class AircraftCleaningDelayException extends HandlingException { $this->code = 35; }
class HandlingException extends DelayException {}
class DelayException extends \Exception {}
IF IATA DELAYS WERE EXCEPTIONS AND WHERE MANAGED BY PHP…
DOCTRINE EXCEPTIONS “THROW” THEMSELVES
https://github.com/doctrine/doctrine2/blob/2.5/lib/Doctrine/ORM/ORMException.php
Exception
LogicException RuntimeException
OutOfBoundsException
OutOfRangeException
OverflowException
BadFunctionCallException
BadMethodCallException
DomainException
InvalidArgumentException
LengthException RangeException
UnderflowExceptionUnexpectedValueException
http://php.net/manual/en/spl.exceptions.php
try { throw new OutOfTimeException( ‘Thanks for listening’ );
} catch (OutOfTimeException $e) {
// Adam Elsodaney
// Senior Symfony developer at REISS
// Follow me on Twitter @ArchFizz }
FIN
https://github.com/adamelso