Pages

2016/06/01

PHPSrbija Conference 2016 review

This past weekend I was invited to speak at PHP Srbija Conference 2016 which was held in Belgrade, the capital of Serbia in the south-east of Europe.

I feared that my departure from Brussels Airport was going to take up a lot of time since the terrorist bombing on March 22, but going through the additional security measures went very smoothly.
Arrived at Brussels Airport well ahead of departure time for #phpsrbija
So, I ended up in "the Loft" business lounge on terminal A where I could catch up on some email and do some work before my flight left for Zurich.
Made it to “the Loft” lounge at Brussels Airport. Let’s get some work done! #IWorkAnywhere #DigitalNomad
This StarAlliance business lounge offers soups, bread and hot snacks along with a variety of drinks. So while waiting for your flight you can relax in the very comfortable sofa's (see picture), have a desk-like table for meals or work, use the sleeping pods or take a shower. I decided to have my coffee and a warm snack before take-off.

At the gate I got a pleasant surprise as I was upgraded to business class, making my trip to Zurich very comfortable.
Just got upgraded to @FlySWISS Business Class! W00t! #travelmagic #phpsrb2016
The flight from BRU to ZRH was quick and uneventful. Making the connection in Zurich was without stress as my flight to Belgrade was delayed. But Zurich is a very nice airport with lots of shops and bars, so instead of heading to the business lounge I ended up wondering around from shop to shop.

At my arrival at Nikola Tesla Airport Belgrade I was welcomed by Milan Popović, one of the 3 organizers of the conference. Milan is a very passionate guy who made PHP Srbija to what it is today.

Awesome reception by @komita1981 as a great start for #phpsrb2016
Before we got to the hotel, we first went for dinner. The other two organizers Aco Gagic and Nikola Poša, a couple of volunteers, Phil Sturgeon and Chris Hartjes were already there and had completed their meals. Milan and I joined the table and got extras. The food was awesome and made me forget I had traveled the bigger part of the day. That night, I slept immediately after we arrived at the hotel.
It's pre #phpsrb16 with @grmpyprogrammer @philsturgeon @DragonBe @nikolaposa @komita1981 @AcoGagic @LDusan

The day before the conference, Milan and Nikola took us on a tour at Belgrade Fortress, a beautiful piece of European history that is kept well preserved against the evils of time. If you visit Belgrade, you should visit this place, with perfect view over the Sava and Danube as it was build at their juncture. The visit was followed by a "small" lunch offered by the crew where we catched up with my good friend and fellow ninja turtle Rafael Dohms.

Lunch time! #phpsrb2016
In the evening we were joined by Ciaran McNulty when we went out for drinks and food. I've come to realize that "lots of meat" is just a simple meal in Serbia.

Just a bit of meat

Conference Day 1! Chris Hartjes was opening keynote and presented his best talk I've seen so far. Was it because of the great food or the warm welcome of the Serbian community, I leave that up to your immagination, but Chris flawlessly presented his keynote talk "An oral history of how I became Grumpy". The rest of the day was filled by Sebastian Bergmann, Rafael DohmsCiaran McNulty, Derick Rethans and Phil Sturgeon.


Conference Day 2: Again a day filled with awesome talks by Rafael Dohms, Marco Pivetta, Michelangelo van Dam (me), a dual talk by Sebastian Bergmann and Ciaran McNulty to be closed off by Gojko Adzic who presented an amazing "The future of test automation" closing keynote.


Again, I would like to thank the organizers Aco GagicMilan Popović and Nikola Poša of #PHPSrb16 for going way beyond expectations. You are awesome hosts and it was my privilege being part of this amazing event and taking home so many wonderful experiences.

I can recommend PHPSrbija Conference to every speaker!

It was hard to say goodbye to the good friends I made at this conference, but every beginning has to have an end. So on Monday I started my way back home. But this time it was a bit more eventful as I had hoped for. Flights were delayed because of bad weather in Western Europe and once I arrived back in Belgium, I ended up without normal public transportation because of strikes. In the end, I litterly had to walk the last mile back home. But I made it safe and sound. This little setback was nothing compared to the great conference I had in Serbia. Can't wait for next year!

2016/02/06

PHP Arrays - The php array functions

Source: Xavier33300 on Flickr.com
In my previous article about arrays (the basicssimple operations and associative arrays or hash maps) I have shown what arrays are and what you can do with it. Now I want to dive into real fun and explain PHP's array functions with real-world examples and how you can apply them in your day-to-day work.

