diff --git a/drafts/function-autoloading.md b/drafts/function-autoloading.md new file mode 100644 index 0000000..0ed6a72 --- /dev/null +++ b/drafts/function-autoloading.md @@ -0,0 +1,165 @@ +# PHP RFC: Function Autoloading v4 + +* Version: 1.0 +* Date: 2024-08-15 +* Author: Robert Landers, landers.robert@gmail.com +* Status: Under Discussion (or Accepted or Declined) +* First Published at: + +## Introduction + +The topic of supporting function autoloading was brought up many times in the past, this RFC introduces a potential +implementation which would be consistent with what we have for autoloading classes. + +By using autoloaders, +programmers can already get quickly up to speed when it comes to classes, +but the language currently lacks a way to do the same for functions. +This requires programmers to manually (and carefully) include files that must be included on every request. +For 'functional' codebases, +they lose the ability to use autoloaders, or they must write their functions as static methods on classes. +This isn’t ideal, and this RFC seeks to close the gap between functions and classes. + +## Proposal + +This RFC proposes to add two new constants to the SPL extension: `SPL_AUTOLOAD_CLASS`, `SPL_AUTOLOAD_FUNCTION`. +These constants may be passed to `spl_autoload_register` as the fourth parameter +to register an autoloader for classes or functions, respectively. +If not specified, the default value `SPL_AUTOLOAD_CLASS` will be used to retain backward compatibility. + +There won’t be any changes to the current autoloading mechanism when it comes to classes. + +### Function Autoloading + +The function autoloader will be called with the fully qualified undefined function name. +This will allow the function autoloader to determine how to load or generate the function. + +PHP allows programmers to call an unqualified function name. +Traditionally, this means that PHP would first search in the current namespace for the function +and then fall back to the global namespace if the function is not found. +This behavior will be preserved. +However, the function autoloader will be called **only once** for the current namespace; +thus, the function autoloader will not be called again if the function is found in the global namespace. + +Example "`PSR-4-style`" (except the last part of the namespace is the file it is in) function autoloader: + +```php + + + * Yes + * No + + + +## Patches and Tests + +Review the implementation [on GitHub #15471](https://github.com/php/php-src/pull/15471) + +## Implementation + +- Implentation: [PR #15471](https://github.com/php/php-src/pull/15471) +- Version: TBD +- PHP Manual Entry: TODO + +## References + +- [autofunc](https://wiki.php.net/rfc/autofunc): This heavily influenced this RFC. (declined in 2011) +- [function_autoloading](https://wiki.php.net/rfc/function_autoloading): This RFC was declined in 2011. +- [function_autoloading_v2](https://wiki.php.net/rfc/function_autoloading2): This RFC was declined in 2012. + +Thank you for all of those that contributed to the discussions back then. I hope that this RFC will be successful. + +## Rejected Features + +### Autoloading constants + +Autoloading of other types such as constants and stream wrappers will come in a later RFC. diff --git a/drafts/typed-aliases.md b/drafts/typed-aliases.md new file mode 100644 index 0000000..d44e64c --- /dev/null +++ b/drafts/typed-aliases.md @@ -0,0 +1,310 @@ +# PHP RFC: Typed Aliases + +* Version: 1.0 +* Date: 2024-09-06 +* Author: Robert Landers, landers.robert@gmail.com +* Status: Under Discussion (or Accepted or Declined) +* First Published at: + +## Introduction + +There are many times when you may need to write out a union/intersection type many times in PHP. This can be cumbersome and +error-prone. +This RFC proposes a new "typed alias" +syntax that will allow for the creation of type aliases that may be used project-wide. + +Here is a brief example: + +```php + +namespace MyLibrary; + +class Second {} +class Minute {} +class Hour {} + +alias Time: Second|Minute|Hour; + +// in another file + +use MyLibrary\Time; +``` + +## Proposal + +This RFC proposes to implement type aliases as a "special" +class type (similar to final, abstract, etc.) under the hood of the same name as its alias. +Thus, the alias `Time`, in the above example, would be a class named `Time` in the namespace `MyLibrary`. +This prevents collisions with other classes and defined "types" in the same namespace. + +When the engine sees a class with this special type, it expands the alias into its actual type, +and continues with type checking. + +### Aliases Classes + +There are several classes of aliases: + +1. **primitive** - An alias for a single primitive data type (int, float, string, bool, array, etc.) +2. **simple** - An alias for a single class or interface +3. **complex** - An alias for a union or intersection of other types + +### Creating Aliases + +An alias is defined by the work `alias`, followed by the alias name, a colon, and then the type to alias: + +```php +alias Time: Second|Minute|Hour; +alias Number: int|float; +alias Stringy: string|Stringable; +alias Matrix: array; +alias Client: HttpClient&JsonClient; +``` + +### Using Aliases + +Since an alias is essentially a class, under the hood, it can be used in the same way as a class. +This allows you to define an alias in one part of a project and use it in another: + +```php +namespace MyProject; + +use MyLibrary\Time; +use MyLibrary\Number; +use MyLibrary\Stringy; + +function sleepFor(Time $time) {} + +function retryTimes(Number $times) {} + +function logMessage(Stringy|string $message) {} // Not a fatal error +``` + +#### Intersections and Unions + +A type alias may be a union or intersection of other types (including other aliases), +even if they contain the same types in their alias. +It will not be a fatal error as it currently is when a type is a union or intersection with itself. +This allows libraries to declare type aliases that are specific to their own library +and be reused in other projects that may also have similar aliases. +For example, +a library may define a `Stringy` alias that is a union of `string` +and `Stringable` and another library may define a `ConstantString` alias +that is also a union of `Stringable` and `string`. +A project using both libraries would be able +to use `Stringy` and `ConstantString` in its own type alias or function type. + +```php +alias Stringy: string|Stringable; +alias ConstantString: string|Stringable; + +function logMessage(Stringy|ConstantString $message) {} // Not a fatal error +``` + +#### Nesting + +Aliases may also be aliases of other aliases: + +```php +namespace MyLibrary; + +alas Time: Second|Minute|Hour; +alias Duration: Time|int; +``` + +#### Argument Lists and Return Types + +The primary usage for aliases is in argument lists, instanceof and return types: + +```php +use MyLibrary\Time; + +function sleep(Time $time): Time {} + +class Alarm { + public function __construct(Time $time) { + assert($time instanceof Time); + } + + public function getTime(): Time {} +} +``` + +#### Extending and Implementing + +For simple aliases of other classes, `type_alias` behaves exactly like `class_alias` and `autoload` set to `false`. +Thus, these types of aliases can be used in class extension and implementation: + +```php +class A {} + +alias B: A; + +class C extends B {} +``` + +However, trying to extend or implement a complex or primitive alias will result in the expected fatal error: + +```php +class A {} +class B {} + +alias C: A|B; +alias D: int; + +class E extends C {} // Fatal error: cannot extend a complex type alias +class F implements D {} // Fatal error: cannot implement a primitive type alias +``` + +#### Calling new on Aliases + +Aliases may be used in the `new` keyword, but only if the alias is a simple alias of a class, as is currently possible: + +```php +class A {} + +alias B: A; // same as calling class_alias('A', 'B'); + +new B(); +``` + +#### Static calls on Aliases + +Aliases may be used in static calls, but only if the alias is a simple alias of a class, as is currently possible: + +```php +class A { + public static function test() {} +} + +alias B: A; // same as calling class_alias('A', 'B'); + +B::test(); +``` + +## Reflection + +It will be possible to use reflection to determine the type of alias. +When using `ReflectionClass` on an alias, it will see an object with one of the following base classes: + +- `PrimitiveTypeAlias` +- `ComplexTypeAlias` + +These classes will have the following structure: + +```php + +enum PrimitiveType { + case int; + case float; + case string; + case bool; + case array; + case object; + case callable; + case iterable; + case void; + case null; +} + +abstract class PrimitiveTypeAlias { + public const PrimitiveType $aliasOf; +} + +abstract class ComplexTypeAlias { + public const ReflectionType $aliasOf; +} +``` + +For simple aliases, using ReflectionClass will return the original class name, just like with `class_alias`. + +Developers may access the `aliasOf` property to find out the alias’s underlying type. + +## Why Special Classes? + +After looking at the current type system in PHP, +it became clear that if we were to implement aliases in the existing type system, +it would be overly complex and challenging to maintain. +Using classes, however, is much simpler, easier to maintain, and debug. +It is also easier to reason about in the symbol tables as well +since classes are synonymous with types in lay-terms. + +## Backward Incompatible Changes + +There should be no backward incompatible changes. + +## Proposed PHP Version(s) + +8.5 or later. + +## RFC Impact + +### To SAPIs + +N/A + +### To Existing Extensions + +N/A + +### To Opcache + +TBD + +### New Constants + +Describe any new constants so they can be accurately and comprehensively +explained in the PHP documentation. + +### php.ini Defaults + +If there are any php.ini settings then list: \* hardcoded default values +\* php.ini-development values \* php.ini-production values + +## Open Issues + +Make sure there are no open issues when the vote starts! + +## Unaffected PHP Functionality + +List existing areas/features of PHP that will not be changed by the RFC. + +This helps avoid any ambiguity, shows that you have thought deeply about +the RFC's impact, and helps reduces mail list noise. + +## Future Scope + +This section details areas where the feature might be improved in +future, but that are not currently proposed in this RFC. + +## Proposed Voting Choices + +Include these so readers know where you are heading and can discuss the +proposed voting options. + +## Patches and Tests + +Links to any external patches and tests go here. + +If there is no patch, make it clear who will create a patch, or whether +a volunteer to help with implementation is needed. + +Make it clear if the patch is intended to be the final patch, or is just +a prototype. + +For changes affecting the core language, you should also provide a patch +for the language specification. + +## Implementation + +After the project is implemented, this section should contain - the +version(s) it was merged into - a link to the git commit(s) - a link to +the PHP manual entry for the feature - a link to the language +specification section (if any) + +## References + +Links to external references, discussions or RFCs + +## Rejected Features + +Keep this updated with features that were discussed on the mail lists. diff --git a/published/function-autoloading.ptxt b/published/function-autoloading.ptxt new file mode 100644 index 0000000..45048d5 --- /dev/null +++ b/published/function-autoloading.ptxt @@ -0,0 +1,141 @@ +====== PHP RFC: Function Autoloading v4 ====== + + * Version: 1.0 + * Date: 2024-08-15 + * Author: Robert Landers, + * Status: Under Discussion (or Accepted or Declined) + * First Published at: http://wiki.php.net/rfc/function_autoloading4 + +===== Introduction ===== + +The topic of supporting function autoloading was brought up many times in the past, this RFC introduces a potential implementation which would be consistent with what we have for autoloading classes. + +By using autoloaders, programmers can already get quickly up to speed when it comes to classes, but the language currently lacks a way to do the same for functions. This requires programmers to manually (and carefully) include files that must be included on every request. For 'functional' codebases, they lose the ability to use autoloaders, or they must write their functions as static methods on classes. This isn’t ideal, and this RFC seeks to close the gap between functions and classes. + +===== Proposal ===== + +This RFC proposes to add two new constants to the SPL extension: ''%%SPL_AUTOLOAD_CLASS%%'', ''%%SPL_AUTOLOAD_FUNCTION%%''. These constants may be passed to ''%%spl_autoload_register%%'' as the fourth parameter to register an autoloader for classes or functions, respectively. If not specified, the default value ''%%SPL_AUTOLOAD_CLASS%%'' will be used to retain backward compatibility. + +There won’t be any changes to the current autoloading mechanism when it comes to classes. + +==== Function Autoloading ==== + +The function autoloader will be called with the fully qualified undefined function name. This will allow the function autoloader to determine how to load or generate the function. + +PHP allows programmers to call an unqualified function name. Traditionally, this means that PHP would first search in the current namespace for the function and then fall back to the global namespace if the function is not found. This behavior will be preserved. However, the function autoloader will be called **only once** for the current namespace; thus, the function autoloader will not be called again if the function is found in the global namespace. + +Example "''%%PSR-4-style%%''" (except the last part of the namespace is the file it is in) function autoloader: + + + + +==== Performance Impact ==== + +Function autoloading doesn’t appear to have a significant impact on performance; however, the function autoloader itself (depending upon its implementation) may have a performance impact. + +To help mitigate any potential performance impact of function autoloading many unqualified functions, a function will only be searched for once per namespace. + +==== spl_autoload ==== + +The ''%%spl_autoload%%'' function will not be modified. It may be used as a function autoloader if the programmer desires, though it will limit the programmer to a single function per file. + +==== spl_autoload_unregister ==== + +''%%spl_autoload_unregister%%'' will be updated to accept the new constants as the second parameter to unregister an autoloader from either mode. + +==== spl_autoload_functions ==== + +''%%spl_autoload_functions%%'' will be updated to accept one of the new constants as the first parameter. Passing both (i.e., ''%%SPL_AUTOLOAD_CLASS | SPL_AUTOLOAD_FUNCTION%%'') will result in all registered functions. + +==== spl_autoload_call ==== + +The ''%%spl_autoload_call%%'' function will be modified to accept a second parameter of one or both of the constants, with the default value set to ''%%SPL_AUTOLOAD_CLASS%%''. The name of the first parameter will be changed to ''%%$name%%'' to reflect that it can be a class or function name. + +In the event that both constants are passed, it will attempt to autoload both types. + + +spl_autoload_call('Some\func', SPL_AUTOLOAD_FUNCTION); // Calls the function autoloader +spl_autoload_call('Some\func'); // Calls the class autoloader +spl_autoload_call('Some\func', SPL_AUTOLOAD_CLASS); // Calls the class autoloader +spl_autoload_call('func', SPL_AUTOLOAD_FUNCTION | SPL_AUTOLOAD_CLASS); // Calls both autoloaders with the name 'func' + + +==== function_exists ==== + +The ''%%function_exists%%'' function will be updated to include a boolean option (''%%$autoload%%'') as the second parameter, which will default to ''%%true%%''. If set to ''%%true%%'', the function autoloader will be called if the function is not defined, otherwise, it will not be called. + +===== Backward Incompatible Changes ===== + +There shouldn’t be any backward incompatible changes. + +===== Proposed PHP Version(s) ===== + +8.5 or later. + +===== RFC Impact ===== + +==== To Opcache ==== + + * Potential changes to JIT helpers to call the autoloader instead of reading from the function table directly. + +==== New Constants ==== + +Two new constants will be added to the SPL extension: SPL_AUTOLOAD_CLASS, SPL_AUTOLOAD_FUNCTION. + +===== Open Issues ===== + +None. + +===== Future Scope ===== + +Potentially, constants and stream wrappers can be added in a similar fashion. + +===== Proposed Voting Choices ===== + +As per the voting RFC a yes/no vote with a 2/3 majority is needed for this proposal to be accepted. + +Voting started on 2023-XX-XX and will end on 2023-XX-XX. + + + + + + * Yes + * No + + + + +===== Patches and Tests ===== + +Review the implementation [[https://github.com/php/php-src/pull/15471|on GitHub #15471]] + +===== Implementation ===== + + * Implentation: [[https://github.com/php/php-src/pull/15471|PR #15471]] + * Version: TBD + * PHP Manual Entry: TODO + +===== References ===== + + * [[https://wiki.php.net/rfc/autofunc|autofunc]]: This heavily influenced this RFC. (declined in 2011) + * [[https://wiki.php.net/rfc/function_autoloading|function_autoloading]]: This RFC was declined in 2011. + * [[https://wiki.php.net/rfc/function_autoloading2|function_autoloading_v2]]: This RFC was declined in 2012. + +Thank you for all of those that contributed to the discussions back then. I hope that this RFC will be successful. + +===== Rejected Features ===== + +==== Autoloading constants ==== + +Autoloading of other types such as constants and stream wrappers will come in a later RFC. diff --git a/published/typed-aliases.ptxt b/published/typed-aliases.ptxt new file mode 100644 index 0000000..057afa0 --- /dev/null +++ b/published/typed-aliases.ptxt @@ -0,0 +1,274 @@ +====== PHP RFC: Typed Aliases ====== + + * Version: 1.0 + * Date: 2024-09-06 + * Author: Robert Landers, + * Status: Under Discussion (or Accepted or Declined) + * First Published at: http://wiki.php.net/rfc/typed-aliases + +===== Introduction ===== + +There are many times when you may need to write out a union/intersection type many times in PHP. This can be cumbersome and error-prone. This RFC proposes a new "typed alias" syntax that will allow for the creation of type aliases that may be used project-wide. + +Here is a brief example: + + + +namespace MyLibrary; + +class Second {} +class Minute {} +class Hour {} + +alias Time: Second|Minute|Hour; + +// in another file + +use MyLibrary\Time; + + +===== Proposal ===== + +This RFC proposes to implement type aliases as a "special" class type (similar to final, abstract, etc.) under the hood of the same name as its alias. Thus, the alias ''%%Time%%'', in the above example, would be a class named ''%%Time%%'' in the namespace ''%%MyLibrary%%''. This prevents collisions with other classes and defined "types" in the same namespace. + +When the engine sees a class with this special type, it expands the alias into its actual type, and continues with type checking. + +==== Aliases Classes ==== + +There are several classes of aliases: + + - **primitive** - An alias for a single primitive data type (int, float, string, bool, array, etc.) + - **simple** - An alias for a single class or interface + - **complex** - An alias for a union or intersection of other types + +==== Creating Aliases ==== + +An alias is defined by the work ''%%alias%%'', followed by the alias name, a colon, and then the type to alias: + + +alias Time: Second|Minute|Hour; +alias Number: int|float; +alias Stringy: string|Stringable; +alias Matrix: array; +alias Client: HttpClient&JsonClient; + + +==== Using Aliases ==== + +Since an alias is essentially a class, under the hood, it can be used in the same way as a class. This allows you to define an alias in one part of a project and use it in another: + + +namespace MyProject; + +use MyLibrary\Time; +use MyLibrary\Number; +use MyLibrary\Stringy; + +function sleepFor(Time $time) {} + +function retryTimes(Number $times) {} + +function logMessage(Stringy|string $message) {} // Not a fatal error + + +=== Intersections and Unions === + +A type alias may be a union or intersection of other types (including other aliases), even if they contain the same types in their alias. It will not be a fatal error as it currently is when a type is a union or intersection with itself. This allows libraries to declare type aliases that are specific to their own library and be reused in other projects that may also have similar aliases. For example, a library may define a ''%%Stringy%%'' alias that is a union of ''%%string%%'' and ''%%Stringable%%'' and another library may define a ''%%ConstantString%%'' alias that is also a union of ''%%Stringable%%'' and ''%%string%%''. A project using both libraries would be able to use ''%%Stringy%%'' and ''%%ConstantString%%'' in its own type alias or function type. + + +alias Stringy: string|Stringable; +alias ConstantString: string|Stringable; + +function logMessage(Stringy|ConstantString $message) {} // Not a fatal error + + +=== Nesting === + +Aliases may also be aliases of other aliases: + + +namespace MyLibrary; + +alas Time: Second|Minute|Hour; +alias Duration: Time|int; + + +=== Argument Lists and Return Types === + +The primary usage for aliases is in argument lists, instanceof and return types: + + +use MyLibrary\Time; + +function sleep(Time $time): Time {} + +class Alarm { + public function __construct(Time $time) { + assert($time instanceof Time); + } + + public function getTime(): Time {} +} + + +=== Extending and Implementing === + +For simple aliases of other classes, ''%%type_alias%%'' behaves exactly like ''%%class_alias%%'' and ''%%autoload%%'' set to ''%%false%%''. Thus, these types of aliases can be used in class extension and implementation: + + +class A {} + +alias B: A; + +class C extends B {} + + +However, trying to extend or implement a complex or primitive alias will result in the expected fatal error: + + +class A {} +class B {} + +alias C: A|B; +alias D: int; + +class E extends C {} // Fatal error: cannot extend a complex type alias +class F implements D {} // Fatal error: cannot implement a primitive type alias + + +=== Calling new on Aliases === + +Aliases may be used in the ''%%new%%'' keyword, but only if the alias is a simple alias of a class, as is currently possible: + + +class A {} + +alias B: A; // same as calling class_alias('A', 'B'); + +new B(); + + +=== Static calls on Aliases === + +Aliases may be used in static calls, but only if the alias is a simple alias of a class, as is currently possible: + + +class A { + public static function test() {} +} + +alias B: A; // same as calling class_alias('A', 'B'); + +B::test(); + + +===== Reflection ===== + +It will be possible to use reflection to determine the type of alias. When using ''%%ReflectionClass%%'' on an alias, it will see an object with one of the following base classes: + + * ''%%PrimitiveTypeAlias%%'' + * ''%%ComplexTypeAlias%%'' + +These classes will have the following structure: + + + +enum PrimitiveType { + case int; + case float; + case string; + case bool; + case array; + case object; + case callable; + case iterable; + case void; + case null; +} + +abstract class PrimitiveTypeAlias { + public const PrimitiveType $aliasOf; +} + +abstract class ComplexTypeAlias { + public const ReflectionType $aliasOf; +} + + +For simple aliases, using ReflectionClass will return the original class name, just like with ''%%class_alias%%''. + +Developers may access the ''%%aliasOf%%'' property to find out the alias’s underlying type. + +===== Why Special Classes? ===== + +After looking at the current type system in PHP, it became clear that if we were to implement aliases in the existing type system, it would be overly complex and challenging to maintain. Using classes, however, is much simpler, easier to maintain, and debug. It is also easier to reason about in the symbol tables as well since classes are synonymous with types in lay-terms. + +===== Backward Incompatible Changes ===== + +There should be no backward incompatible changes. + +===== Proposed PHP Version(s) ===== + +8.5 or later. + +===== RFC Impact ===== + +==== To SAPIs ==== + +N/A + +==== To Existing Extensions ==== + +N/A + +==== To Opcache ==== + +TBD + +==== New Constants ==== + +Describe any new constants so they can be accurately and comprehensively explained in the PHP documentation. + +==== php.ini Defaults ==== + +If there are any php.ini settings then list: * hardcoded default values * php.ini-development values * php.ini-production values + +===== Open Issues ===== + +Make sure there are no open issues when the vote starts! + +===== Unaffected PHP Functionality ===== + +List existing areas/features of PHP that will not be changed by the RFC. + +This helps avoid any ambiguity, shows that you have thought deeply about the RFC's impact, and helps reduces mail list noise. + +===== Future Scope ===== + +This section details areas where the feature might be improved in future, but that are not currently proposed in this RFC. + +===== Proposed Voting Choices ===== + +Include these so readers know where you are heading and can discuss the proposed voting options. + +===== Patches and Tests ===== + +Links to any external patches and tests go here. + +If there is no patch, make it clear who will create a patch, or whether a volunteer to help with implementation is needed. + +Make it clear if the patch is intended to be the final patch, or is just a prototype. + +For changes affecting the core language, you should also provide a patch for the language specification. + +===== Implementation ===== + +After the project is implemented, this section should contain - the version(s) it was merged into - a link to the git commit(s) - a link to the PHP manual entry for the feature - a link to the language specification section (if any) + +===== References ===== + +Links to external references, discussions or RFCs + +===== Rejected Features ===== + +Keep this updated with features that were discussed on the mail lists. diff --git a/src/convert-from-md.sh b/src/convert-from-md.sh index d98c6c5..84222f2 100755 --- a/src/convert-from-md.sh +++ b/src/convert-from-md.sh @@ -1,6 +1,9 @@ #!/bin/sh -docker run -v "$(pwd)":/data --pull always --user "$(id -u)":"$(id -g)" pandoc/latex -t dokuwiki -f gfm "$1" -o "$2" +docker run --rm -v "$(pwd)":/data --user "$(id -u)":"$(id -g)" pandoc/latex -t dokuwiki -f gfm "$1" -o "$2" # remove all and tags sed -i 's///g' "$2" sed -i 's/<\/HTML>//g' "$2" + +# remove all html comments +sed -i 's///g' "$2"