PHP
"C'est de la merde"
Ce n'est pas un "vrai" langage de programmation
En résumé
- 1994 - Rasmus Lerdorf crée Personal Home Page Tools
- 1995 - PHP Tools devient public
- 1996 - PHP/FI 2.0 - Réécriture de 0, PHP devient un langage
- 1998 - PHP 3.0 est annoncé (10% des serveurs web)
- 2000 - PHP 4.0 est publié
- 2004 - PHP 5.0 plus de fonctions, un nouveau modèle objet
- 2015 - PHP 7.0 de meilleurs performances, déclaration de type scalaires
source : L'histoire de PHP
<!--include /text/header.html-->
<!--getenv HTTP_USER_AGENT-->
<!--ifsubstr $exec_result Mozilla-->
Hé, vous utilisez Netscape !<p>
<!--endif-->
<!--sql database select * from table where user='$username'-->
<!--ifless $numentries 1-->
Désolé, cette ligne n'existe pas<p>
<!--endif exit-->
Bienvenue <!--$user--> !<p>
Vous avez <!--$index:0--> crédits sur votre compte.<p>
<!--include /text/footer.html-->
<!--include /text/header.html-->
<!--getenv HTTP_USER_AGENT-->
<!--ifsubstr $exec_result Mozilla-->
Hé, vous utilisez Netscape !<p>
<!--endif-->
<!--sql database select * from table where user='$username'-->
<!--ifless $numentries 1-->
Désolé, cette ligne n'existe pas<p>
<!--endif exit-->
Bienvenue <!--$user--> !<p>
Vous avez <!--$index:0--> crédits sur votre compte.<p>
<!--include /text/footer.html-->
<?php
namespace App\Basket\Table;
use App\Auth\User;
use App\Basket\Basket;
use App\Basket\BasketRow;
use App\Basket\Entity\Basket as BasketEntity;
class BasketTable extends Table
{
public function findForUser(int $userId): ?BasketEntity
{
return $this->makeQuery()->where("user_id = $userId")->fetch() ?: null;
}
public function createForUser(int $userId): BasketEntity
{
$params = [
'user_id' => $userId
];
$this->insert($params);
$params['id'] = $this->pdo->lastInsertId();
return Hydrator::hydrate($params, $this->entity);
}
public function addRow(BasketEntity $basket, Product $product, int $quantity = 1): BasketRow
{
$params = [
'basket_id' => $basket->getId(),
'product_id' => $product->getId(),
'quantity' => $quantity
];
$this->basketRowTable->insert($params);
$params['id'] = $this->pdo->lastInsertId();
/** @var BasketRow $row */
$row = Hydrator::hydrate($params, $this->basketRowTable->getEntity());
$row->setProduct($product);
return $row;
}
public function updateRowQuantity(BasketRow $row, int $quantity): BasketRow
{
$this->basketRowTable->update($row->getId(), ['quantity' => $quantity]);
$row->setQuantity($quantity);
return $row;
}
public function deleteRow(BasketRow $row): void
{
$this->basketRowTable->delete($row->getId());
}
public function findRows(BasketEntity $basketEntity): array
{
return $this->basketRowTable
->makeQuery()
->where("basket_id = {$basketEntity->getId()}")
->fetchAll()
->toArray();
}
public function deleteRows(\App\Basket\Entity\Basket $basket)
{
return $this->pdo->exec('DELETE FROM baskets_products WHERE basket_id = ' . $basket->getId());
}
}
<?php if (strpos($_SERVER['HTTP_USER_AGENT'], "Firefox") !== false): ?>
<p>Hé, vous utilisez Firefox !<p>
<?php endif; ?>
<?php $posts = mysqli_num_rows(mysqli_query($conn, 'SELECT * FROM wp_posts'));
<?php if ($posts === 0): ?>
<p>Désolé, cette ligne n'existe pas<p>
<?php else: ?>
<p>Bienvenue !<p>
<p>Vous avez écrit <?= $posts; ?> articles !
<?php endif; ?>
Ce n'est pas un vrai* langage
*réservé au débutant
<?php
session_start();
if (!isset($_SESSION['id'])) {
die('Accès interdit');
}
$conn = mysqli_connect("127.0.0.1", "my_user", "my_password", "my_db")
$sql = 'SELECT * FROM articles WHERE user_id = ' . $_SESSION['id'];
$posts = mysqli_num_rows(mysqli_query($conn, $sql));
include 'header.php';
?>
<h1>Bonjour <?= $_SESSION['username']; ?></h1>
<p><a href="posts.php">Voir mes <?= $posts; ?> articles</a></p>
<?php include 'footer.php'; ?>
<?php
namespace App\Controller;
use App\Entity\Contact;
use App\Form\ContactType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use TijsVerkoyen\CssToInlineStyles\CssToInlineStyles;
class ContactController extends Controller
{
/**
* @param Request $request
* @param \Swift_Mailer $mailer
* @return mixed
*/
public function index(Request $request, \Swift_Mailer $mailer)
{
$contact = new Contact();
$contact->setBirthday((new \DateTime())->modify('first day of january')->modify('-20 years'));
$form = $this
->createForm(ContactType::class, $contact)
->add('save', SubmitType::class, array('label' => "M'inscrire"));
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$data = $contact->fromForm($form);
$inliner = new CssToInlineStyles();
$message = (new \Swift_Message('Inscription'))
->setFrom('site@site.fr')
->setTo('contact@site.fr')
->setBody(
$inliner->convert(
$this->renderView('emails/signup.html.twig',compact('data'))
),
'text/html'
);
$mailer->send($message);
return $this->render('contact/success.html.twig');
}
return $this->render('contact/index.html.twig', [
'form' => $form->createView()
]);
}
}
PHP c'est "lent"
il doit lire tous les fichiers à chaque requêtes
http://monsite.fr/demo.php
PHP FPM
Apache mod
Source : https://engineering.facile.it/blog/eng/realpath-cache-is-it-all-php-opcache-s-fault/
PHP est surprenant*
*inconsistant
Plus d'informations : PHP: a fractal of bad design
(certains points ne sont plus d'actualité)
<?php
namespace App\Controller;
use App\Entity\Contact;
use App\Form\ContactType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use TijsVerkoyen\CssToInlineStyles\CssToInlineStyles;
class ContactController extends Controller
{
/**
* @param Request $request
* @param \Swift_Mailer $mailer
* @return mixed
*/
public function index(Request $request, \Swift_Mailer $mailer)
{
$contact = new Contact();
$contact->setBirthday((new \DateTime())->modify('first day of january')->modify('-20 years'));
$form = $this
->createForm(ContactType::class, $contact)
->add('save', SubmitType::class, array('label' => "M'inscrire"));
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$data = $contact->fromForm($form);
$inliner = new CssToInlineStyles();
$message = (new \Swift_Message('Inscription'))
->setFrom('site@site.fr')
->setTo('contact@site.fr')
->setBody(
$inliner->convert(
$this->renderView('emails/signup.html.twig',compact('data'))
),
'text/html'
);
$mailer->send($message);
return $this->render('contact/success.html.twig');
}
return $this->render('contact/index.html.twig', [
'form' => $form->createView()
]);
}
}
// underscore ou pas ?
base64_encode/urlencode
// to ou 2 ?
bin2hex(), deg2rad(), strtolower(), strtotime()
// Ordre des arguments
array_filter($input, $callback);
array_map($callback, $input);
strpos($haystack, $needle);
array_search($needle, $haystack);
// Souvent plusieurs options pour faire la même chose
/*
mysqli ou PDO ?
(new DateTime()) ou date_modify()
https://secure.php.net/manual/en/refs.xml.php
*/
Les fonctions
var_dump("6" == " 6"); // true
var_dump("foo" == 0); // true
var_dump(NULL < -1); // true
var_dump(NULL == 0); // true
Typage faible
$var; // null
global $var; // Les variables sont locales par défaut
// Les variables prennent en compte la casse
$var = 0;
$vAr = 1;
// Mais pas les fonctions
vAr_DuMp($a);
Pas de déclaration de variables
<?php
echo strlen('Salut ☺'); // 9
echo mb_strlen('Salut ☺'); // 7
UTF-8 en option
PHP ne gère pas la concurrence
$contact = new Contact();
$contact->setBirthday((new \DateTime())->modify('first day of january')->modify('-20 years'));
$form = $this
->createForm(ContactType::class, $contact)
->add('save', SubmitType::class, array('label' => "M'inscrire"));
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$data = $contact->fromForm($form);
$inliner = new CssToInlineStyles();
$message = (new \Swift_Message('Inscription'))
->setFrom('site@site.fr')
->setTo('contact@site.fr')
->setBody(
$inliner->convert(
$this->renderView('emails/signup.html.twig',compact('data'))
),
'text/html'
);
$mailer->send($message);
return $this->render('contact/success.html.twig');
}
return $this->render('contact/index.html.twig', [
'form' => $form->createView()
]);
Plus d'informations : La concurrence sur PHP / NodeJS / Golang / Erlang
PHP est synchrone
PHP est synchrone
mais pas son modèle d'éxécution
(PHP-FPM / Apache)
<?php
class WorkerThread extends Thread {
public function __construct($i){
$this->i = $i;
}
public function run(){
while(true){
echo $this->i;
sleep(1);
}
}
}
for($i=0;$i<50;$i++){
$workers[$i] = new WorkerThread($i);
$workers[$i]->start();
}
pthreads
$loop = React\EventLoop\Factory::create();
$server = new React\Http\Server(function (Psr\Http\Message\ServerRequestInterface $request) {
return new React\Http\Response(
200,
array('Content-Type' => 'text/plain'),
"Hello World!\n"
);
});
$socket = new React\Socket\Server(8080, $loop);
$server->listen($socket);
echo "Server running at http://127.0.0.1:8080\n";
$loop->run();
ReactPHP
Files d'attente
PHP c'est mort
{NodeJS|Golang|Elixir...} c'est mieux
Vraiment ?
- 2012 - Composer / PSR
- 2015 - PHP 7.0
- Novembre 2017 - Symfony 4
- Février 2018 - PHP 7.2
- Février 2018 - Laravel 5.6
Mais au final ?
Est-ce qu'on s'en fout pas un peu ?