rfc:deprecated_attribute

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
rfc:deprecated_attribute [2020/12/19 08:52] beberleirfc:deprecated_attribute [2024/04/23 17:05] (current) – Formatting: wrap @deprecated with <php>/** */</php> levim
Line 1: Line 1:
-====== PHP RFC: #[Deprecated] Attribute ======+====== PHP RFC: #[\Deprecated] Attribute ======
  
-  * Version: 1.1 +  * Version: 1.3 
-  * Date: 2020-05-06 +  * Date: 2024-04-15 
-  * Author: Benjamin Ebelei +  * Author: Benjamin Eberlei, Tim Düsterhus 
   * Status: Under Discussion   * Status: Under Discussion
   * First Published at: http://wiki.php.net/rfc/deprecated_attribute   * First Published at: http://wiki.php.net/rfc/deprecated_attribute
Line 9: Line 9:
 ===== Introduction ===== ===== Introduction =====
  
-With the Attributes RFC accepted for PHP 8, this is a first proposal for an internal attribute hooking into the engine.+PHP’s internal functions can be marked as deprecatedmaking this information available to Reflection and emitting deprecation errors (<php>E_DEPRECATED</php>), but there is no //equivalent// functionality for functions defined in userland.
  
-It also serves as good prototype and first stepas usually all languages with attributes also have Deprecated attribute in their language core.+While the functionality can be //emulated// using <php>trigger_error()</php> to emit <php>E_USER_DEPRECATED</php> error when calling a deprecated functioncombined with either parsing doc comment for the <php>/** @deprecated */</php> annotation or attaching a custom-defined attribute and reading it with Reflection, it requires special handling depending on whether the function in question is an internal or a userland function. <php>ReflectionFunctionAbstract::isDeprecated()</php> always returns <php>false</php> for userland functions - and doc comments / custom attributes are unavailable for internal functions.
  
 ===== Proposal ===== ===== Proposal =====
  
-<nowiki>Developers can put an attribute #[Deprecated] on the following elements (targets):</nowiki>+A new attribute <php>#[\Deprecated]</phpshall be added:
  
-  * Functions 
-  * Methods 
  
-For now is not possible to target classes, constants, properties or arguments with this attribute, and it is left for future RFC(sto address this.+<PHP> 
 +/** 
 + * @strict-properties 
 + */ 
 +#[Attribute(Attribute::TARGET_METHOD|Attribute::TARGET_FUNCTION)
 +final class Deprecated 
 +
 +    public readonly ?string $message;
  
-Using attribute will add "ZEND_ACC_DEPERACTED" function flag to the op_array (userland function), which will automatically (with only small changes to the VM) lead to a deprecation warning, when the function is called. +    public function __construct(?string $message = null{} 
 +
 +</PHP>
  
-This functionality is present for internal functions already. The Deprecaed attribute allows to expose this feature to userland functions/methods and closes gap between internal and userland functions.+Applying this attribute to a userland function or method will add the internal ''ZEND_ACC_DEPRECATED'' flag to the function, resulting in behavior that is consistent with the existing deprecation functionality for internal functions. This means:
  
-<code php>+  * <php>ReflectionFunctionAbstract::isDeprecated()</php> will return <php>true</php>
 +  * Calling the function will emit a <php>E_USER_DEPRECATED</php> error (internal functions emit <php>E_DEPRECATED</php>, but this error code is reserved for internal functions). 
 + 
 +The <php>$message</php> given within the attribute definition will be included in the error message when calling the function. It goes without saying that it will also be available to static analysis tools, just like the parameters of any other attribute. 
 + 
 +==== Examples ==== 
 + 
 +<PHP>
 <?php <?php
  
-use Deprecated;+#[\Deprecated
 +function test() { 
 +}
  
-#[Deprecated] +#[\Deprecated("use test() instead")
-function test() {} +function test2() { 
-// Deprecated: Function test() is deprecated+}
  
-#[Deprecated("use test3() instead")+class Clazz { 
-function test2() {} +    #[\Deprecated] 
-// Deprecated: Function test2() is deprecated, use test3() instead+    function test() { 
 +    }
  
-class Foo { +    #[\Deprecated("use test() instead")
-    #[Deprecated] +    function test2() { 
-    public function test() {} +    }
-    // Deprecated: Method Foo::test() is deprecated in %s+
 } }
-</code> 
  
-The deprecated class is final and cannot be extended.+test(); // Deprecated: Function test() is deprecated in test.php on line 21 
 +test2(); // Deprecated: Function test2() is deprecated, use test() instead in test.php on line 22 
 +call_user_func("test"); // Deprecated: Function test() is deprecated in test.php on line 23
  
-==== Runtime Effects ====+$cls new Clazz(); 
 +$cls->test(); // Deprecated: Method Clazz::test() is deprecated in test.php on line 26 
 +$cls->test2(); // Deprecated: Method Clazz::test2() is deprecated, use test() instead in test.php on line 27
  
-Using the deprecated attribute on a function or method behaves the same as putting a call to trigger_error using E_DEPRECATED level as the first line of the same function/method. +call_user_func([$cls, "test"]); // Deprecated: Method Clazz::test() is deprecated in test.php on line 29
  
