1<?php 2 3use function releases\php83\common_header; 4use function releases\php83\language_chooser; 5use function releases\php83\message; 6 7if (!isset($lang)) { 8 $lang = 'en'; 9} 10 11$_SERVER['BASE_PAGE'] = 'releases/8.3/' . $lang . '.php'; 12 13include_once __DIR__ . '/common.php'; 14 15common_header(message('common_header', $lang)); 16 17?> 18 <section class="php8-section php8-section_dark php8-section_header center"> 19 <div class="page-tools"> 20 <div class="change-language"> 21 <?php language_chooser($lang); ?> 22 </div> 23 </div> 24 <div class="php8-section__content"> 25 <div class="php8-logo"> 26 <img src="/images/php8/logo_php8_3.svg" alt="PHP 8.3" height="126" width="343"> 27 </div> 28 <div class="php8-title"><?= message('main_title', $lang) ?></div> 29 <div class="php8-subtitle"><?= message('main_subtitle', $lang) ?></div> 30 <div class="php8-button-wrapper center"> 31 <a class="php8-button php8-button_light" href="/downloads"><?= message('upgrade_now', $lang) ?></a> 32 </div> 33 </div> 34 </section> 35 36 <section class="php8-section center"> 37 <div class="php8-compare"> 38 <h2 class="php8-h2" id="typed_class_constants"> 39 <?= message('typed_class_constants_title', $lang) ?> 40 <a class="php8-rfc" href="https://wiki.php.net/rfc/typed_class_constants">RFC</a> 41 </h2> 42 <div class="php8-compare__main"> 43 <div class="php8-compare__block example-contents"> 44 <div class="php8-compare__label">PHP < 8.3</div> 45 <div class="php8-code phpcode"> 46 <?php highlight_php_trimmed( 47 <<<'PHP' 48interface I { 49 // We may naively assume that the PHP constant is always a string. 50 const PHP = 'PHP 8.2'; 51} 52 53class Foo implements I { 54 // But implementing classes may define it as an array. 55 const PHP = []; 56} 57PHP 58 59 ); ?> 60 </div> 61 </div> 62 <div class="php8-compare__arrow"></div> 63 <div class="php8-compare__block example-contents"> 64 <div class="php8-compare__label php8-compare__label_new">PHP 8.3</div> 65 <div class="php8-code phpcode"> 66 <?php highlight_php_trimmed( 67 <<<'PHP' 68interface I { 69 const string PHP = 'PHP 8.3'; 70} 71 72class Foo implements I { 73 const string PHP = []; 74} 75 76// Fatal error: Cannot use array as value for class constant 77// Foo::PHP of type string 78PHP 79 ); ?> 80 </div> 81 </div> 82 </div> 83 </div> 84 85 <div class="php8-compare"> 86 <h2 class="php8-h2" id="dynamic_class_constant_fetch"> 87 <?= message('dynamic_class_constant_fetch_title', $lang) ?> 88 <a class="php8-rfc" href="https://wiki.php.net/rfc/dynamic_class_constant_fetch">RFC</a> 89 </h2> 90 <div class="php8-compare__main"> 91 <div class="php8-compare__block example-contents"> 92 <div class="php8-compare__label">PHP < 8.3</div> 93 <div class="php8-code phpcode"> 94 <?php highlight_php_trimmed( 95 <<<'PHP' 96class Foo { 97 const PHP = 'PHP 8.2'; 98} 99 100$searchableConstant = 'PHP'; 101 102var_dump(constant(Foo::class . "::{$searchableConstant}")); 103PHP 104 105 ); ?> 106 </div> 107 </div> 108 <div class="php8-compare__arrow"></div> 109 <div class="php8-compare__block example-contents"> 110 <div class="php8-compare__label php8-compare__label_new">PHP 8.3</div> 111 <div class="php8-code phpcode"> 112 <?php highlight_php_trimmed( 113 <<<'PHP' 114class Foo { 115 const PHP = 'PHP 8.3'; 116} 117 118$searchableConstant = 'PHP'; 119 120var_dump(Foo::{$searchableConstant}); 121PHP 122 ); ?> 123 </div> 124 </div> 125 </div> 126 </div> 127 128 <div class="php8-compare"> 129 <h2 class="php8-h2" id="override_attribute"> 130 <?= message('override_title', $lang) ?> 131 <a class="php8-rfc" href="https://wiki.php.net/rfc/marking_overriden_methods">RFC</a> 132 </h2> 133 <div class="php8-compare__main"> 134 <div class="php8-compare__block example-contents"> 135 <div class="php8-compare__label">PHP < 8.3</div> 136 <div class="php8-code phpcode"> 137 <?php highlight_php_trimmed( 138 <<<'PHP' 139use PHPUnit\Framework\TestCase; 140 141final class MyTest extends TestCase { 142 protected $logFile; 143 144 protected function setUp(): void { 145 $this->logFile = fopen('/tmp/logfile', 'w'); 146 } 147 148 protected function taerDown(): void { 149 fclose($this->logFile); 150 unlink('/tmp/logfile'); 151 } 152} 153 154// The log file will never be removed, because the 155// method name was mistyped (taerDown vs tearDown). 156PHP 157 158 ); ?> 159 </div> 160 </div> 161 <div class="php8-compare__arrow"></div> 162 <div class="php8-compare__block example-contents"> 163 <div class="php8-compare__label php8-compare__label_new">PHP 8.3</div> 164 <div class="php8-code phpcode"> 165 <?php highlight_php_trimmed( 166 <<<'PHP' 167use PHPUnit\Framework\TestCase; 168 169final class MyTest extends TestCase { 170 protected $logFile; 171 172 protected function setUp(): void { 173 $this->logFile = fopen('/tmp/logfile', 'w'); 174 } 175 176 #[\Override] 177 protected function taerDown(): void { 178 fclose($this->logFile); 179 unlink('/tmp/logfile'); 180 } 181} 182 183// Fatal error: MyTest::taerDown() has #[\Override] attribute, 184// but no matching parent method exists 185PHP 186 ); ?> 187 </div> 188 </div> 189 </div> 190 191 <div class="php8-compare__content"> 192 <?= message('override_description', $lang) ?> 193 </div> 194 </div> 195 196 <div class="php8-compare"> 197 <h2 class="php8-h2" id="readonly_classes"> 198 <?= message('readonly_title', $lang) ?> 199 <a class="php8-rfc" href="https://wiki.php.net/rfc/readonly_amendments">RFC</a> 200 </h2> 201 <div class="php8-compare__main"> 202 <div class="php8-compare__block example-contents"> 203 <div class="php8-compare__label">PHP < 8.3</div> 204 <div class="php8-code phpcode"> 205 <?php highlight_php_trimmed( 206 <<<'PHP' 207class PHP { 208 public string $version = '8.2'; 209} 210 211readonly class Foo { 212 public function __construct( 213 public PHP $php 214 ) {} 215 216 public function __clone(): void { 217 $this->php = clone $this->php; 218 } 219} 220 221$instance = new Foo(new PHP()); 222$cloned = clone $instance; 223 224// Fatal error: Cannot modify readonly property Foo::$php 225PHP 226 227 ); ?> 228 </div> 229 </div> 230 <div class="php8-compare__arrow"></div> 231 <div class="php8-compare__block example-contents"> 232 <div class="php8-compare__label php8-compare__label_new">PHP 8.3</div> 233 <div class="php8-code phpcode"> 234 <?php highlight_php_trimmed( 235 <<<'PHP' 236class PHP { 237 public string $version = '8.2'; 238} 239 240readonly class Foo { 241 public function __construct( 242 public PHP $php 243 ) {} 244 245 public function __clone(): void { 246 $this->php = clone $this->php; 247 } 248} 249 250$instance = new Foo(new PHP()); 251$cloned = clone $instance; 252 253$cloned->php->version = '8.3'; 254PHP 255 ); ?> 256 </div> 257 </div> 258 </div> 259 <div class="php8-compare__content"> 260 <?= message('readonly_description', $lang) ?> 261 </div> 262 </div> 263 264 <div class="php8-compare"> 265 <h2 class="php8-h2" id="json_validate"> 266 <?= message('json_validate_title', $lang) ?> 267 <a class="php8-rfc" href="https://wiki.php.net/rfc/json_validate">RFC</a> 268 <a class="php8-rfc" 269 href="/manual/<?= $lang ?>/function.json-validate.php"><?= message('documentation', $lang) ?></a> 270 </h2> 271 <div class="php8-compare__main"> 272 <div class="php8-compare__block example-contents"> 273 <div class="php8-compare__label">PHP < 8.3</div> 274 <div class="php8-code phpcode"> 275 <?php highlight_php_trimmed( 276 <<<'PHP' 277function json_validate(string $string): bool { 278 json_decode($string); 279 280 return json_last_error() === JSON_ERROR_NONE; 281} 282 283var_dump(json_validate('{ "test": { "foo": "bar" } }')); // true 284PHP 285 286 ); ?> 287 </div> 288 </div> 289 <div class="php8-compare__arrow"></div> 290 <div class="php8-compare__block example-contents"> 291 <div class="php8-compare__label php8-compare__label_new">PHP 8.3</div> 292 <div class="php8-code phpcode"> 293 <?php highlight_php_trimmed( 294 <<<'PHP' 295var_dump(json_validate('{ "test": { "foo": "bar" } }')); // true 296PHP 297 ); ?> 298 </div> 299 </div> 300 </div> 301 <div class="php8-compare__content"> 302 <?= message('json_validate_description', $lang) ?> 303 </div> 304 </div> 305 306 <div class="php8-compare"> 307 <h2 class="php8-h2" id="randomizer_get_bytes_from_string"> 308 <?= message('randomizer_getbytesfromstring_title', $lang) ?> 309 <a class="php8-rfc" href="https://wiki.php.net/rfc/randomizer_additions#getbytesfromstring">RFC</a> 310 <a class="php8-rfc" 311 href="/manual/<?= $lang ?>/random-randomizer.getbytesfromstring.php"><?= message('documentation', $lang) ?></a> 312 </h2> 313 <div class="php8-compare__main"> 314 <div class="php8-compare__block example-contents"> 315 <div class="php8-compare__label">PHP < 8.3</div> 316 <div class="php8-code phpcode"> 317 <?php highlight_php_trimmed( 318 <<<'PHP' 319// This function needs to be manually implemented. 320function getBytesFromString(string $string, int $length) { 321 $stringLength = strlen($string); 322 323 $result = ''; 324 for ($i = 0; $i < $length; $i++) { 325 // random_int is not seedable for testing, but secure. 326 $result .= $string[random_int(0, $stringLength - 1)]; 327 } 328 329 return $result; 330} 331 332$randomDomain = sprintf( 333 "%s.example.com", 334 getBytesFromString( 335 'abcdefghijklmnopqrstuvwxyz0123456789', 336 16, 337 ), 338); 339 340echo $randomDomain; 341PHP 342 343 ); ?> 344 </div> 345 </div> 346 <div class="php8-compare__arrow"></div> 347 <div class="php8-compare__block example-contents"> 348 <div class="php8-compare__label php8-compare__label_new">PHP 8.3</div> 349 <div class="php8-code phpcode"> 350 <?php highlight_php_trimmed( 351 <<<'PHP' 352// A \Random\Engine may be passed for seeding, 353// the default is the secure engine. 354$randomizer = new \Random\Randomizer(); 355 356$randomDomain = sprintf( 357 "%s.example.com", 358 $randomizer->getBytesFromString( 359 'abcdefghijklmnopqrstuvwxyz0123456789', 360 16, 361 ), 362); 363 364echo $randomDomain; 365PHP 366 ); ?> 367 </div> 368 </div> 369 </div> 370 371 <div class="php8-compare__content"> 372 <?= message('randomizer_getbytesfromstring_description', $lang) ?> 373 </div> 374 </div> 375 376 <div class="php8-compare"> 377 <h2 class="php8-h2" id="randomizer_get_float"> 378 <?= message('randomizer_getfloat_nextfloat_title', $lang) ?> 379 <a class="php8-rfc" href="https://wiki.php.net/rfc/randomizer_additions#getfloat">RFC</a> 380 <a class="php8-rfc" 381 href="/manual/<?= $lang ?>/random-randomizer.getfloat.php"><?= message('documentation', $lang) ?></a> 382 </h2> 383 <div class="php8-compare__main"> 384 <div class="php8-compare__block example-contents"> 385 <div class="php8-compare__label">PHP < 8.3</div> 386 <div class="php8-code phpcode"> 387 <?php highlight_php_trimmed( 388 <<<'PHP' 389// Returns a random float between $min and $max, both including. 390function getFloat(float $min, float $max) { 391 // This algorithm is biased for specific inputs and may 392 // return values outside the given range. This is impossible 393 // to work around in userland. 394 $offset = random_int(0, PHP_INT_MAX) / PHP_INT_MAX; 395 396 return $offset * ($max - $min) + $min; 397} 398 399$temperature = getFloat(-89.2, 56.7); 400 401$chanceForTrue = 0.1; 402// getFloat(0, 1) might return the upper bound, i.e. 1, 403// introducing a small bias. 404$myBoolean = getFloat(0, 1) < $chanceForTrue; 405PHP 406 407 ); ?> 408 </div> 409 </div> 410 <div class="php8-compare__arrow"></div> 411 <div class="php8-compare__block example-contents"> 412 <div class="php8-compare__label php8-compare__label_new">PHP 8.3</div> 413 <div class="php8-code phpcode"> 414 <?php highlight_php_trimmed( 415 <<<'PHP' 416$randomizer = new \Random\Randomizer(); 417 418$temperature = $randomizer->getFloat( 419 -89.2, 420 56.7, 421 \Random\IntervalBoundary::ClosedClosed, 422); 423 424$chanceForTrue = 0.1; 425// Randomizer::nextFloat() is equivalent to 426// Randomizer::getFloat(0, 1, \Random\IntervalBoundary::ClosedOpen). 427// The upper bound, i.e. 1, will not be returned. 428$myBoolean = $randomizer->nextFloat() < $chanceForTrue; 429PHP 430 ); ?> 431 </div> 432 </div> 433 </div> 434 </div> 435 436 <div class="php8-compare__content"> 437 <?= message('randomizer_getfloat_nextfloat_description', $lang) ?> 438 </div> 439 440 <div class="php8-compare"> 441 <h2 class="php8-h2" id="command_line_linter"> 442 <?= message('command_line_linter_title', $lang) ?> 443 <a class="php8-rfc" href="https://github.com/php/php-src/issues/10024">PR</a> 444 <a class="php8-rfc" href="/manual/<?= $lang ?>/features.commandline.options.php"><?= message('documentation', $lang) ?></a> 445 </h2> 446 <div class="php8-compare__main"> 447 <div class="php8-compare__block example-contents"> 448 <div class="php8-compare__label">PHP < 8.3</div> 449 <div class="php8-code phpcode"> 450 <code> 451php -l foo.php bar.php 452No syntax errors detected in foo.php 453 </code> 454 </div> 455 </div> 456 <div class="php8-compare__arrow"></div> 457 <div class="php8-compare__block example-contents"> 458 <div class="php8-compare__label php8-compare__label_new">PHP 8.3</div> 459 <div class="php8-code phpcode"> 460 <code> 461php -l foo.php bar.php 462No syntax errors detected in foo.php 463No syntax errors detected in bar.php 464 </code> 465 </div> 466 </div> 467 </div> 468 </div> 469 470 <div class="php8-compare__content"> 471 <?= message('command_line_linter_description', $lang) ?> 472 </div> 473 474 475 </section> 476 477 <section class="php8-section center php8-section_light php8-columns"> 478 <div class="php8-column"> 479 <h2 class="php8-h2" id="other_new_things"><?= message('new_classes_title', $lang) ?></h2> 480 <div class="php8-compare__content php8-compare__content--block"> 481 <ul> 482 <li><?= message('new_dom', $lang) ?></li> 483 <li><?= message('new_intl', $lang) ?></li> 484 <li><?= message('new_ldap', $lang) ?></li> 485 <li><?= message('new_mb_str_pad', $lang) ?></li> 486 <li><?= message('new_posix', $lang) ?></li> 487 <li><?= message('new_reflection', $lang) ?></li> 488 <li><?= message('new_socket', $lang) ?></li> 489 <li><?= message('new_str', $lang) ?></li> 490 <li><?= message('new_ziparchive', $lang) ?></li> 491 <li><?= message('new_openssl_ec', $lang) ?></li> 492 <li><?= message('new_ini', $lang) ?></li> 493 <li><?= message('ini_fallback', $lang) ?></li> 494 <li><?= message('anonymous_readonly', $lang) ?></li> 495 </ul> 496 </div> 497 </div> 498 499 <div class="php8-column"> 500 <h2 class="php8-h2" id="deprecations_and_bc_breaks"><?= message('bc_title', $lang) ?></h2> 501 <div class="php8-compare__content"> 502 <ul> 503 <li><?= message('bc_datetime', $lang) ?></li> 504 <li><?= message('bc_arrays', $lang) ?></li> 505 <li><?= message('bc_range', $lang) ?></li> 506 <li><?= message('bc_traits', $lang) ?></li> 507 <li><?= message('bc_umultipledecimalseparators', $lang) ?></li> 508 <li><?= message('bc_mtrand', $lang) ?></li> 509 <li><?= message('bc_reflection', $lang) ?></li> 510 <li><?= message('bc_ini', $lang) ?></li> 511 <li><?= message('bc_standard', $lang) ?></li> 512 <li><?= message('bc_sqlite3', $lang) ?></li> 513 </ul> 514 </div> 515 </div> 516 </section> 517 518 <section class="php8-section php8-section_dark php8-section_footer php8-footer"> 519 <div class="php8-section__content"> 520 <h2 class="php8-h2 center"><?= message('footer_title', $lang) ?></h2> 521 <div class="php8-button-wrapper center"> 522 <a class="php8-button php8-button_light" href="/downloads"><?= message('upgrade_now', $lang) ?></a> 523 </div> 524 <div class="php8-footer__content"><?= message('footer_description', $lang) ?></div> 525 </div> 526 </section> 527 528<?php 529 530site_footer(); 531