rfc:namespace_scoped_declares

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:namespace_scoped_declares [2017/12/10 22:03] – Resolve one open question nikicrfc:namespace_scoped_declares [2022/01/25 18:22] (current) – Move to inactive ilutov
Line 4: Line 4:
   * Author: Nikita Popov <nikic@php.net>   * Author: Nikita Popov <nikic@php.net>
   * Proposed PHP version: PHP 7.3   * Proposed PHP version: PHP 7.3
-  * Status: Under Discussion+  * Status: Inactive
   * PR: https://github.com/php/php-src/pull/2972   * PR: https://github.com/php/php-src/pull/2972
   * ML thread: http://externals.io/thread/326   * ML thread: http://externals.io/thread/326
Line 17: Line 17:
 // bootstrap.php // bootstrap.php
 namespace_declare('Vendor\Lib', ['strict_types' => 1]); namespace_declare('Vendor\Lib', ['strict_types' => 1]);
-namespace_declare('Vendor\Lib\Sub\Name\Space', ['strict_types' => 0]); 
 </code> </code>
  
-The first call would make ''strict_types=1'' the default in the namespace ''Vendor\Lib'' and all sub-namespaces (i.e. all namespaces starting with ''Vendor\Lib\''). The second call would create an exception for this and make ''strict_types=0'' the default in ''Vendor\Lib\Sub\Name\Space'' (and sub-namespaces). A specific file in this namespace could then again override this default using a specific ''declare(strict_types=1);'' directive.+This would make ''strict_types=1'' the default in the namespace ''Vendor\Lib'' and all sub-namespaces (i.e. all namespaces starting with ''Vendor\Lib\''). A specific file in this namespace could of course override this default using a specific ''declare(strict_types=0);'' directive.
  
 ===== Motivation and Vision ===== ===== Motivation and Vision =====
Line 69: Line 68:
  
 <code php> <code php>
-function namespace_declare(string $namespace, array $directives) : void;+function namespace_declare(string $namespace, array $declares) : void;
 </code> </code>
  
-The given ''$directives'' will be used as default values for all code inside the namespace ''$namespace'' or a sub-namespace. A sub-namespace is any namespace that starts with ''$namespace . "\\"''(Note that namespaces are case-insensitive, so ''namespace_declare'' also applies case-insensitively.)+The given ''$declares'' will be used as default values for all code inside the namespace ''$namespace'' or a sub-namespace. A sub-namespace is any namespace that starts with ''$namespace . "\\"''Namespaces in PHP are case-insensitive, so ''namespace_declare'' also applies case-insensitively.
  
 If the provided ''$namespace'' is the empty string, an ''Error'' is thrown. It is explicitly not possible to specify a global default. If ''$namespace'' starts or ends with a backslash, an ''Error'' is thrown. If the provided ''$namespace'' is the empty string, an ''Error'' is thrown. It is explicitly not possible to specify a global default. If ''$namespace'' starts or ends with a backslash, an ''Error'' is thrown.
Line 78: Line 77:
 If ''namespace_declare'' was already called for a certain ''$namespace'', another call with the same namespace will result in an ''Error''. If ''namespace_declare'' was already called for a certain ''$namespace'', another call with the same namespace will result in an ''Error''.
  
-If code using ''$namespace'' or a sub-namespace has already been used (compiled or loaded), an ''Error'' is thrown. This avoids situations where code in a namespace is loaded, subsequently ''namespace_declare()'' is used and more code from the namespace is loaded. Without this check, code in the same namespace would end up using inconsistent declare directives.+If code using ''$namespace'' or a sub-namespace has already been loaded, an ''Error'' is thrown. This avoids situations where code in a namespace is loaded, subsequently ''namespace_declare()'' is used and more code from the namespace is loaded. Without this check, code in the same namespace would end up using inconsistent declare directives.
  
 ''namespace_declare'' has no impact on aliases created using ''class_alias'' and entities declared by internal code. ''namespace_declare'' has no impact on aliases created using ''class_alias'' and entities declared by internal code.
Line 125: Line 124:
  
 This restriction is introduced for two reasons: Firstly, lack of such a restriction would imply that language behavior can silently change in the middle of a single file, which would be very confusing. Secondly, there are are significant implementational complexities associated with allowing this type of code due to limitations of specific declare directives. In particular the current implementation of ''strict_types'' only permits a consistent ''strict_types'' value for a whole file. Lifting the declare-consistency requirement would require changing the ''strict_types'' implementation to support this and, more importantly, commitment to support this for all future declare directives we introduce, which may be non-trivial. This restriction is introduced for two reasons: Firstly, lack of such a restriction would imply that language behavior can silently change in the middle of a single file, which would be very confusing. Secondly, there are are significant implementational complexities associated with allowing this type of code due to limitations of specific declare directives. In particular the current implementation of ''strict_types'' only permits a consistent ''strict_types'' value for a whole file. Lifting the declare-consistency requirement would require changing the ''strict_types'' implementation to support this and, more importantly, commitment to support this for all future declare directives we introduce, which may be non-trivial.
 +
 +==== Supported declare directives ====
 +
 +Currently PHP supports three declare directives, ''ticks'', ''strict_types'' and ''encoding''.
 +
 +''namespace_declare()'' does not support ''encoding'' and will generate an ''Error'' if it is specified. The reason is that ''encoding'' has very special semantics, and requires the directive to be resolved already at parse-time, so that the lexer behavior may be influenced. At the point where the first namespace is encountered, it may already be too late to act on this directive.
 +
 +For ''ticks'' the passed value must be a non-negative integer, otherwise an ''Error'' is thrown.
 +
 +For ''strict_types'' the passed value must be integer ''0'' or ''1'', otherwise an ''Error'' is thrown.
  
 ==== Open Question: Handling of unknown directives ==== ==== Open Question: Handling of unknown directives ====
