xref: /web-php/releases/8.3/release.inc (revision 9b12309e)
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 &lt; 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 &lt; 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 &lt; 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 &lt; 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 &lt; 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 &lt; 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 &lt; 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 &lt; 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