if ($order->status == 'paid') in the shipping module. Another one in the refund module. A slightly different one in the admin panel. Then someone cancels a shipped order from an admin button, because the button just writes the string, and the warehouse learns about it a week later.
Symfony 3.2 is out this week and ships a Workflow component. Finally a framework says out loud what every order table has been whispering for years: status is a state machine, not a string column you assign wherever convenient.
The state machine view asks one question first: which transitions are legal? Which states exist, everybody knows. Transitions are the question.
transitions:
pay:
from: new
to: paid
ship:
from: paid
to: shipped
cancel:
from: [new, paid]
to: cancelled
Ten lines, and they hold a business decision: a shipped order cannot be cancelled, it can only be refunded, and refund is a different process. With the component, an illegal transition throws. Without the component the same idea costs one small class with a whitelist of transitions and a single method that changes status. The model matters more than the library.
You also get transitions as events. “Order became paid” is a real moment where things happen: reserve stock, notify, start the shipping clock. Scattered status writes have no such moment, so the logic ends up duplicated near every write.
My test: try to draw the order lifecycle on a whiteboard, from the code alone. On the project with the admin button I could not. The graph existed anyway. Nobody controlled it.