Collection to select form key-values

Many of the website registration forms uses a country select element or an autocomplete input field using data from a database.


If this was a single PHP with HTML combined page, there was no problem as you could easily reuse the query made to collect the data. But when using an MVC approach where your controller needs to push the data it fetches from the backend to the form before the form can be passed to the view you're in for a treat. We're addressing the issues for an MVC approach here.

Let's look at our country table first to get an impression how data is being stored in the database.

+-----------+-------------+------+-----+---------+----------------+
| Field     | Type        | Null | Key | Default | Extra          |
+-----------+-------------+------+-----+---------+----------------+
| id        | int(11)     | NO   | PRI | NULL    | auto_increment |
| iso       | char(2)     | NO   |     | NULL    |                |
| name      | varchar(80) | NO   |     | NULL    |                |
| nicename  | varchar(80) | NO   |     | NULL    |                |
| iso3      | char(3)     | YES  |     | NULL    |                |
| numcode   | smallint(6) | YES  |     | NULL    |                |
| phonecode | int(5)      | NO   |     | NULL    |                |
+-----------+-------------+------+-----+---------+----------------+

In order to use this data in our forms, the two fields "iso" and "printable_name" are most likely the fields that would make the most sense.

Two approaches we can take here:

  1. we query our database for only those fields we need, with the requirement that we need to make a second database call when we need to populate our select field for country phone prefixes
  2. we query all of our required fields "iso", "printable_name" and "phonecode" in one query and use PHP array functions to populate our select fields
We choose to take option 2.

Let's have a look on how most people do things nowadays. The first thing they do is retrieve the data from their backend in the controller. In the controller they prepare their form and pass the form back to the view.

public function registerAction()
{
    
$form $this->getForm('member');

    
$countryMapper = new CountryMapper();
    
$countryList $countryMapper->fetchAll();
    
$countrySelect = [];
    
$phoneSelect = [];
    foreach (
$countryList as $country) {
        
$countrySelect[] = [
            
'iso' => $country['iso'],
            
'nicename' => $country['nicename'],
        ];
        
$phoneSelect[] = [
            
'phonecode' => $country['phonecode'],
            
'nicename' => $country['nicename'],
        ];
    }
    
$form->getElement('country')->addMultiOptions($countrySelect);
    
$form->getElement('phoneprefix')->addMultiOptions($phoneSelect);

    if (isset (
$this->session->memberForm)) {
        
$form unserialize($this->session->memberForm);
        unset (
$this->session->memberForm);
    }
    return [
        
'memberForm' => $form,
    ];
}

So, within the controller a loop is created to populate two field elements "country" and "phoneprefix".  Even though this is an easy approach and works in most cases, the moment you have a lot of data to process, this kind of approach is slowing down your application. Say hello to two power functions: "array_walk" and "array_intersect_key"!

PHP function "array_walk" allows you to apply user functionality to each element of that array. This means we can apply our second functionality "array_intersect_key" on each row.

PHP function "array_intersect_key" gives us the ability to take the common elements from our country list row and the keys we provide as second argument.

$countrySelect = [];
array_walk($countryList, function ($row$key) use (&$countrySelect) {
    
$countrySelect[] = array_intersect_key(
        
$row,
        [
'iso' => null'nicename' => null]
    );
});

$phoneSelect = [];
array_walk($countryList, function ($row$key) use (&$phoneSelect) {
    
$phoneSelect[] = array_intersect_key(
        
$row,
        [
'iso' => null'phonecode' => null]
    );
});

Now we have two arrays that contain only the elements we can just pass on to the form select elements. And the whole controller action now looks like this:

public function registerAction()
{
    
$form $this->getForm('member');

    
$countryMapper = new CountryMapper();
    
$countryList $countryMapper->fetchAll();
    
$countrySelect = [];
    
array_walk($countryList, function ($row$key) use (&$countrySelect) {
        
$countrySelect[] = array_intersect_key(
            
$row,
            [
'iso' => null'nicename' => null]
        );
    }); 

    
$phoneSelect = [];
    
array_walk($countryList, function ($row$key) use (&$phoneSelect) {
        
$phoneSelect[] = array_intersect_key(
            
$row,
            [
'iso' => null'phonecode' => null]
        );
    });
    
$form->getElement('country')->addMultiOptions($countrySelect);
    
$form->getElement('phoneprefix')->addMultiOptions($phoneSelect);

    if (isset (
$this->session->memberForm)) {
        
$form unserialize($this->session->memberForm);
        unset (
$this->session->memberForm);
    }
    return [
        
'memberForm' => $form,
    ];
}

