From 5b689d618ff4d9e068e7fd4156b2c807ee67dc8a Mon Sep 17 00:00:00 2001 From: Larry Garfield Date: Sat, 6 Sep 2025 12:04:49 -0500 Subject: [PATCH 1/4] Add a Pure attribute for functions and methods. --- src/Pure.php | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 src/Pure.php diff --git a/src/Pure.php b/src/Pure.php new file mode 100644 index 0000000..6dad661 --- /dev/null +++ b/src/Pure.php @@ -0,0 +1,34 @@ + Date: Tue, 21 Oct 2025 20:47:58 -0500 Subject: [PATCH 2/4] Update Pure attribute to the new template. --- src/Pure.php | 60 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 47 insertions(+), 13 deletions(-) diff --git a/src/Pure.php b/src/Pure.php index 6dad661..64e73cb 100644 --- a/src/Pure.php +++ b/src/Pure.php @@ -7,28 +7,62 @@ /** * Indicates that a function or method is a "pure" function. * - * A pure function is a function or method that has the following properties: + * ## Target audience * - * 1. The function return values are identical for identical arguments (no variation with local static variables, - * non-local variables, mutable reference arguments or input streams, i.e., referential transparency). - * 2. The function has no side effects (no mutation of non-local variables, mutable reference - * arguments or input/output streams). + * Implementors + * - Static analysis tooling + * - Code compilation and optimization tooling (such as for compiled containers + * or event dispatchers, etc.) + * Users + * - Users who want their static analysis tools to double-check their use of + * pure functions. + * + * ## Purpose + * + * A pure function is a function or method that has the following properties, + * per [Wikipedia](https://en.wikipedia.org/wiki/Pure_function): + * + * 1. The function return values are identical for identical arguments + * (no variation with local static variables, non-local variables, mutable + * reference arguments or input streams, i.e., referential transparency). + * 2. The function has no side effects (no mutation of non-local variables, + * mutable reference arguments or input/output streams). * * In PHP, that means a pure function MUST NOT: * * 1. Use or modify any global variable. * 2. Perform any IO operations, even read-only ones. - * 3. Modify any property of an object provided to it as an argument, even transitively. - * 4. Read from an object property on the same object unless that property is `readonly`. - * 5. Call any function that is not also marked "pure." (It may invoke a callable passed to it as an explicit argument.) + * 3. Modify any property of an object provided to it as an argument, + * even transitively. + * 4. Read from an object property on the same object unless that property + * is `readonly`. + * 5. Accept a parameter by reference. + * 6. Call any function that is not also marked "pure." (It may invoke a + * callable passed to it as an explicit argument.) + * + * ## When should the attribute be applied + * + * When a user marks a function or method as pure, it means they are asserting + * that the function conforms to the rules above. + * + * If this attribute is placed on a method in an interface, it means that all + * implementations of that method MUST themselves be marked pure. + * + * Static analysis tools SHOULD + * - Verify that the function indeed meets the rules above, and treat it as + * an error if not. * - * Many functions in the PHP standard library are already pure. Implementers MUST treat those as acceptable to call - * from a pure function. + * Static analysis tools MUST + * - Treat PHP standard library functions that conform to these rules as pure. + * As an example, `strtolower()` is pure. `sort()` is not. + * - Flag as an error any function that is marked pure but is demonstrably not. + * - Treat any method implementing an interface method marked pure as pure. * - * Implementers MAY choose to implement optimizations based on the information that a function is pure, such as caching. + * Optimization tools and pre-compilation tools MAY: + * - Implement optimizations based on the knowledge that a function is pure. + * For example, they may safely cache its results indefinitely, or inline its + * code into another routine. * - * If this attribute is placed on a method in an interface, it means that all implementations of that method MUST - * themselves be marked pure. Implementers MUST enforce this rule. */ #[\Attribute(\Attribute::TARGET_FUNCTION | \Attribute::TARGET_METHOD)] class Pure {} From 99888ebe8f6a3206c87656d560bc7c641123c4e0 Mon Sep 17 00:00:00 2001 From: Larry Garfield Date: Sun, 26 Oct 2025 10:35:59 -0500 Subject: [PATCH 3/4] Move SHOULD/MUST statements to each bullet point Co-authored-by: Andreas Heigl --- src/Pure.php | 47 +++++++++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/src/Pure.php b/src/Pure.php index 64e73cb..6ad555d 100644 --- a/src/Pure.php +++ b/src/Pure.php @@ -28,17 +28,17 @@ * 2. The function has no side effects (no mutation of non-local variables, * mutable reference arguments or input/output streams). * - * In PHP, that means a pure function MUST NOT: + * In PHP, that means a pure function: * - * 1. Use or modify any global variable. - * 2. Perform any IO operations, even read-only ones. - * 3. Modify any property of an object provided to it as an argument, - * even transitively. - * 4. Read from an object property on the same object unless that property - * is `readonly`. - * 5. Accept a parameter by reference. - * 6. Call any function that is not also marked "pure." (It may invoke a - * callable passed to it as an explicit argument.) + * 1. MUST NOT use or modify any global variable. + * 2. MIST NOT perform any IO operations, even read-only ones. + * 3. MUST NOT modify any property of an object provided to it as an + * argument, even transitively. + * 4. MUST NOT read from an object property on the same object unless + * that property is `readonly`. + * 5. MUST NOT accept a parameter by reference. + * 6. MUST NOT call any function that is not also marked "pure." (It + * may invoke a callable passed to it as an explicit argument.) * * ## When should the attribute be applied * @@ -48,20 +48,23 @@ * If this attribute is placed on a method in an interface, it means that all * implementations of that method MUST themselves be marked pure. * - * Static analysis tools SHOULD - * - Verify that the function indeed meets the rules above, and treat it as - * an error if not. + * Static analysis tools + * - SHOULD verify that the function indeed meets the rules above, + * and treat it as an error if not. * - * Static analysis tools MUST - * - Treat PHP standard library functions that conform to these rules as pure. - * As an example, `strtolower()` is pure. `sort()` is not. - * - Flag as an error any function that is marked pure but is demonstrably not. - * - Treat any method implementing an interface method marked pure as pure. + * Static analysis tools + * - MUST treat PHP standard library functions that conform to these + * rules as pure. As an example, `strtolower()` is pure. `sort()` + * is not. + * - MUST flag as an error any function that is marked pure but is + * demonstrably not. + * - MUST treat any method implementing an interface method marked + * pure as pure. * - * Optimization tools and pre-compilation tools MAY: - * - Implement optimizations based on the knowledge that a function is pure. - * For example, they may safely cache its results indefinitely, or inline its - * code into another routine. + * Optimization tools and pre-compilation tools: + * - MAY implement optimizations based on the knowledge that a function + * is pure. For example, they may safely cache its results indefinitely, + * or inline its code into another routine. * */ #[\Attribute(\Attribute::TARGET_FUNCTION | \Attribute::TARGET_METHOD)] From 1b9b88eca0303fad2f8af69d7304a8817da2cc6c Mon Sep 17 00:00:00 2001 From: Larry Garfield Date: Sun, 26 Oct 2025 10:40:23 -0500 Subject: [PATCH 4/4] Combine sections now that the SHOULD/MUST is repeated. --- src/Pure.php | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/Pure.php b/src/Pure.php index 6ad555d..2acf00b 100644 --- a/src/Pure.php +++ b/src/Pure.php @@ -32,12 +32,12 @@ * * 1. MUST NOT use or modify any global variable. * 2. MIST NOT perform any IO operations, even read-only ones. - * 3. MUST NOT modify any property of an object provided to it as an + * 3. MUST NOT modify any property of an object provided to it as an * argument, even transitively. - * 4. MUST NOT read from an object property on the same object unless + * 4. MUST NOT read from an object property on the same object unless * that property is `readonly`. * 5. MUST NOT accept a parameter by reference. - * 6. MUST NOT call any function that is not also marked "pure." (It + * 6. MUST NOT call any function that is not also marked "pure." (It * may invoke a callable passed to it as an explicit argument.) * * ## When should the attribute be applied @@ -49,21 +49,19 @@ * implementations of that method MUST themselves be marked pure. * * Static analysis tools - * - SHOULD verify that the function indeed meets the rules above, + * - SHOULD verify that the function indeed meets the rules above, * and treat it as an error if not. - * - * Static analysis tools - * - MUST treat PHP standard library functions that conform to these + * - MUST treat PHP standard library functions that conform to these * rules as pure. As an example, `strtolower()` is pure. `sort()` * is not. - * - MUST flag as an error any function that is marked pure but is + * - MUST flag as an error any function that is marked pure but is * demonstrably not. * - MUST treat any method implementing an interface method marked * pure as pure. * * Optimization tools and pre-compilation tools: - * - MAY implement optimizations based on the knowledge that a function - * is pure. For example, they may safely cache its results indefinitely, + * - MAY implement optimizations based on the knowledge that a function + * is pure. For example, they may safely cache its results indefinitely, * or inline its code into another routine. * */