[PRES] [presentations] master: AFUP talk
[email protected] (Derick Rethans) Tue, 30 Sep 2025 12:15:05 +0000
| Newsgroups | php.pres |
|---|---|
| Message-ID | <[email protected]> |
Author: Derick Rethans (derickr) Date: 2025-09-30T13:14:59+01:00 Commit: https://github.com/php/presentations/commit/5dfacc6b9c343c52e68a057b00fe7ddacd91d70b Raw diff: https://github.com/php/presentations/commit/5dfacc6b9c343c52e68a057b00fe7ddacd91d70b.diff AFUP talk Changed paths: A php-afup25.xml A slides/internals/abstain.png A slides/internals/php85-array-first-last.xml A slides/internals/php85-clone-with.xml A slides/internals/php85-deprecated-trait-attribute.xml A slides/internals/php85-error-backtraces.xml A slides/internals/php85-filter-throw.xml A slides/internals/php85-final-property-promotion.xml A slides/internals/php85-grapheme-add-locale.xml A slides/internals/php85-grapheme-levenstein3.xml A slides/internals/php85-opcache-required.xml A slides/internals/php85-pipes-debug.xml A slides/internals/php85-pipes-examples.xml A slides/internals/php85-url-parsing-api.xml A slides/internals/pie.jpg A slides/internals/policy-adopt-pie.xml A slides/internals/policy-vote-abstain.xml A templates/default/ordered-list.ezt M slides/internals/php85-pipes.xml Diff: diff --git a/php-afup25.xml b/php-afup25.xml new file mode 100644 index 00000000..d216f44f --- /dev/null +++ b/php-afup25.xml @@ -0,0 +1,115 @@ +<?xml version="1.0" encoding="utf-8"?> +<presentation css="derick.css"> +<topic>PHP</topic> +<title>What's New in PHP 8.5</title> +<event>Forum PHP 2025</event> +<location>Paris, France</location> +<date>October 9th, 2025</date> +<speaker>Derick Rethans</speaker> +<email>[email protected]</email> +<twitter>derickr</twitter> +<mastodon>@[email protected]</mastodon> +<url>https://derickrethans.nl/talks/php-afup25</url> +<joindin></joindin> +<slide>slides/xdebug/title.xml</slide> +<slide>slides/mongodb/me.xml</slide> + + +Syntax: + +https://wiki.php.net/rfc/closures_in_const_expr +<slide>slides/internals/php85-closures-in-constant-expressions.xml</slide> + +https://wiki.php.net/rfc/fcc_in_const_expr +<slide>slides/internals/php85-fcc-in-constant-expressions.xml</slide> + +https://wiki.php.net/rfc/pipe-operator-v3 +<slide>slides/internals/php85-pipes.xml</slide> +<slide>slides/internals/php85-pipes-examples.xml</slide> +<slide>slides/internals/php85-pipes-debug.xml</slide> + +https://wiki.php.net/rfc/asymmetric-visibility-v2 +<slide>slides/internals/php84-asymmetric-visibility.xml</slide> +<slide>slides/internals/php84-asymmetric-visibility-2.xml</slide> + +https://wiki.php.net/rfc/static-aviz +<slide>slides/internals/php85-asymmetric-visibility-static.xml</slide> + +https://wiki.php.net/rfc/final_promotion +<slide>slides/internals/php85-final-property-promotion.xml</slide> + +https://wiki.php.net/rfc/clone_with_v2 +<slide>slides/internals/php85-clone-with.xml</slide> + +Major additions: + +https://wiki.php.net/rfc/url_parsing_api +<slide>slides/internals/php85-url-parsing-api.xml</slide> + +https://wiki.php.net/rfc/make_opcache_required +<slide>slides/internals/php85-opcache-required.xml</slide> + + +Minor additions: + +Attributes: + +https://wiki.php.net/rfc/attributes-on-constants +<slide>slides/internals/php85-attributes-on-constants.xml</slide> + +https://wiki.php.net/rfc/marking_return_value_as_important +<slide>slides/internals/php85-nodiscard-attribute.xml</slide> + +https://wiki.php.net/rfc/deprecated_traits +<slide>slides/internals/php85-deprecated-trait-attribute.xml</slide> + +<!-- +https://wiki.php.net/rfc/delayedtargetvalidation_attribute +<s lide>slides/internals/php85-delayed-target-validation-attribute.xml</slide> +--> + +https://wiki.php.net/rfc/error_backtraces_v2 +<slide>slides/internals/php85-error-backtraces.xml</slide> + +https://wiki.php.net/rfc/filter_throw_on_failure +<slide>slides/internals/php85-filter-throw.xml</slide> + +https://wiki.php.net/rfc/array_first_last +<slide>slides/internals/php85-array-first-last.xml</slide> + + +Language stuff: +https://wiki.php.net/rfc/grapheme_str_split +<slide>slides/internals/php84-grapheme-str-split.xml</slide> +<slide>slides/internals/php84-grapheme-str-split-2.xml</slide> +<slide>slides/internals/php84-grapheme-str-split-3.xml</slide> + +https://wiki.php.net/rfc/grapheme_levenshtein +<slide>slides/internals/php85-grapheme-levenstein.xml</slide> +<slide>slides/internals/php85-grapheme-levenstein2.xml</slide> + +https://wiki.php.net/rfc/grapheme_add_locale_for_case_insensitive +<slide>slides/internals/php85-grapheme-levenstein3.xml</slide> +<slide>slides/internals/php85-grapheme-add-locale.xml</slide> + +Deprecations: + +Deprecations for PHP 8.5 +https://wiki.php.net/rfc/deprecations_php_8_5 + + +Policy: + +Abstain voting option for RFCs +https://wiki.php.net/rfc/rfc_vote_abstain +<slide>slides/internals/policy-vote-abstain.xml</slide> + +Recommend PIE and deprecate PECL +https://wiki.php.net/rfc/adopt_pie_deprecate_pecl +<slide>slides/internals/policy-adopt-pie.xml</slide> + + +<slide>slides/internals/questions-new.xml</slide> +<slide>slides/xdebug/resources.xml</slide> + +</presentation> diff --git a/slides/internals/abstain.png b/slides/internals/abstain.png new file mode 100644 index 00000000..8fd456e2 Binary files /dev/null and b/slides/internals/abstain.png differ diff --git a/slides/internals/php85-array-first-last.xml b/slides/internals/php85-array-first-last.xml new file mode 100644 index 00000000..e0ade50d --- /dev/null +++ b/slides/internals/php85-array-first-last.xml @@ -0,0 +1,73 @@ +<slide> +<title>PHP 8.5: array_first() and array_last()</title> + +<div effect="fade-out"> +<blurb>PHP 7.3 added %array_key_first()% and %array_key_last()%:</blurb> +<example><![CDATA[<?php +$timezone = new DateTimeZone("Europe/Kyiv"); +$trans = $timezone->getTransitions(); +var_dump(array_key_first($trans), array_key_last($trans)); +]]></example> + +<example> +int(0) +int(122) +</example> +</div> + +<div effect="fade-in-out"> +<blurb>But accessing values was still "odd":</blurb> +<example inline="1"><![CDATA[<?php +$timezone = new DateTimeZone("Europe/Kyiv"); +*$trans* = $timezone->getTransitions(); +var_dump(*$trans*[array_key_first(*$trans*)], *$trans*[array_key_last(*$trans*)]); +]]></example> + +<example> +array(5) { + ["ts"]=> int(-9223372036854775808) + ["time"]=> string(34) "-292277022657-01-27T08:29:52+00:00" + ["offset"]=> int(7324) + ["isdst"]=> bool(false) + ["abbr"]=> string(3) "LMT" +} +array(5) { + ["ts"]=> int(2140045200) + ["time"]=> string(25) "2037-10-25T01:00:00+00:00" + ["offset"]=> int(7200) + ["isdst"]=> bool(false) + ["abbr"]=> string(3) "EET" +} +</example> +</div> + +<div effect="fade-in"> +<blurb>PHP 8.5 adds %array_first()% and %array_last()%:</blurb> +<example inline="1"><![CDATA[<?php +$timezone = new DateTimeZone("Europe/Kyiv"); +*$trans* = $timezone->getTransitions(); +var_dump(*array_first*(*$trans*), *array_last*(*$trans*)); +]]></example> + +<example> +array(5) { + ["ts"]=> int(-9223372036854775808) + ["time"]=> string(34) "-292277022657-01-27T08:29:52+00:00" + ["offset"]=> int(7324) + ["isdst"]=> bool(false) + ["abbr"]=> string(3) "LMT" +} +array(5) { + ["ts"]=> int(2140045200) + ["time"]=> string(25) "2037-10-25T01:00:00+00:00" + ["offset"]=> int(7200) + ["isdst"]=> bool(false) + ["abbr"]=> string(3) "EET" +} +</example> +</div> + +</slide> + + + diff --git a/slides/internals/php85-clone-with.xml b/slides/internals/php85-clone-with.xml new file mode 100644 index 00000000..30a32f01 --- /dev/null +++ b/slides/internals/php85-clone-with.xml @@ -0,0 +1,55 @@ +<slide> +<title>PHP 8.5: Clone With</title> + +<div effect="fade-out"> +<blurb>Applying a ~wither~ method:</blurb> +<example><![CDATA[<?php +final readonly class Response { + public function __construct( + public int $statusCode, + public string $reasonPhrase, + ) {} + + public function withStatus($code, $reasonPhrase = ''): Response + { + $values = get_object_vars($this); + $values['statusCode'] = $code; + $values['reasonPhrase'] = $reasonPhrase; + return new self( + ...$values + ); + } +}]]></example> +<list> + <bullet>Only works if all properties are assignable via %__construct%</bullet> +</list> +</div> + +<div effect="fade-in"> +<blurb>PHP 8.5: Change %clone% to a function with optional arguments:</blurb> +<example><![CDATA[<?php +final readonly class Response { + public function __construct( + public int $statusCode, + public string $reasonPhrase, + ) {} + + public function withStatus($code, $reasonPhrase = ''): Response + { + return clone($this, [ + "statusCode" => $code, + "reasonPhrase" => $reasonPhrase, + ]); + } +}]]></example> +</div> + +<div effect="fade-in"> +<list> + <bullet>The magic %__clone% method will still be called (first)</bullet> + <bullet>Visibility, Property Hooks, and %__set% all work as expected</bullet> + <bullet>%readonly% is temporarily not enforced during cloning</bullet> +</list> +</div> + +</slide> diff --git a/slides/internals/php85-deprecated-trait-attribute.xml b/slides/internals/php85-deprecated-trait-attribute.xml new file mode 100644 index 00000000..336e5f27 --- /dev/null +++ b/slides/internals/php85-deprecated-trait-attribute.xml @@ -0,0 +1,31 @@ +<slide> +<title>PHP 8.5: Deprecated Trait Attribute</title> + +<blurb>PHP 8.4 introduced the %#[Deprecated]% attribute:</blurb> + +<example result="0"><![CDATA[<?php +class Clazz { + #[\Deprecated("use test() instead", since: "2024-10-08")] + function test2() { + } +} + +$c = new Clazz()->test2(); +?>]]></example> + +<div effect="fade-in"> +<blurb>PHP 8.5 adds support for the attributes on *traits*:</blurb> + +<example result="3"><![CDATA[<?php +#[\Deprecated] +trait LoggingTrait +{ + public function log(string $message) : void + { + // Log the message + } +} +?>]]></example> + +</div> +</slide> diff --git a/slides/internals/php85-error-backtraces.xml b/slides/internals/php85-error-backtraces.xml new file mode 100644 index 00000000..5e0ce02c --- /dev/null +++ b/slides/internals/php85-error-backtraces.xml @@ -0,0 +1,45 @@ +<slide> +<title>PHP 8.5: Backtrace with Fatal Error</title> + +<example inline="1"><![CDATA[<?php |aaaaaa|// mydatetimeclass.php| +class MyDateTimeClass implements DateTimeInterface {}]]></example> + +<example inline="1"><![CDATA[<?php |aaaaaa|// autoload.php| +function autoloader(string $class) { + include strtolower($class) . '.php'; +} +spl_autoload_register(autoloader(...));]]></example> + +<example inline="1"><![CDATA[<?php |aaaaaa|// code.php| +require 'autoload.php'; +$mdt = new MyDateTimeClass(); ]]></example> + +<div effect="fade-in-out"> +<blurb>PHP 8.4:</blurb> +<example>Fatal error: DateTimeInterface can't be implemented by user classes in + mydatetimeclass.php on line 2</example> +</div> + +<div effect="fade-in-out"> +<blurb>PHP 8.5:</blurb> +<example>Fatal error: DateTimeInterface can't be implemented by user classes in + mydatetimeclass.php on line 2 +Stack trace: +#0 autoload.php(4): include() +#1 test.php(4): autoloader('MyDateTimeClass') +#2 {main}</example> +</div> + +<div effect="fade-in"> +<blurb>PHP with Xdebug:</blurb> +<example>Fatal error: DateTimeInterface can't be implemented by user classes in + mydatetimeclass.php on line 2 + +Call Stack: + 0.0002 520872 1. {main}() test.php:0 + 0.0003 523432 2. autoloader($class = 'MyDateTimeClass') test.php:4 + 0.0003 525000 3. include('mydatetimeclass.php') autoload.php:4 +</example> +</div> + +</slide> diff --git a/slides/internals/php85-filter-throw.xml b/slides/internals/php85-filter-throw.xml new file mode 100644 index 00000000..c07da6e6 --- /dev/null +++ b/slides/internals/php85-filter-throw.xml @@ -0,0 +1,68 @@ +<slide> +<title>PHP 8.5: FILTER_THROW_ON_FAILURE</title> + +<div effect="fade-out"> +<blurb>Default %filter_var% behaviour:</blurb> +<example><![CDATA[<?php +function validateUser(string $email, string $userId, string $userName) : bool +{ + if (filter_var($email, FILTER_VALIDATE_EMAIL) === false) { + return false; + } + if (filter_var($userId, FILTER_VALIDATE_INT) === false) { + return false; + } + if (filter_var( + $userName, FILTER_VALIDATE_REGEXP, + ['options' => ['regexp' => '/^[a-z]+$/']] + ) === false) { + return false; + } + return true; +}]]> +</example> +</div> + +<div effect="fade-in-out"> +<blurb>%filter_var% with %FILTER_NULL_ON_FAILURE%:</blurb> +<example inline="1"><![CDATA[<?php +function validateUser(string $email, string $userId, string $userName) : bool +{ + if (filter_var($email, FILTER_VALIDATE_EMAIL, *FILTER_NULL_ON_FAILURE*) === *null*) { + return false; + } + if (filter_var($userId, FILTER_VALIDATE_INT, *FILTER_NULL_ON_FAILURE*) === *null*) { + return false; + } + if (filter_var( + $userName, FILTER_VALIDATE_REGEXP, + ['options' => ['regexp' => '/^[a-z]+$/'], 'flags' => *FILTER_NULL_ON_FAILURE*] + ) === *null*) { + return false; + } + return true; +}]]> +</example> +</div> + +<div effect="fade-in"> +<blurb>PHP 8.5: %filter_var% with %FILTER_THROW_ON_FAILURE%:</blurb> +<example inline="1"><![CDATA[<?php +function validateUser(string $email, string $userId, string $userName) : bool +{ + try { + filter_var($email, FILTER_VALIDATE_EMAIL, *FILTER_THROW_ON_FAILURE*); + filter_var($userId, FILTER_VALIDATE_INT, *FILTER_THROW_ON_FAILURE*); + filter_var( + $userName, FILTER_VALIDATE_REGEXP, + ['options' => ['regexp' => '/^[a-z]+$/'], 'flags' => *FILTER_THROW_ON_FAILURE*] + ); + return true; + } catch (*\Filter\FilterFailedException* $e) { + return false; + } +}]]> +</example> +</div> + +</slide> diff --git a/slides/internals/php85-final-property-promotion.xml b/slides/internals/php85-final-property-promotion.xml new file mode 100644 index 00000000..92cf9291 --- /dev/null +++ b/slides/internals/php85-final-property-promotion.xml @@ -0,0 +1,72 @@ +<slide> +<title>PHP 8.5: Final Property Promotion</title> + +<div effect="fade-out"> +<blurb>PHP 8.0 introduced property promotion:</blurb> +<example inline="1"> +&lt;?php +class π₯whisky +{ + function __construct( + *public* string $name, + *protected* Distillery $distillery, + ) {} +} +</example> +</div> + +<div effect="fade-in-out"> +<blurb>PHP 8.4 introduced property hooks:</blurb> +<example inline="1"><![CDATA[<?php +class User implements Named +{ + public function __construct( + private string $first, + private string $last, + ) {} + + public string $fullName { + *get* *=>* $this->first . " " . $this->last; + *set {* [$this->first, $this->last] = explode(' ', $value); *}* + } +} +?>]]></example> +</div> + +<div effect="fade-in-out"> +<blurb>PHP 8.4 introduced property hooks and %final% properties:</blurb> +<example inline="1"><![CDATA[<?php +class User implements Named +{ + public function __construct( + private string $first, + private string $last, + ) {} + + *final* public string $fullName { + get => $this->first . " " . $this->last; + set { [$this->first, $this->last] = explode(' ', $value); } + } +} +?>]]></example> +</div> + +<div effect="fade-in-out"> +<blurb>PHP 8.5 adds %final% for promoted properties:</blurb> +<example inline="1"><![CDATA[<?php +class User implements Named +{ + public function __construct( + *final* ---private--- string $first, + *final* ---private--- string $last, + ) {} + + final public string $fullName { + get => $this->first . " " . $this->last; + set { [$this->first, $this->last] = explode(' ', $value); } + } +} +?>]]></example> +</div> + +</slide> diff --git a/slides/internals/php85-grapheme-add-locale.xml b/slides/internals/php85-grapheme-add-locale.xml new file mode 100644 index 00000000..f307de74 --- /dev/null +++ b/slides/internals/php85-grapheme-add-locale.xml @@ -0,0 +1,16 @@ +<slide> +<title>PHP 8.5: locale parameter for other grapheme_* functions</title> + +<blurb class="center"> +%grapheme_strpos%, %grapheme_stripos%, %grapheme_strrpos%, %grapheme_strripos%, +%grapheme_substr%, %grapheme_strstr%, %grapheme_stristr% +</blurb> + +<example result="1"><![CDATA[<?php +$sentence = 'AutobahnstraΓe'; +$word = 'ss'; + +var_dump(grapheme_strpos($sentence, $word)); +var_dump(grapheme_strpos($sentence, $word, locale: 'de_DE-u-ks-level1')); +?>]]></example> +</slide> diff --git a/slides/internals/php85-grapheme-levenstein3.xml b/slides/internals/php85-grapheme-levenstein3.xml new file mode 100644 index 00000000..a9928d3f --- /dev/null +++ b/slides/internals/php85-grapheme-levenstein3.xml @@ -0,0 +1,43 @@ +<slide> +<title>PHP 8.5: grapheme_levenshtein</title> + +<div effect="fade-out"> +<example><![CDATA[<?php +$normalCase = 'Hoffwn i ddΕ΅r'; +$upperCase = 'HOFFWN I DDΕ΄R'; + +echo grapheme_levenshtein($normalCase, $upperCase), "\n"; +?>]]></example> +<example> +10 +</example> + +<blurb>What if I would like it case-insensitively matched?</blurb> +</div> + +<div effect="fade-in"> +<blurb>PHP 8.5 adds the %locale% argument:</blurb> +<example inline="1"><![CDATA[<?php +$normalCase = 'Hoffwn i ddΕ΅r'; +$upperCase = 'HOFFWN I DDΕ΄R'; + +echo grapheme_levenshtein($normalCase, $upperCase, *locale: 'cy_GB-u-ks-level2'*), "\n"; +?>]]></example> +<example> +0 +</example> +</div> + +<div effect="fade-in"> +<blurb>Locale descriptor:</blurb> +<example> +cy_GB-u-ks-level2 +β³β β³β β³ βββββ³ββββ +β β β ββββ ks: strength, with level 2 +β β ββββββββββ flag separator +β βββββββββββββ region code: GB (Great Britain) +ββββββββββββββββ language code: CY (Cymreag) +</example> +</div> + +</slide> diff --git a/slides/internals/php85-opcache-required.xml b/slides/internals/php85-opcache-required.xml new file mode 100644 index 00000000..d6f7eb2c --- /dev/null +++ b/slides/internals/php85-opcache-required.xml @@ -0,0 +1,16 @@ +<slide> +<title>OPcache is no longer optional</title> + +<break lines="3"/> +<blurb class="center"> +OPcache is now always *loaded* as part of PHP as a static part. +</blurb> + +<div effect="fade-in"> +<break lines="3"/> +<blurb class="center"> +OPcache is *not* always *enabled*, you still need to make the right %php.ini% settings. +</blurb> +</div> + +</slide> diff --git a/slides/internals/php85-pipes-debug.xml b/slides/internals/php85-pipes-debug.xml new file mode 100644 index 00000000..bd204f9d --- /dev/null +++ b/slides/internals/php85-pipes-debug.xml @@ -0,0 +1,7 @@ +<slide> +<title>PHP 8.5: Pipe Operator β Debugging</title> + +<example><![CDATA[<?php +?>]]></example> + +</slide> diff --git a/slides/internals/php85-pipes-examples.xml b/slides/internals/php85-pipes-examples.xml new file mode 100644 index 00000000..09d58423 --- /dev/null +++ b/slides/internals/php85-pipes-examples.xml @@ -0,0 +1,7 @@ +<slide> +<title>PHP 8.5: Pipe Operator β Further Examples</title> + +<example><![CDATA[<?php +?>]]></example> + +</slide> diff --git a/slides/internals/php85-pipes.xml b/slides/internals/php85-pipes.xml index aa5812d2..4959ef91 100644 --- a/slides/internals/php85-pipes.xml +++ b/slides/internals/php85-pipes.xml @@ -20,8 +20,4 @@ function slugger(string $input) var_dump(slugger('Hello, World!')); // string(11) "hello-world" ?>]]></example> -<list> - <bullet>Still under consideration (but currently passing)</bullet> -</list> - </slide> diff --git a/slides/internals/php85-url-parsing-api.xml b/slides/internals/php85-url-parsing-api.xml new file mode 100644 index 00000000..9394a2ee --- /dev/null +++ b/slides/internals/php85-url-parsing-api.xml @@ -0,0 +1,33 @@ +<slide> +<title>PHP 8.5: URL API</title> + +<break lines="3"/> +<div effect="fade-out"> +<blurb class="big-centre">%parse_url()% is π©</blurb> +</div> + +<div effect="fade-in"> +<blurb class="big-centre">%Uri\WhatWg\Url::parse()%</blurb> +<blurb class="center">embedding URLs into HTML</blurb> +</div> + +<div effect="fade-in-out"> +<break lines="2"/> +<blurb class="big-centre">%Uri\Rfc3986\Url::parse()%</blurb> +<blurb class="center">"server to server" communication (e.g. DSN parsing or outgoing HTTP requests)</blurb> +</div> + +<div effect="fade-in"> +<example result="1"><![CDATA[ +<?php +$uri = new Uri\Rfc3986\Uri("https://www.example.com/elephpants?are=yes#great"); +echo $uri->getScheme(), "\n"; +echo $uri->getHost(), "\n"; +echo $uri->getPath(), "\n"; +echo $uri->getQuery(), "\n"; +echo $uri->getFragment(), "\n"; +]]> +</example> +</div> + +</slide> diff --git a/slides/internals/pie.jpg b/slides/internals/pie.jpg new file mode 100644 index 00000000..cef22741 Binary files /dev/null and b/slides/internals/pie.jpg differ diff --git a/slides/internals/policy-adopt-pie.xml b/slides/internals/policy-adopt-pie.xml new file mode 100644 index 00000000..8054e516 --- /dev/null +++ b/slides/internals/policy-adopt-pie.xml @@ -0,0 +1,12 @@ +<slide> +<title>Policy: Adopting PIE</title> + +<image filename="pie.jpg"/> + +<break/> +<blurb class="big-centre">A modern installer for PHP extensions</blurb> +<div effect="fade-in"> +<blurb class="big-centre">to replace PECL.</blurb> +</div> + +</slide> diff --git a/slides/internals/policy-vote-abstain.xml b/slides/internals/policy-vote-abstain.xml new file mode 100644 index 00000000..dce3bf41 --- /dev/null +++ b/slides/internals/policy-vote-abstain.xml @@ -0,0 +1,11 @@ +<slide> +<title>Policy: Abstain</title> + +<image filename="abstain.png"/> + +<div effect="fade-in"> +<break lines="3"/> +<blurb class="big-centre">It's now okay *not* to have an opinion π!</blurb> +</div> + +</slide> diff --git a/templates/default/ordered-list.ezt b/templates/default/ordered-list.ezt new file mode 100644 index 00000000..78d95da6 --- /dev/null +++ b/templates/default/ordered-list.ezt @@ -0,0 +1,9 @@ +{use $node, $pres} +{var $class = get_attribute( $node, 'class' )} +<ol{if $class} class='{$class}'{/if}> +{foreach $node->childNodes as $child} + {if is_set( $child->tagName )} + {include $child->tagName . '.ezt' send $child as $node, $pres} + {/if} +{/foreach} +</ol>