Thinking about it again, I feel like this last solution (having an explicit `Transaction::begin()` method) is the most sensible way of all. It keeps the API simple and semantic, and allows unlimited future extensions like the features suggested in deeky666@d228cd6.

What I would suggest to avoid the complications mentioned above, is:

- throw an exception when trying to `commit()` or `rollback()` a Transaction not yet begun
- throw an exception when trying to `begin()` a nested Transaction when its parent is not active

After all, it's not *very* difficult to remember to routinely use `createTransaction()->begin()`.
Plus, the existing `beginTransaction()` will still be available, and transparently call `createTransaction()->begin()`.
And finally, as noted in the comment above, a forgotten `begin()` will be easily spotted during development, as any subsequent `commit()` or `rollback()` will throw an exception.

I could maybe open another PR based on this principle, so that we can compare the code and see which one we prefer?