Line 132: Line 141:
 If we go for throwing a warning here, it might be beneficial to add a ''supports_declare()'' function, which allows you to determine whether a certain declare directive is supported, without resorting to a PHP version check (which would likely be unreliable with regard to alternative PHP implementations). If we go for throwing a warning here, it might be beneficial to add a ''supports_declare()'' function, which allows you to determine whether a certain declare directive is supported, without resorting to a PHP version check (which would likely be unreliable with regard to alternative PHP implementations).
  
-===== Challenges, Disadvantages, Alternatives =====+==== Open Question: Introspection functionality ====
  
-==== Technical challenges ====+It might be useful to also provide a mechanism to retrieve the active namespace-scoped declares at runtime, e.g. using a ''get_namespace_declares()'' function. One could either make this return the declarations for all namespaces exactly as given, or return the computed declarations for a specific namespace. I'm not sure what the specific use-case for this kind of introspection functionality would be, though.
  
-The implementation of this feature will be less simple than it may initially sound:+==== Implementation considerations ====
  
-  * Namespace-scoped declares will have to be taken into account by opcache. Namelyif a file is compiled with a certain set of namespace-scoped declares, it cannot necessarily be reused if it is compiled with a different set of declares. This could be solved by storing a checksum based on the namespace-scoped declares at the time of compilation together with the cached file and compare it when loading itI believe this can be done efficiently. +Declare directives have to be known at compile-timebecause they may directly influence the emitted opcodes. Files will always be compiled for the current declare configuration and opcache will cache them for that specific configuration. Opcache additionally stores which namespaces and namespace-scoped declares are used and will verify that the (relevant) namespace-scoped declares did not change when the file is loaded again. If the (relevant) namespace-scoped declares changedthe file will be invalidated and compiled again for the new configuration.
-  * If the open question "namespace_declare after namespace already used" is resolved in favor of forbidding such usesinformation about namespaces that have already been loaded needs to be stored by the runtimeThis requires opcache integration. (I consider this resolution likely.)+
  
-==== Disadvantages ====+===== Disadvantages =====
  
-=== Reduced explicitness ===+==== Reduced explicitness ====
  
 It could be argued that the introducing of namespace-scoped declares will make it less discoverable which declare values are active inside a given file, because they are no longer required to be specified at the top of the file. It could be argued that the introducing of namespace-scoped declares will make it less discoverable which declare values are active inside a given file, because they are no longer required to be specified at the top of the file.
Line 151: Line 159:
 Additionally it should be noted that the same problem (to an even worse degree) exists for the ini system, where ini options can be specified from many different sources (including multiple ini files, htaccess files and inline in PHP code). In practice this does not appear to be a major problem. Additionally it should be noted that the same problem (to an even worse degree) exists for the ini system, where ini options can be specified from many different sources (including multiple ini files, htaccess files and inline in PHP code). In practice this does not appear to be a major problem.
  
-=== Proliferation of declare directives ===+Finally, while namespace-scoped declares may be less explicit, they fit better into the mental model we use as programmers. Libraries generally do not haphazardly switch between different strict_types files and instead use a consistent mode for the entire project. Namespace-scoped declares codify this and prevent mistakes like forgetting to add a declare directive when creating a new file. 
 + 
 +==== Proliferation of declare directives ====
  
 While this RFC proposes specific functionality (namespace-scoped declares), the Motivation section outlined a likely future application of this mechanism, which is the introduction of additional declare directives that modify language behavior to be "stricter" in some sense, without breaking compatibility or interoperability. While this RFC proposes specific functionality (namespace-scoped declares), the Motivation section outlined a likely future application of this mechanism, which is the introduction of additional declare directives that modify language behavior to be "stricter" in some sense, without breaking compatibility or interoperability.
Line 163: Line 173:
 Nonetheless, I think that proliferation of declare directives is a real danger and we need to ensure that new directives are not added frivolously. Nonetheless, I think that proliferation of declare directives is a real danger and we need to ensure that new directives are not added frivolously.
  
-==== Alternatives ====+==== Discussion: Potential for abuse ==== 
 + 
 +One issue that came up repeatedly during the first discussion, is that people perceived a potential for abuse in this feature. The concern is that it would be possible to call ''namespace_declare()'' on a namespace one doesn't own, and consequently break code using that namespace. 
 + 
 +I honestly do not understand this concern. PHP is already oversaturated with ways in which you could break external library code if one wants to (such as hijacking autoloading). If breaking library code is your goal, you don't need this feature to achieve that. However, the question remains why anyone would want to this, as in the end you only sabotage yourself. 
 + 
 +===== Alternatives =====
  
 The main alternative to this proposal I see is the introduction of a "proper module system", which would allow per-module specification of declares, similar to package attributes in Java. However this is just a very vague concept in my mind and would certainly require major language changes. The main alternative to this proposal I see is the introduction of a "proper module system", which would allow per-module specification of declares, similar to package attributes in Java. However this is just a very vague concept in my mind and would certainly require major language changes.
Line 179: Line 195:
 ===== Patches and Tests ===== ===== Patches and Tests =====
  
-There is no implementation yet.+PR: https://github.com/php/php-src/pull/2972
  
  
Line 185: Line 201:
  
   * Resolve open question "Handling of unknown directives"   * Resolve open question "Handling of unknown directives"
-  * Consider adding some introspection functionality, such as ''get_namespace_declares()'' +  * Resolve open question "Introspection functionality"
-  * Investigate whether this mechanism can support the ''encoding'' directive, which is a lot more magic than the rest.+
rfc/namespace_scoped_declares.1512943412.txt.gz · Last modified: 2017/12/10 22:03 by nikic