Finding primary keys from a collection

Another common pattern I see is when developers need to pull ID's from a collection of elements to pass on to a next request. Again, foreach is the common used loop to iterate over each element, adding the ID property to another array which then gets passed on to the query.

Let's first look our code that we're going to process.

class PhpFunction {
    public 
$id;
    public 
$label;

    public function 
__construct($id$label)
    {
        
$this->id $id;
        
$this->label $label;
    }
$functions = [
    new 
PhpFunction(123'array_map'),
    new 
PhpFunction(124'array_merge_recursive'),
    new 
PhpFunction(125'array_merge'),
];

Now this example is only containing 3 elements, but when you look at the php.net website there are thousands of functions, so consider this is a huge collection of php functions.

In many cases I see something like the following code to retrieve the ID's from this collection:

$functionIds = [];
foreach (
$functions as $function) {
    
$functionIds[] = $function->id;
}

Even though this is a common pattern, I would prefer to use a native PHP function for processing this. Say hello to "array_map", the function that allows you to use a custom functionality on each element of the given array.

$functionIds array_map(function ($element) {
    return 
$element->id;
}, 
$functions);

The result is exactly the same, but now using PHP's native C power processing huge arrays goes a bit faster than the "foreach"-loop.

Next article we're looking at more common patterns for processing arrays. Love to see you again.



2016/01/14

PHP Arrays - Associative Arrays or Hash Maps


Associative array or hash maps are listings of key and value pairs with a posibility to nest additional keys and values. An associative array is a very powerful construct within PHP.

In our previous article we discussed simple arrays, which in their turn are indexed associative arrays under the hood. Take the following example:

$array = [
  
'apple',
  
'banana',
  
'chocolate',
]; 


Is in fact an indexed associative array under the hood:

$array = [
    
=> 'apple',
    
=> 'banana',
    
=> 'chocolate',
]; 


But associative arrays can be so much more than just an indexed array, and you will find many database operations returning arrays where the fields of a table are the keys in the array while their values are also the values within the array.

$productRowData = [
    
'product_id' => 1234,
    
'brand_id' => 321,
    
'product_name' => 'Our awesome product',
    
'prodcut_description' => 'This is our most awesome product.',
    
'product_sku' => 'ABC1234-XYZ',
    
'product_price' => 59.95,
];


Another example of use is to store configuration information in a PHP array, like Zend Framework does. It's maybe why they call it the "Array Framework". But it's actually a good approach to store configuration settings inside a PHP array as you don't need to parse another format like INI, XML, YAML, JSON or CSV, saving a couple of CPU cycles loading the configuration for your application. Once parsed, it will be represented as an array anyways, maybe serialized for persistance.

$dbConfig = [
    
'db' => [
        
'erp' => [
            
'host' => '123.123.456.456',
            
'port' => 3306,
            
'username' => 'erp_user',
            
'password' => 'v3rRy$ecR3tP@ssMor7! ',
            
'dbname' => 'erp',
        ],
        
'crm' => [
            
'host' => '123.123.426.426',
            
'port' => 3306,
            
'username' => 'crm_user',
            
'password' => ' Y0u L1k3 f1&h 4nD Ch1p$?! ',
            
'dbname' => 'crm',
        ],
    ],
];


How can we iterate over these values? The easiest way is to use "foreach()" as we can define the key and value in the iteration construction:

foreach ($productRowData as $key => $value) {
    echo 
'key : '  $key PHP_EOL;
    echo 
'value: ' $value PHP_EOL;
    echo 
PHP_EOL;
}


For the other loops like "for", "do-while" and "while-do" we need to do a bit of extra work. As we don't have direct access to the "index" of the associative array, we cannot iterate over the keys. So we fetch the keys as a seperate array with "array_keys" function.

$count count($productRowData); 
$keys array_keys($productRowData);

echo 
'== Iteration with for' PHP_EOL;
for (
$i 0$i $count$i++) {
    echo 
'key : '  $keys[$i] . PHP_EOL;
    echo 
'value: ' $productRowData[$keys[$i]] . PHP_EOL;
    echo 
PHP_EOL;
}

echo 
'== Iteration with do-while' PHP_EOL
$i 0;
do {
    echo 
'key : '  $keys[$i] . PHP_EOL;
    echo 
'value: ' $productRowData[$keys[$i]] . PHP_EOL;
    echo 
PHP_EOL;
    
$i++;
} while (
$i $count);

echo 
'== Iteration with while-do' PHP_EOL
$i 0;
while (
$i $count) {
    echo 
'key : '  $keys[$i] . PHP_EOL;
    echo 
'value: ' $productRowData[$keys[$i]] . PHP_EOL;
    echo 
PHP_EOL;
    
$i++;
}


Both loops "for" and "while-do" will first evaluate the given condition before they start their iteration. The "do-while" loop will execute the loop at least once before validating a condition. In some conditions this can be convenient.

What if we want to look for a specific value, should we iterate over each element until we find the value? Let's say we are looking in our configuration for the array containing the value "123.123.426.426" because we found it in one of our logs. A very common practice is the following example:

$searchResult null
$search '123.123.426.426'

foreach (
$dbConfig as $db) {
    foreach (
$db as $target => $dbSettings) {
        if (
$search === $dbSettings['host']) {
            
$searchResult $dbSettings;
        }
    }

// do something with $searchResult

This is a very common practice I come accross and even though it's not a bad practice, there are php array functions available that do the trick as well. In this case, I choose "array_filter" to quickly retrieve the correct array.

foreach ($dbConfig as $db) {
    
$searchResult array_filter($db, function ($v) use ($search) {
        return 
in_array($search$v);
    });

// do something with $searchResult

Above functionality allows us to keep a clear understanding what's going on and we reduce the amount of iterations we need to execute. Consider doing this on an array with a couple of 1000 entries.

In our next article we're going to look a bit more at the various PHP array functions you can use in your day-to-day application development.

2016/01/06

PHP arrays - simple operations

Source: Flickr.com -  Upupa4me
Like all things in life, we need to start with simple things. So, in order to understand what arrays are in PHP, we need to take a look at the PHP manual to read what it is all about:
An array in PHP is actually an ordered map. A map is a type that associates values to keys. This type is optimized for several different uses; it can be treated as an array, list (vector), hash table (an implementation of a map), dictionary, collection, stack, queue, and probably more.
The thing with PHP is that an array is probably one of the most used data structures in web applications build with PHP and used for a wide variety of purposes.

Let's look at a first usage of an array: storing multiple values in a list.

<?php
$array 
= [
    
'foo',
    
'bar',
    
'baz',
];


This is a PHP array with 3 elements. Now we can add an element at the end of this array.

// Adding an element at the of the array 
array_push($array'foobar');

Or even more efficient:

$array[] = 'barbaz';

Now our array looks like this:

$array = [
    
'foo',
    
'bar',
    
'baz',
    
'foobar',
    
'barbaz',
];


As you can see, PHP arrays are easy to create lists which you can now toss around in your application. But what if you need to reverse the process and remove elments from the end of your array?

// Removing the last element of an array 
$last array_pop($array);

Now $last will contain the value "barbaz" and the array itself is now reduced by one from the end.

$array = [
    
'foo',
    
'bar',
    
'baz',
    
'foobar',
]; 


Of course we can also pull elements from the beginning of the array.

// Removing the first element of an array 
$first array_shift($array); 

Now $first will contain the value "foo" and the array is now reduced by one from the beginning.

$array = [
    
'bar',
    
'baz',
    
'foobar',
]; 


In our next chapter let's have a look at associative arrays and what you can do with those.




2016/01/04

PHP arrays - the basics




In 2015 we celebrated the twentieth birthday of PHP and we even had the release of php-7.0.0. Life is all good!

I wish it was all this peachy. In my work as a consultant or when I'm working on OSS projects I cannot help noticing that some of the basics of PHP are missing, especially when dealing with arrays.

To give you an example: developers and site owners often complain about their web application being slow. When I get called in to improve performance, I stumble on a huge number of foreach-loops when processing data retrieved from a database. The first iteration happens right at data retrieval where the result set is iterated over to produce a new array of data models.

/**
 * Fetches all entries, optionally matching provided conditions,
 * optionally ordered by provided order, optionally limited by
 * provided number of entries with an optional provided offset.
 *
 * @param array $where
 * @param array $order
 * @param int $limit
 * @param int $offset
 * @return array
 */
public function fetchAll($where = [], $order = [], $limit = 0, $offset = 0)
{
    $sql = 'SELECT * FROM ' . $this->getTable();
    if ([] !== $where) {
        $sql .= ' WHERE ';
        $fields = array_keys($where);
        $sql .= implode(' AND ', $fields);
    }
    if ([] !== $order) {
        $sql .= ' ORDER BY ' . implode(', ', $order);
    }
    if (0 < $limit) {
        $sql .= ' LIMIT ';
        if (0 < $offset) {
            $sql .= $offset . ', ';
        }
        $sql .= $limit;
    }
    if (false === ($statement = $this->pdo->prepare($sql))) {
        $this->error($this->pdo->errorInfo());
    }
    if (false === $statement->execute(array_values($where))) {
        $this->error($statement->errorInfo());
    }
    $result = $statement->fetchAll(\PDO::FETCH_ASSOC);
    $collection = [];
    foreach ($result as $entry) {
        $collection[] = new $this->modelName($entry);
    }
    return $collection;
}

A second iteration is often found somewhere at the controller or services level where the collection of data models is enriched or changed as preparation for the view (or output).

/**
 * Apply a discount percentage on all articles
 *
 * @param float $discount
 * @return array
 */
public function applyDiscountAsPercentage($discount)
{
    $entries = $this->mapper->fetchAll();
    $discounts = [];
    foreach ($entries as $entry) {
        $discountProduct = new DiscountProduct($entry->toArray());
        $discountCalc = round(($entry->getPrice() * (100 - $discount)) / 100, 2);
        $discountProduct->setDiscountPrice($discountCalc);
        $discounts[] = $discountProduct;
    }
    return $discounts;
}

A third iteration is often found at the output, where the collection is presented in a listing, table or grid.

require_once __DIR__ . '/php_arrays_examples.php';

use \DragonBe\ProductService;
use \DragonBe\ProductMapper;
use \DragonBe\ProductGateway;

$pdo = new \PDO('sqlite:phparray.db');

$productService = new ProductService(new ProductMapper(new ProductGateway($pdo)));
$discounts = $productService->applyDiscountAsPercentage(15);

echo sprintf('%-25s %10s %10s', 'Product', 'Sales', 'Promo') . PHP_EOL;
foreach ($discounts as $discountProduct) {
    echo sprintf(
        '%-25s %10.2f %10.2f',
        $discountProduct->getTitle(),
        $discountProduct->getPrice(),
        $discountProduct->getDiscountPrice()
    ) . PHP_EOL;
}

At this point, we already count 3 iterations between fetching data and outputting data. Often there are  a whole lot more iterations in between. Only to display a simple list of products with discounts.

Product                        Sales      Promo
demo_phone                    295.95     251.56
demo_computer                1999.95    1699.96
demo_tablet                   675.00     573.75
demo_drive                      5.99       5.09
demo_charger                   12.45      10.58
demo_coffee_mug                24.95      21.21
demo_phone_case                29.00      24.65
demo_usb_cable                 45.95      39.06
demo_external_screen          199.95     169.96
Added prodcut                 129.95     110.46
Added prodcut                 129.95     110.46
Added prodcut                 129.95     110.46

So what is the big deal here? Well, in development you probably test these routines with maybe 5 data entries (or 10 for extra edge cases) and performance is great. But in production, especially over time, you're dealing with a couple of thousand records. Millions if you're working for a large company. Simple math will give you an idea how 3 times many will start to slow things down. Unfortunately this is where PHP gets a bad reputation for being slow, even though I see similar mistakes in other technologies as well.

Luckily PHP has a few powerful array functions to help developers improve performance and their code.

In next articles I will highlight some of these functions and give real world examples where they will make a difference in performance.

2015/12/07

Installing PHP 7 with XDebug, Apache and MySQL on OS X Yosemite


In my previous blog post "Installing PHP 7 on OS X Yosemite" I gave some insights on how to get quicly started with PHP7 on your Mac, specifically on your commandline. But before I continue on how to make it work with your installed Apache and MySQL I would like to address a subject many people found worth mentioning: PHP Installation Managers.

PHP Installation Managers

In the feedback I received on my article, people would like to point out that the package managers like "PHP-OSX" binary installer, "phpenv" multiversion php management and installer, "phpbrew" for installing and running multiple versions of PHP and "HomeBrew" the missing package manger for OS X. There will be probably more tools out there, but these were the suggestions made by some of my readers.

Again, I have nothing against these tools and I value their functionality a lot. The only reason I posted my article was to show people how you could have PHP 7 run immediately on your system without being too depending of any availability in a package manager or other tool. If you already have one of these PIM's configured, by all means use them. Saves you a bunch of manual work.

But if you don't have interest to install an additional tool, you can still follow these guidelines to have the latest and greatest PHP7 running on OS X.

If you would like to keep your system clean, there's also a Docker installation for PHP7 provided by Zend Technologies, Inc.


XDebug

When running PHP you also want to have XDebug compiled into it. Unfortunately there's not a stable release for XDebug 2.4, but I feel confident using the RC in the mean time as debugging is only something I will use locally.

Get the latest XDebug package (at this time of writing it's xdebug-4.2.0RC2), check the signature and unpack it.

$ cd /tmp/
$ wget http://xdebug.org/files/xdebug-2.4.0rc2.tgz
$ md5check xdebug-2.4.0rc2.tgz e00e92bb2e72f7c94e1300b2a980e79e
OK
$ tar -xvzf xdebug-2.4.0rc2.tgz
$ cd xdebug-2.4.0RC2/
Once done, we need to phpize and configure XDebug using our installed PHP7 in /opt/php7.

$ /opt/php7/bin/phpize
$ ./configure --enable-xdebug --with-php-config=/opt/php7/bin/php-config
Now all we need to do is to run make and make test to complete the build. This will create a xdebug.so shared object we need to copy to our PHP7 installation extension directory.

$ sudo cp modules/xdebug.so /opt/php7/lib/php/extensions/no-debug-non-zts-20151012/
Now we have the extension installed, we need to inform PHP7 we have the extension available. In the configuration of PHP7 in my previous article, I had stated that our configuration was going to be installed in /etc/php7 (see --with-config-file-path=/etc/${PHP} argument). This also means we need to ensure a php.ini file is there. Since this is a clean installation, we can easily copy the supplied php.ini-development into our configration path.

$ sudo cp /tmp/php-7.0.0/php.ini-development /etc/php7/php.ini
Now we need to add the xdebug configuration in it.

[xdebug]
zend_extension=/opt/php7/lib/php/extensions/no-debug-non-zts-20151012/xdebug.so
When we now run php -v on the commandline, we now see xdebug is installed correctly.

Further php.ini settings

In PHP7 if you omit to change the date.timezone, it will be set to UTC by default which might cause some conflicts if you have time and date operations. Best is you set it to the timezone you prefer (e.g. Europe/Brussels).

[Date]
; Defines the default timezone used by the date functions
; http://php.net/date.timezone
date.timezone = Europe/Brussels

Apache Module for PHP7

OS X Yosemite comes with Apache 2.4 installed, so all we need to do is ensure PHP7 is compiled with flag --with-apxs2 enabled, which we already provided in my configure script mentioned in my previous article. This will modify our Apache /etc/apache2/httpd.conf and will add the following line:

LoadModule php7_module        libexec/apache2/libphp7.so
So now we have a PHP5 and a PHP7 module in our configuration. Prefer to uncoment the line for loading the PHP5 module so we only have the PHP7 module to take care of.

Now you just have to make the configuration for php7_module available. Therefor I added a new file /etc/apache2/other/php7.conf where I have specific PHP7 directives (comparable to the PHP5 directives).

<IfModule php7_module>
 AddType application/x-httpd-php .php
 AddType application/x-httpd-php-source .phps

 <IfModule dir_module>
  DirectoryIndex index.html index.php
 </IfModule>
</IfModule>
Now we can restart Apache and we should be able to see a nice phpinfo() page for PHP7 (I always have one available in the webroot).
Success! We have now PHP7 for our web applications too.

MySQL setup

The final step is to ensure we can connect with the installed MySQL database. Since we already took care of that in our configure-php.sh script, all database settings were already configured. No further settings are required.

--with-mysqli \
--with-pdo-mysql \
--with-mysql-sock=/tmp/mysql.sock
Done. That's it. Again, if you can work with a package manager of binary installer tool, go ahead use them. If you would like to have a bit more control, feel free to use this guide.