-While other languages have deprecation attributes, they usually generate compile time warnings instead of runtime warnings. However as PHPs current deprecation model is based on runtime warnings, the existing concept is extended instead of inventing another approach.+?> 
 +</PHP>
  
-Changing deprecation warnings from runtime to a different approach falls out of the scope of this RFC.+<PHP> 
 +<?php 
 + 
 +#[\Deprecated] 
 +function test() { 
 +
 + 
 +$r = new ReflectionFunction('test'); 
 + 
 +var_dump($r->isDeprecated()); // bool(true) 
 + 
 +?> 
 +</PHP> 
 + 
 +<PHP> 
 +<?php 
 + 
 +#[\Deprecated] 
 +function test1() { 
 +
 + 
 +#[\Deprecated()] 
 +function test2() { 
 +
 + 
 +#[\Deprecated("use test() instead")] 
 +function test3() { 
 +
 + 
 +$reflection = new ReflectionFunction('test1'); 
 +var_dump($reflection->getAttributes()[0]->newInstance()); 
 +/* 
 +object(Deprecated)#3 (1) { 
 +  ["message"]=> 
 +  NULL 
 +
 +*/ 
 + 
 +$reflection = new ReflectionFunction('test2'); 
 +var_dump($reflection->getAttributes()[0]->newInstance()); 
 +/* 
 +object(Deprecated)#2 (1) { 
 +  ["message"]=> 
 +  NULL 
 +
 +*/ 
 + 
 +$reflection = new ReflectionFunction('test3'); 
 +var_dump($reflection->getAttributes()[0]->newInstance()); 
 +/* 
 +object(Deprecated)#1 (1) { 
 +  ["message"]=> 
 +  string(18) "use test() instead" 
 +
 +*/ 
 + 
 +?> 
 +</PHP> 
 + 
 +Further examples are given by [[https://github.com/php/php-src/pull/11293/files?file-filters%5B%5D=.phpt&show-viewed-files=true|the newly added tests within the PR for this RFC]].
  
 ===== Backward Incompatible Changes ===== ===== Backward Incompatible Changes =====
  
-class with the name "Deprecated" is introduced into the global namespace.+<php>Deprecated</php> can no longer be used as a class name in the global namespace. A GitHub search for ''"class Deprecated " language:php symbol:deprecated'' revealed a total of 173 matches in source code. The vast majority of them appear to be defined within a namespace.
  
 ===== Proposed PHP Version(s) ===== ===== Proposed PHP Version(s) =====
  
-8.1 for function/method deprecations+Next minor (PHP 8.4).
  
 ===== RFC Impact ===== ===== RFC Impact =====
 +
 ==== To SAPIs ==== ==== To SAPIs ====
-None+ 
 +None.
  
 ==== To Existing Extensions ==== ==== To Existing Extensions ====
-None+ 
 +The <php>#[\Deprecated]</php> attribute will also be available to internal functions. Within a stub file it will have the same effect as adding a <php>/** @deprecated */</php> doc comment. The attribute will //not// be automatically applied to existing functions having the doc comment, but extension authors are encouraged to apply the attribute for consistency reasons. 
 + 
 +For extensions that are part of php-src the attribute will replace the existing doc comment as part of this RFC.
  
 ==== To Opcache ==== ==== To Opcache ====
  
-None+None.
  
 ==== New Constants ==== ==== New Constants ====
  
-None+None.
  
 ==== php.ini Defaults ==== ==== php.ini Defaults ====
  
-None+None.
  
 ===== Open Issues ===== ===== Open Issues =====
  
-A few things tracked in https://github.com/php/php-src/pull/6521+A few things tracked in https://github.com/php/php-src/pull/11293 
 + 
 +===== Future Scope ===== 
 + 
 +  * Supporting <php>#[\Deprecated]</php> on classes or other targets of attributes. 
 +  * Adding further metadata to the <php>#[\Deprecated]</php> attribute beyond a custom message (e.g. hints for replacements that IDEs could use).
  
 ===== Proposed Voting Choices ===== ===== Proposed Voting Choices =====
  
-Accept #[Deprecated] attribute into core?+<doodle title="Implement the #[\Deprecated] attribute as described?" auth="timwolla" voteType="single" closed="false" closeon="2022-01-01T00:00:00Z"> 
 +   * Yes 
 +   * No 
 +</doodle>
  
 ===== Patches and Tests ===== ===== Patches and Tests =====
  
-https://github.com/php/php-src/pull/6521+https://github.com/php/php-src/pull/11293 
 + 
 +===== Implementation ===== 
 + 
 +n/a 
 + 
 +===== References ===== 
 + 
 +  * Implementation: https://github.com/php/php-src/pull/11293 
 +  * Early Mailing List Discussion: https://externals.io/message/112554#112554 
 + 
 +===== Rejected Features =====
  
-No implementation for deprecated class constants, properties and parameters yet.+  * Changes to the runtime behavior of deprecated functions are out of scope of this RFC (i.e. not emitting the <php>E_DEPRECATED</php> error for internal functions). 
 +  * Making the <php>Deprecated</php> attribute class non-final: Child classes of attributes are not understood by the engine for technical reasons and the semantics of a child class would be less clear for static analysis tools.
rfc/deprecated_attribute.1608367955.txt.gz · Last modified: 2020/12/19 08:52 by beberlei