PHP – Jongler avec les dates

Lors de mes recherches pour une modification de WordPress, je suis tombé par hasard dans la documentation de PHP sur la fonction date_parse_from_format(). Cette fonction propose de décomposer une date à partir de sa représentation en chaîne de caractères. Cependant, à la différence de strtotime(), il est possible de passer en paramètre le format de la date à décomposer. Il est donc désormais possible de retrouver les éléments constitutifs d’une date (heure incluse) plus facilement qu’auparavant.

Exemple

Avant lorsque l’on souhaitait transposer une date SQL en date « française », on pouvait procéder comme suit :

$maDateSQL = '2011-07-18';
preg_match('/^(\d{4})-(\d{2})-(\d{2})$/', $maDateSQL, $regs);
$maDateFr = sprintf('%d/%d%d', $regs[3], $regs[2], $regs[1]);

Avec date_parse_from_format(), le code est tout de suite plus agréable à lire (de plus, certaines vérifications plus poussées sont effectuées au passage car le code ci-dessus ne vérifie que la présence de chiffres et pas leur cohérence) :

$maDateSQL = '2011-07-18';
$arr = date_parse_from_format('Y-m-d', $maDateSQL);
$maDateFr = sprintf('%d/%d/%d', $arr['day'], $arr['month'], $arr['year']);

Problème

Je disais précédemment qu’il était « désormais possible » d’utiliser cette fonction. A vrai dire, pas tout à fait. date_parse_from_format() n’est disponible qu’à partir de PHP 5.3 !

A vrai dire, lorsque l’on a la maîtrise de son hébergement, il s’agit d’un détail. Mais le passage à PHP 5.3 a des conséquences si l’on migre depuis la version 5.2 et tout le monde n’y est pas encore passé. De plus, lorsque l’on travaille avec un logiciel comme WordPress, massivement utilisé dans le monde, il faut pouvoir s’adapter au plus grand nombre et ne pas se limiter au haut du panier.

Résolution

Du coup, j’ai recodé la fonction directement en PHP et elle rend à peu près les mêmes résultats que la fonction native.

Le code source est disponible sous licence GPL version 2 et téléchargeable ici (requiert PHP 4.0.6 ou version ultérieure, c’est-à-dire à peu près tout le monde).

L’Open source ou la Vie

L’Open source donne un accès libre et illimité au code source d’un programme, avec la possibilité de le modifier, de le compléter et de le diffuser à sa guise. Cette approche diffère bien évidemment des choix propriétaires qui ont prédominé pendant les années 80 avec la domination notoire de Microsoft et de son Windows. La diffusion de logiciels libres a également profité de l’émergence d’internet dans les foyers et qui a permis de partager beaucoup plus vite des informations.

Cependant, contrairement à la pensée actuelle, l’Open source et la notion de code source partagé ont précédé les grandes sociétés de logiciels propriétaires puisque dès les années 1950, IBM fournissait le code source de ses logiciels aux clients qui investissait dans un ordinateur de la marque.

Deux visions s’opposent donc : la vision capitaliste (ou égoïste) ou la vision communautaire (ou altruiste).

La Vision Capitaliste

Les bases de cette approche sont simples : un développeur engage du temps, de l’argent et des ressources pour développer un logiciel. Celui-ci supporte donc l’ensemble des coûts tant financiers qu’humains de la création dudit logiciel et fait donc payer son client pour obtenir le droit d’utiliser son logiciel, avec pour objectif évident de vendre plus que ce que le développement aura coûté.

Dans le meilleur de cas, l’argent ainsi récolté sera réinvesti dans le logiciel lui-même pour lui assurer un avenir et un bon support tout en enrichissant ses propriétaires. Dans le pire des cas, l’avenir et le support seront oubliés.

Rappelons une chose importante à ce sujet. Lorsque vous acheté une boîte d’un logiciel (quel qu’il soit, logiciel bureautique ou même logiciel de jeu vidéo), vous ne devenez pas propriétaire du logiciel mais d’une licence vous autorisant à vous en servir. Le logiciel reste la propriété de son créateur, ou d’une entité physique ou morale qui en aura fait l’acquisition à un moment donné.

La notion de « propriétaire vendeur » induit nécessairement une notion de « client acheteur ». Une obligation de résultat du logiciel est également induite et si un logiciel propriétaire entraîne une perte avérée d’informations dommageable pour son utilisateur, le « client » peut éventuellement se retourner contre le « vendeur » pour réparation.

La Vision Communautaire

A l’opposée de la vision centrique capitaliste se situe la vision excentrique communautaire. La principale différence vient de la position du développeur par rapport au logiciel qu’il a créé. Ici aussi, un développeur décide d’investir du temps et des ressources (et donc de l’argent) pour créer un logiciel. Cependant, ce logiciel n’est pas nécessairement terminé ou débogué lorsqu’il est fourni au public sous une forme libre. En ouvrant son logiciel au monde, le développeur initial peut potentiellement créer une communauté d’autres développeurs si son concept intéresse du monde.

La chose la plus importante dans le monde de l’Open source est similaire au monde propriétaire. Il s’agit de la notion de licence. Un code libre ne veut pas dire qu’il n’y a aucun encadrement. Une des licences les plus connues, la General Public Licence (ou GPL) inclut dans ses clauses une propriété fondamentale pour l’essor du logiciel libre. Toute modification apportée à un code source libre doit être partagée selon les mêmes termes, et donc rendue libre également. Ce qui permet l’avancée de tous.

Mais alors comment gagne-t-on de l’argent dans le monde libre ? Plusieurs possibilités existent à ce niveau-là :

  • Vendre son logiciel libre
    La General Public Licence est une des rares (sinon la seule) licences à autoriser le diffuseur à vendre ou à revendre son code source libre. Mais comme le code source vendu doit être libre et que la licence autorise la rediffusion de façon gratuite, les sources d’accès payantes n’ont qu’un potentiel très limité. Pourquoi payer si l’on peut avoir un accès légal gratuit identique ?
  • Publier son code source selon plusieurs licences
    En tant que créateur ou originel, il est possible de publier son code source selon plusieurs licences différentes, comme par exemple une licence Open source (qui requiert donc que le logiciel qui sera déployé au final soit Open source lui aussi) et une licence commerciale (qui autorise les développeurs du logiciel suivant à ne pas diffuser leurs sources). C’est le cas notamment du framework Qt, actuellement propriété de Nokia, et utilisé notamment par le gestionnaire de bureau libre KDE.
  • Faire payer le support ou des services
    La notion d’Open source ne porte que sur la liberté d’accès au code source. Rien n’interdit le créateur de faire payer des services connexes comme le support technique pour faciliter l’intégration des outils. On retrouve dans ce cas des sociétés comme Canonical (créateurs d’Ubuntu) ou Red Hat.
  • Offrir un service amélioré
    Nous entrons aujourd’hui dans l’ère du « cloud« , autrement dit des services hébergés sur des sites internet plutôt que des applications installées directement sur nos ordinateurs. Différentes sociétés du monde Open source ont décidé d’embrasser ce mouvement en proposant des services gratuits utilisant leur propre logiciel mais avec des portions payantes pour les utilisateurs désirant aller plus loin. Dans ce cas, on ne paye pas le logiciel, mais simplement l’accessibilité à une partie du service hébergé. Un des exemples de réussite les plus récents reste la plate-forme WordPress.com sur laquelle est hébergée ce blog.
  • Les donations directes

Un Logiciel Libre doit-il rester Gratuit pour ses Utilisateurs ?

La question est large, mais la réponse est oui. La gratuité est la meilleure forme d’égalité et permet l’accès à tous aux mêmes services. Cela garantit donc en partie la neutralité que l’on commence à exiger aujourd’hui d’internet.

Cependant, que penser du fait que des sociétés gagnent de l’argent en utilisant des logiciels libres sans reverser quoi que ce soit aux créateurs originaux ? Cela fait partie du jeu du logiciel libre. Diffuser son code source sous cette forme implique que n’importe qui pourra s’en servir sans compensation.

Il existe cependant des moyens de remercier les auteurs de logiciels libres sans pour autant systématiquement parler d’argent. Voici la liste des actions que j’ai personnellement entamées sur différents projets :

  • depuis plusieurs années, je contribue à la traduction française de TortoiseSVN
  • j’ai effectué une donation pour le logiciel CyberDuck
  • j’aide à la résolution de bugs sur différents plugins WordPress

Cet article a été motivé par ma décision récente d’intégrer la communauté WordPress encore plus activement en tentant de corriger des bugs du logiciel principal et en proposant de nouvelles fonctionnalités.

Tous les projets auxquels j’ai contribué sont tous des logiciels que j’utilise intensivement dans mon travail et/ou dans mes loisirs. Après plusieurs années d’utilisation à sens unique, il m’est apparu important de renvoyer la balle et j’engage tous les développeurs et créateurs motivés à en faire de même pour ces projets et bien sûr pour d’autres

Benchmarking PHP – Partie 2

Voici la suite du premier article de cette série sur les performances de PHP.

Je me suis intéressé cette fois-ci à un autre « côté pervers » des langages de scripting tels que PHP, à savoir leur aspect faiblement typé.

En programmation, deux tendances s’opposent : le typage fort (ou typage strict) et le typage faible. Comme son nom le laisse entendre, le typage se rapporte aux types de données utilisés couramment : nombre entiers, nombres réels, chaînes de caractères, etc…

Dans un langage fortement typé, les fonctions ne peuvent être appelées qu’avec les types de données pour lesquels elles ont été conçues. Si une fonction requiert que son premier paramètre soit en entier, vous obtiendrez une erreur de compilation si vous essayez de lui envoyer une chaîne de caractères.

La plupart des langage de scripting sont, quant à eux, faiblement typés, c’est-à-dire, qu’il est possible d’appeler des fonctions avec un autre type de données que celui avec lequel elles ont été conçues. Dans certains cas, comme JavaScript ou PHP avant sa version 5, les paramètres de fonction n’ont même pas de type, uniquement un nom. Cela simplifie la programmation mais complique le débogage dans certains cas, notamment avec les objets. Avec l’arrivée de PHP 5, il est possible d’appliquer un typage fort sur certains paramètres de fonction. La raison principale de ce comportement est que les langages de scripting sont compilés au moment de leur exécution.

Etat des lieux

Dans le cas de PHP, c’est à sa capacité à traiter des chaînes de caractères comme des nombres que j’ai choisi de m’intéresser.

Le code suivant est parfaitement légal en PHP :

$a = 3;
$b = '4';
$c = $a + $b;

Le résultat sera bien 7.

Mais travailler avec des chaînes de caractères comme avec des entiers n’est-il pas plus long que de travailler directement avec des entiers ?
La réponse théorique est évidente, mais dans la pratique, certains éléments font que les choses ne sont pas si simples.

Le protocole de test

Pour ce test, j’ai choisi d’effectuer 1000 fois l’addition de tableaux d’entiers contenant :

  1. 100 000 entiers aléatoires natifs
  2. 100 000 entiers aléatoires sous forme de chaînes de caractères
  3. 100 000 entiers aléatoires sous forme de chaînes de caractères qui seront convertis « manuellement » au moment du traitement

Tous les entiers aléatoires sont compris entre 0 et 100 inclus.

Résultats

Les résultats sont évidents :

Somme de 100 000 entiers natifs (1000 itérations) : 2.017847 s
Somme de 100 000 entiers sous forme de strings (1000 itérations) : 9.314373 s
Somme de 100 000 entiers sous forme de strings convertis en natifs (1000 itérations) : 57.042635 s

Les entiers natifs sont les grands vainqueurs, avec un calcul plus de 4x plus rapide que les entiers sous forme de chaîne de caractères.

J’ai poussé les tests avec des entiers compris entre 0 et 1 000 000. Les résultats montrent que la longueur des chaînes de caractères (plus le nombre est grand, plus la chaîne est longue) influent sur les performances globales. Dans le cas présent, les entiers natifs sont presque 6x plus rapide que les chaînes de caractères.

