Ce guide présente une comparaison de la syntaxe entre PHP (5.6 minimum) et JavaScript (ES2020 minimum).
Vous trouverez d’autres guides et une explication plus générale ici.
Déclarations des données
En JavaScript, les variables doivent être déclarées. Depuis l’ES6, utilisez seulement l’instruction let
.
L’ES6 a introduit les constantes en JavaScript. Des valeurs complexes peuvent être utilisées et donc manipulées.
|
<?php |
|
const MY_DATA = 'php'; |
|
const MY_USER = new User(); // Error |
|
const MY_DATA = 'js'; |
|
const MY_USER = new User(); // OK |
|
MY_USER.name = 'New name'; |
Types de données simples
|
<?php |
|
$userMan = true; |
|
$userAge = 81; |
|
$userAverage = 10.5; |
|
$userName = 'Henri Bergson'; |
|
let userMan = true; |
|
let userAge = 81; |
|
let userAverage = 10.5; |
|
let userName = 'Henri Bergson'; |
En plus de null
, JavaScript contient le type undefined
, et NaN
(Not a Number). Ce sont des erreurs, ne les utilisez donc pas.
Détails sur les chaînes de caractères
En JavaScript, les sauts de ligne ne sont pas autorisés avec les guillemets simples ou doubles.
L’ES6 a introduit les template literals : de nouveaux guillemets, les backticks, pour l’interpolation des variables et dans lesquels les sauts de ligne sont autorisés (les mêmes qu’on utilise en PHP dans les requêtes MySQL). Soyez vigilants avec la position des accolades et leur rôle : en PHP, elles permettent d’isoler les variables pour éviter les confusions, en JavaScript, elles permettent d’insérer une expression.
|
<?php |
|
$userFullName = "{$userFirstName} {$userLastName}"; |
|
let userFullName = `${userFirstName} ${userLastName}`; |
C’est aussi pratique pour gérer les guillemets simples et doubles dans une même chaîne.
|
let HTMLTemplate = `<p class="content">My name's Henri !</p>`; |
En JavaScript, privilégiez les backticks plutôt que la concaténation, qui porte à confusion avec les additions et peut conduire à des erreurs.
Listes de données
En JavaScript, les tableaux sont seulement des listes indexées numériquement. Ils sont passés par référence.
|
<?php |
|
$userBooks = ['Book 1', 'Book 2']; |
|
$userBooks[0]; |
|
count($userBooks); |
|
$userBooks[] = 'Book 3'; |
|
let userBooks = [`Book 1`, `Book 2`]; |
|
userBooks[0]; |
|
userBooks.length; |
|
userBooks.push(`Book 3`); |
L’équivalent des tableaux associatifs en PHP sont appelés des objets en JavaScript.
|
<?php |
|
$user = [ |
|
'firstName' => 'Henri', |
|
'lastName' => 'Bergson' |
|
]; |
|
$user['firstName']; |
|
let user = { |
|
firstName: `Henri`, |
|
lastName: `Bergson` |
|
}; |
|
user.firstName; |
Décomposition
L’ES6 permet de déstructurer les tableaux, c’est-à-dire extraire les valeurs dans différentes variables.
|
<?php |
|
$myList = [1, 2, 3]; |
|
|
|
/* PHP 5+ */ |
|
list($data1, $data2, $data3) = $myList; |
|
|
|
/* PHP 7.1+ */ |
|
[$data1, $data2, $data3] = $myList; |
|
let myList = [1, 2, 3]; |
|
let [data1, data2, data3] = myList; |
Lié à cette façon de faire, l’opérateur spread permet de diffuser les valeurs d’un tableau en plusieurs valeurs successives, comme c’est aussi possible depuis PHP 5.6.
|
<?php |
|
$myOptions = [1, 2]; |
|
function test($option1, $option2) {} |
|
test(…$myOptions); |
|
|
|
$defaultConfig = ['data1', 'data2']; |
|
$userConfig = ['data3', 'data4']; |
|
$finalConfig = [ |
|
...$defaultConfig, |
|
...$userConfig |
|
]; |
|
let myOptions = [1, 2]; |
|
function test(option1, option2) {} |
|
test(…myOptions); |
|
|
|
let defaultConfig = ['data1', 'data2']; |
|
let userConfig = ['data3', 'data4']; |
|
let finalConfig = [ |
|
…defaultConfig, |
|
…userConfig |
|
]; |
On peut aussi décomposer des objets de façon similaire, nouveauté qui est également apparue en PHP 7.1.
|
<?php |
|
$user = [ |
|
'firstName' => 'Henri', |
|
'lastName' => 'Bergson' |
|
]; |
|
|
|
/* PHP 7.1+ */ |
|
['firstName' => $myName] = $user; // ou list('firstName' => $myName) = $user; |
|
$myName; // `Henri` |
|
let user = { |
|
firstName: `Henri`, |
|
lastName: `Bergson` |
|
}; |
|
|
|
let { firstName: myName } = user; |
|
myName; // `Henri` |
Souvent, vous voudrez créer une variable portant le même nom que la propriété. Auquel cas vous pouvez raccourcir à :
|
let user = { |
|
firstName: `Henri`, |
|
lastName: `Bergson` |
|
}; |
|
|
|
let { firstName } = user; |
|
firstName; // `Henri` |
Et si la propriété n’existe pas dans l’objet ? Vous pouvez prévoir une valeur par défaut.
|
let user = { |
|
firstName: `Henri`, |
|
lastName: `Bergson` |
|
}; |
|
|
|
let { firstName = `default`, age = 0 } = user; |
|
firstName; // `Henri` |
|
age; // 0 |
Blocs
En JavaScript, l’espace est obligatoire dans l’instruction else if
.
|
<?php |
|
if ($userAge > 18) {} |
|
elseif ($userAge > 21) {} |
|
if (userAge > 18) {} |
|
else if (userAge > 21) {} |
Comme en PHP, faites attention aux valeurs équivalentes à false
.
|
<?php |
|
$myData = $myData ?: 'default'; |
|
let myData = myData ?? 'default'; |
En JavaScript, l’instruction switch
fait des comparaisons strictes.
Depuis l’ES6, grâce à let
, la portée des variables se limite au bloc en cours.
|
<?php |
|
for ($i = 0; $i < 10; $i++) {} |
|
$i; // 10, error prone |
|
for (let i = 0; i < 10; i++) {} |
|
i; // undefined |
Les itérations sont simplifiées depuis l’ES6.
|
<?php |
|
foreach ($userBooks as $value) {} |
|
for (let value of userBooks) {} |
Une autre possibilité pour les itérations complexes (avec les valeurs et les index, seulement pour les tableaux).
|
<?php |
|
foreach ($userBooks as $key => $value) {} |
|
userBooks.forEach((value, index) => {}); |
Fonctions
En JavaScript, vous pouvez accéder aux portées parentes directement.
|
<?php |
|
$myData = 'php'; |
|
function myMethod() { |
|
$myData; // null |
|
} |
|
let myData = 'js'; |
|
function myMethod() { |
|
myData; // 'js' |
|
} |
En JavaScript, les paramètres sont toujours facultatifs. L’ES6 a introduit la possibilité de préciser des valeurs par défaut.
|
<?php |
|
function myMethod($required, $optional = 'default') {} |
|
myMethod(); // Error |
|
function myMethod(optional1, optional2 = 'default') {} |
|
myMethod(); // OK |
Ce problème est réglé en TypeScript :
Vous pouvez aussi avoir un nombre indéfini de paramètres.
|
<?php |
|
|
|
function myArrayPush(…$values) { |
|
foreach ($values as $value) {} |
|
} |
|
myArrayPush(1, 2, 3); |
|
function myArrayPush(…values) { |
|
for (let value of values) {} |
|
} |
|
myArrayPush(1, 2, 3); |
Arrow functions
L’ES6 a introduit une syntaxe raccourcie pour les fonctions anonymes, appelée arrow functions. Utilisez-la systématiquement, car elle règle aussi un problème de contexte spécifique à JavaScript.
|
<?php |
|
array_map(function ($value) { |
|
return $value * 2; |
|
}, $numbersList); |
|
numbersList.map((value) => value * 2); |
Fonctions natives
Toutes les fonctions sont des méthodes en JavaScript, et sont donc appelées depuis un objet.
|
<?php |
|
mb_strpos($myEmail, '@'); |
|
str_replace('@', '[at]', $myEmail); |
|
mb_substr($myEmail, 0, 5); |
|
mb_strlen($myEmail); |
|
(int) '5'; |
|
array_key_exists('name', $user); |
|
in_array('Book 1', $userBooks); |
|
time(); |
|
var_dump($varToDebug); |
|
json_encode($user); |
|
json_decode('{}'); |
|
myEmail.indexOf('@'); |
|
myEmail.replace('@', '[at]'); |
|
myEmail.substr(0, 5); |
|
myEmail.length; |
|
Number.parseInt('5', 10); |
|
'name' in user; |
|
userBooks.includes(`Book 1`); |
|
Date.now(); |
|
console.log(varToDebug); |
|
JSON.stringify(user); |
|
try { |
|
JSON.parse('{}'); |
|
} catch (error) {} |
Quand une fonction semble être appelée directement, comme setTimeout()
, c’est parce que l’objet global est implicite : window.setTimeout()
.
Classes
L’ES6 a introduit la syntaxe des classes, pour simplifier la programmation orienté objet en JavaScript. Les propriétés sont déclarées directement dans le constructeur. Les propriétés pré-déclarées apparaîtront dans une prochaine version de JavaScript.
|
<?php |
|
class User { |
|
public $firstName; |
|
public function __construct($firstName) { |
|
$this->firstName = $firstName; |
|
} |
|
public function sayHello() {} |
|
} |
|
|
|
$myUser = new User('Henri'); |
|
$myUser->firstName; |
|
$myUser->sayHello(); |
|
class User { |
|
constructor(firstName) { |
|
this.firstName = firstName; |
|
} |
|
sayHello() {} |
|
} |
|
|
|
let myUser = new User(`Henri`); |
|
myUser.firstName; |
|
myUser.sayHello(); |
Lors d’un héritage en JavaScript, l’appel au constructeur parent est obligatoire dans le constructeur fils.
|
<?php |
|
class Editor extends User { |
|
public function __construct($firstName) { |
|
parent::__construct($firstName); |
|
} |
|
public function sayHello() { |
|
parent::sayHello(); |
|
} |
|
} |
|
class Editor extends User { |
|
constructor(firstName) { |
|
super(firstName); |
|
} |
|
sayHello() { |
|
super.sayHello(); |
|
} |
|
} |
Les getters et setters ont une syntaxe spéciale en JavaScript (mais vous pouvez aussi faire des accesseurs classiques). Ne pré-déclarez pas la propriété, JavaScript le fait automatiquement.
|
<?php |
|
class User { |
|
private $firstName; |
|
public function getFirstName() { |
|
return $this->firstName; |
|
} |
|
public function setFirstName($newFirstName) { |
|
$this->firstName = $newFirstName; |
|
} |
|
} |
|
|
|
$myUser = new User('Henri'); |
|
$myUser->getFirstName(); |
|
$myUser->setFirstName('New name'); |
|
class User { |
|
get firstName() { |
|
return this._firstName; |
|
} |
|
set firstName(newFirstName) { |
|
this._firstName = newFirstName; |
|
} |
|
} |
|
|
|
myUser = new User('Henri'); |
|
myUser.firstName; |
|
myUser.firstName = 'New name'; |
Contrairement à PHP, JavaScript n’a pas une syntaxe distincte pour l’accès aux méthodes statiques.
|
<?php |
|
class Utilities { |
|
public static function filter() {} |
|
} |
|
|
|
Utilities::filter(); |
|
class Utilities { |
|
static filter() {} |
|
} |
|
|
|
Utilities.filter(); |
Pour l’instant, il n’y a pas de modificateurs de visibilité, ni d’interfaces et de classes abstraites. Ils apparaîtront sans doute dans une prochaine version de JavaScript, mais TypeScript permet de les utiliser dès maintenant (voir notre guide de PHP 7 à TypeScript).
Namespaces
L’encapsulation est gérée directement par le système de chargement depuis l’ES6 : s’il y a l’instruction export
ou l’instruction import
, alors vous n’êtes plus en portée globale.
|
<?php |
|
// module.php |
|
namespace Symfony\Accounts; |
|
|
|
class User {} |
|
|
|
// script.php |
|
use Symfony\User\User; |
|
|
|
$myUser = new User(); |
|
// module.js |
|
export class User {} |
|
|
|
// script.js |
|
import { User } from './module.js'; |
|
|
|
let myUser = new User(); |
Poursuivre avec le guide de PHP 7 à TypeScript