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
<!--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()
]);

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 ?

PHP​ "C'est de la merde"

By Jonathan Boyer

PHP​ "C'est de la merde"

  • 33,628