Somme de 100 000 entiers natifs (1000 itérations) : 2.561392 s
Somme de 100 000 entiers sous forme de strings (1000 itérations) : 12.046772 s
Somme de 100 000 entiers sous forme de strings convertis en natifs (1000 itérations) : 55.341405 s

PHP incite-t-il à l’usage des chaînes de caractères ?

A vrai dire, cela n’est pas le cas. Le typage faible de PHP permet cette utilisation aberrante des chaînes de caractères, mais rien dans son fonctionnement ne force à aller dans ce sens. En revanche, l’utilisation de PHP avec MySQL incite fortement à ce comportement.

Les extensions de PHP qui permettent de communiquer avec MySQL présentent une étrangeté. Toutes les valeurs retournées par MySQL lors d’une requête (exceptée NULL) sont des chaînes de caractères, que le champ original contienne un entier ou bien tout à fait autre chose. Du coup, ce que montre ce test, c’est que nous gagnerions beaucoup à ce que MySQL permette de renvoyer à PHP les types natifs de ses champs, mais aujourd’hui aucune possibilité à ma connaissance n’est proposée dans ce sens (que ce soit du côté de MySQL ou de PHP).

Mais alors pourquoi vouloir utiliser des entiers natifs ?

Il y a quelques cas que j’ai rencontrés personnellement, récemment, où l’utilisation d’entiers natifs a son avantage. Le plus courant est l’encodage JSON, qui permet de faire transiter de manière simplifiée des données.

Considérons les deux alternatives que sont un tableau d’entiers sous forme de chaînes de caractères (A) et le même tableau sous forme d’entiers (B), voilà ce qui ressort en JSON :

A = ["1","2","3","4","5"]
B = [1,2,3,4,5]

Vous pourrez constater deux choses :

  1. les nombres sont entourés de guillemets (« ) pour indiquer à JSON qu’il s’agit de chaînes de caractères et donc le résultat encodé en JSON est plus long
  2. lorsque ces informations encodées en JSON vont être décodées de l’autre côté, ce sont des chaînes de caractères qui vont être générées. Si le destinataire est un langage faiblement typé, tout va bien, mais s’il s’agit d’un langage fortement typé comme Java, attention aux dégâts.

Astuce : convertir des chaînes en entiers

Voilà un petit code source très sommaire mais qui résume à lui seul la méthode à employer pour convertir un tableau d’entiers sous forme de chaînes de caractères en tableau d’entiers natifs :

$tableau = array('1', '2', '3');
$tableau_natifs = array_map('intval', $tableau);

Code du test

<?php
    header('Content-type: text/plain; charset=UTF-8');
    set_time_limit(0);

    // Construction du tableau d'entiers natifs
    $intArray = array();
    for ($i = 0; $i < 100000; $i++)
        $intArray[] = mt_rand(0, 1000000);

    // Construction du tableau d'entiers sous forme de strings
    $strArray = array_map('strval', $intArray);

    // Temps de calcul avec le tableau d'entiers natifs
    $debut = microtime(true);
    for ($i = 0; $i < 1000; $i++)
        array_sum($intArray);
    $elapsed = microtime(true) - $debut;
    printf("Somme de 100 000 floats natifs (1000 itérations) : %f s\n\n", $elapsed);

    // Temps de calcul avec le tableau d'entiers sous forme de strings
    $debut = microtime(true);
    for ($i = 0; $i < 1000; $i++)
        array_sum($strArray);
    $elapsed = microtime(true) - $debut;
    printf("Somme de 100 000 floats sous forme de strings (1000 itérations) : %f s\n\n", $elapsed);

    // Temps de calcul avec le tableau d'entiers sous forme de strings avec conversion vers entiers natifs
    $debut = microtime(true);
    for ($i = 0; $i < 1000; $i++)
        array_sum(array_map('intval', $strArray));
    $elapsed = microtime(true) - $debut;
    printf("Somme de 100 000 floats sous forme de strings convertis en natifs (1000 itérations) : %f s\n\n", $elapsed);
?>