15. Community
The PHP community is as diverse as it is large, and its members are ready and willing to support new PHP programmers. Consider joining your local PHP user group (PUG) or attending larger PHP conferences to learn more about the best practices shown here. You can hang out on IRC in the #phpc channel on irc.libera.chat and follow the @phpc, on Discord, on X or Mastodon. Get out there, meet new developers, learn new topics, and above all, make new friends! Other community resources include StackOverflow.
Read the Official PHP Events Calendar
15.1 PHP Conferences
The PHP community also hosts larger regional and national conferences in many countries around the world. Well-known members of the PHP community usually speak at these larger events, so it’s a great opportunity to learn directly from industry leaders.
15.2 PHP User Groups
If you live in a larger city, odds are there’s a PHP user group nearby. You can easily find your local PUG at
PHP.ug. Alternate sources might be Meetup.com or a search for php user group near me
using your favorite search engine (i.e. Google). If you live in a smaller town, there may not be a
local PUG; if that’s the case, start one!
Special mention should be made of two global user groups: NomadPHP and PHPWomen. NomadPHP offers twice monthly online user group meetings with presentations by some of the top speakers in the PHP community. PHPWomen is a non-exclusive user group originally targeted towards the women in the PHP world. Membership is open to everyone who supports a more diverse community. PHPWomen provide a network for support, mentorship and education, and generally promote the creating of a “female friendly” and professional atmosphere.
Read about User Groups on the PHP Wiki
15.3 ElePHPants
ElePHPant is that beautiful mascot of the PHP project with an elephant in its design. It was originally designed for the PHP project in 1998 by Vincent Pontier - spiritual father of thousands of elePHPants around the world - and ten years later adorable plush elephant toys came to birth as well. Now elePHPants are present at many PHP conferences and with many PHP developers at their computers for fun and inspiration.
Interview with Vincent Pontier
15.4 Interacting with Databases
When developers first start to learn PHP, they often end up mixing their database interaction up with their presentation logic, using code that might look like this:
1 <ul>
2 <?php
3 foreach ($db->query('SELECT * FROM table') as $row) {
4 echo "<li>".$row['field1']." - ".$row['field1']."</li>";
5 }
6 ?>
7 </ul>
This is bad practice for all sorts of reasons, mainly that it’s hard to debug, hard to test, hard to read and it is going to output a lot of fields if you don’t put a limit on there.
While there are many other solutions to doing this - depending on if you prefer OOP or functional programming - there must be some element of separation.
Consider the most basic step:
1 <?php
2 function getAllFoos($db) {
3 return $db->query('SELECT * FROM table');
4 }
5
6 $results = getAllFoos($db);
7 foreach ($results as $row) {
8 echo "<li>".$row['field1']." - ".$row['field1']."</li>"; // BAD!!
9 }
That is a good start. Put those two items in two different files and you’ve got some clean separation.
Create a class to place that method in and you have a “Model”. Create a simple .php file to put the presentation
logic in and you have a “View”, which is very nearly MVC - a common OOP architecture for most
frameworks.
foo.php
1 <?php
2 $db = new PDO('mysql:host=localhost;dbname=testdb;charset=utf8mb4', 'username', 'password');
3
4 // Make your model available
5 include 'models/FooModel.php';
6
7 // Create an instance
8 $fooModel = new FooModel($db);
9 // Get the list of Foos
10 $fooList = $fooModel->getAllFoos();
11
12 // Show the view
13 include 'views/foo-list.php';
models/FooModel.php
1 <?php
2 class FooModel
3 {
4 public function __construct(protected PDO $db)
5 {
6 }
7
8 public function getAllFoos() {
9 return $this->db->query('SELECT * FROM table');
10 }
11 }
views/foo-list.php
1 <?php foreach ($fooList as $row): ?>
2 <li><?= $row['field1'] ?> - <?= $row['field1'] ?></li>
3 <?php endforeach ?>
This is essentially the same as what most modern frameworks are doing, albeit a little more manual. You might not need to do all of that every time, but mixing together too much presentation logic and database interaction can be a real problem if you ever want to unit-test your application.
15.5 MySQL Extension
The mysql extension for PHP is incredibly old and has been superseded by two other extensions:
Not only did development stop long ago on mysql, but it has been officially removed in PHP 7.0.
To save digging into your php.ini settings to see which module you are using, one option is to search for mysql_*
in your editor of choice. If any functions such as mysql_connect() and mysql_query() show up, then mysql is
in use.
Even if you are not using PHP 7.x or later yet, failing to consider this upgrade as soon as possible will lead to greater hardship when the PHP upgrade does come about. The best option is to replace mysql usage with mysqli or PDO in your applications within your own development schedules so you won’t be rushed later on.
If you are upgrading from mysql to mysqli, beware lazy upgrade guides that suggest you can simply find and replace mysql_* with mysqli_*. Not only is that a gross oversimplification, it misses out on the advantages that mysqli provides, such as parameter binding, which is also offered in PDO.
15.6 PDO Extension
PDO is a database connection abstraction library — built into PHP since 5.1.0 — that provides a common interface to talk with many different databases. For example, you can use basically identical code to interface with MySQL or SQLite:
1 <?php
2 // PDO + MySQL
3 $pdo = new PDO('mysql:host=example.com;dbname=database', 'user', 'password');
4 $statement = $pdo->query("SELECT some_field FROM some_table");
5 $row = $statement->fetch(PDO::FETCH_ASSOC);
6 echo htmlentities($row['some_field']);
7
8 // PDO + SQLite
9 $pdo = new PDO('sqlite:/path/db/foo.sqlite');
10 $statement = $pdo->query("SELECT some_field FROM some_table");
11 $row = $statement->fetch(PDO::FETCH_ASSOC);
12 echo htmlentities($row['some_field']);
PDO will not translate your SQL queries or emulate missing features; it is purely for connecting to multiple types of database with the same API.
More importantly, PDO allows you to safely inject foreign input (e.g. IDs) into your SQL queries without worrying
about database SQL injection attacks.
This is possible using PDO statements and bound parameters.
Let’s assume a PHP script receives a numeric ID as a query parameter. This ID should be used to fetch a user record
from a database. This is the wrong way to do this:
1 <?php
2 $pdo = new PDO('sqlite:/path/db/users.db');
3 $pdo->query("SELECT name FROM users WHERE id = " . $_GET['id']); // <-- NO!
This is terrible code. You are inserting a raw query parameter into a SQL query. This will get you hacked in a
heartbeat, using a practice called SQL Injection. Just imagine if a hacker passes in an inventive id parameter by
calling a URL like http://domain.com/?id=1%3BDELETE+FROM+users. This will set the $_GET['id'] variable to 1;DELETE
FROM users which will delete all of your users! Instead, you should sanitize the ID input using PDO bound parameters.
1 <?php
2 $pdo = new PDO('sqlite:/path/db/users.db');
3 $stmt = $pdo->prepare('SELECT name FROM users WHERE id = :id');
4 $id = filter_input(INPUT_GET, 'id', FILTER_SANITIZE_NUMBER_INT); // <-- filter your data first\
5 (see [Data Filtering](#data_filtering)), especially important for INSERT, UPDATE, etc.
6 $stmt->bindParam(':id', $id, PDO::PARAM_INT); // <-- Automatically sanitized for SQL by PDO
7 $stmt->execute();
This is correct code. It uses a bound parameter on a PDO statement. This escapes the foreign input ID before it is introduced to the database preventing potential SQL injection attacks.
For writes, such as INSERT or UPDATE, it’s especially critical to still filter your data first and sanitize it for other things (removal of HTML tags, JavaScript, etc). PDO will only sanitize it for SQL, not for your application.
You should also be aware that database connections use up resources and it was not unheard-of to have resources exhausted if connections were not implicitly closed, however this was more common in other languages. Using PDO you can implicitly close the connection by destroying the object by ensuring all remaining references to it are deleted, i.e. set to NULL. If you don’t do this explicitly, PHP will automatically close the connection when your script ends - unless of course you are using persistent connections.
15.7 Abstraction Layers
Many frameworks provide their own abstraction layer which may or may not sit on top of PDO. These will often emulate features for one database system that is missing from another by wrapping your queries in PHP methods, giving you actual database abstraction instead of just the connection abstraction that PDO provides. This will of course add a little overhead, but if you are building a portable application that needs to work with MySQL, PostgreSQL and SQLite then a little overhead will be worth it for the sake of code cleanliness.
Some abstraction layers have been built using the PSR-0 or PSR-4 namespace standards so can be installed in any application you like: