If I have two extensions that both use, say,
hook_civicrm_post, how can I control the order in which the two extensions fire?
I got some great answers on Mattermost.
Frank Gomez of Ginkgo Street Labs says: We've developed an approach (which you may find heavy handed) to dealing with order of operation problems when it comes to hook_civicrm_post. In our case the problem was not the order in which extensions were firing it but rather that dependent entities might not exist yet. Basically the approach is to defer execution of the code by creating a queue item to deal with it on the next page load, when the dependent entities are expected to have been created.
Here's the repo: https://github.com/ginkgostreet/com.ginkgostreet.listener.
Allen Shaw of Joinery points to Tim Otten's post here, the most notable part is: [You can't] - in fact, I suspect the order is non-deterministic, with a slight bias towards installation-order (ie the extension which was installed first would tend to run first). I came to this belief from tracing CRM_Utils_Hook::commonInvoke() => commonBuildModuleList() => requireCiviModules() ...etc... finally arriving at CRM_Extension_Mapper::getActiveModuleFiles(), which queries the DB and does not have an ORDER BY.
My original answer in 2016 is now out of date. In Civi 4.7.19+, you can control the order of hooks with the Symfony EventDispatcher.