3 simple PHP tips to optimize your code

How I divided my server errors by 40 with this 3 tips

This 3 PHP tips are based on first hand experience, as I have been running several Raspberry Pi based trackers for a while, and I wanted to create a common database of detected aircraft and their positions. I looked for online database solution and how I could connect my Pi to them directly in Python, but that was not convenient.

I finally decided to get an hosting plan at OVH and create my own databases, with API to add more aircraft and positions. I wrote all the APIs of my server in PHP, as it was pretty straightforward. I got it work pretty well, but I was still having quite a lot of errors. At first, it was simple, I played a little with the timeout, I add retries, but I was still not able to go below 2% of errors. For a long time I lived with that, my system still worked well, but I finally decided to work on that and optimize PHP code.

The usual PHP tips to optimize PHP code…

A quick search on php optimization got me a list of things to do:

  • use single quote instead of double one: 'text' is better than "text"
  • calculate variable only once in a loop
  • close databases
  • order switch by order of use
  • select specific columns instead of * in mySQL SELECT queries
  • use foreach instead of while
  • use echo $a,$b,$c instead of echo $a.$b.$c
  • use sprintf to add strings: $string = sprintf('today is %s', $date)
  • use === instead of == in if: if ($a===$b) { action}
  • INSERT multiple values in database instead of multiple single INSERT

It seems that many of them were useful for older PHP versions, but not really for PHP versions over 7…

… and what really worked for me!

The 3 actions that had a tremendous effect on my API have been around database optimisation: first, I rewrote the few INSERT loops in order to INSERT multiple values at once. This was already much better. Then I checked my databases structures, to make sure I had all the right indexes corresponding to my SELECT queries. And finally, I switched all the heavy ones to InnoDB (I am not sure why OVH use MyISAM as default structure…).

These 3 actions reduced my error rate from 2% to 0.05% by reducing the load of my server (I am using a very basic hosted configuration, nothing fancy here). On the other tips I found, most of them had no or only very marginal impact. The only one I will keep, is the sprintf function to create my strings with variables as this makes my code much easier to read (it was easy to get lost in the quotes when you write mySQL queries with all that ‘ and ” and .).

How did I find that was my issues? What is important is to find where you PHP requests are spending time. For that, I simply implemented some time measurement inside the code (with the microtime function: $start_time=microtime(True); $stop_time=microtime(True); phpduration = $stop_time-$start_time;), that is coming back to my Pi with the result of the API. I could then dig into the one loading the server for more than 1s and reduced their load. I did the same in my Pi, to track which mySQL queries were taking more than 0.001s to run, and that was very efficient.

I was able to focus on optimising the most important ones (mainly those on huge database, such as positions, which rapidly contain millions of entries), and optimise their structure and indexes. There are many tools available to profile your PHP code, but I didn’t find any that was easy enough to start with compared to what I needed them for.

With 0.05% error rate, I can think about adding more trackers and maybe even have a way for others to share their tracking data with me! Let me know if you would share yours or if you have more tips to optimise PHP code…

What else can help reduce connection errors?

I also did several actions to reduce connection errors to my API server:
– make sure you don’t have any redirection
– make sure you updated requests and certifi on the Raspberry Pi, specially if you are using a secured connection. It can easily be done by:
pip install --upgrade requests certifi urllib3 idna chardet
– use session if you are calling the API regularly:
api_session = requests.Session()
resp = api_session.get([request])
will replace requests.get([request])
– set a different timeout for connection and response:
api_session.get([request], timeout=(5,10))

Don’t hesitate to share your own PHP tips in the comments!

Leave a Reply