1<?php
2declare(strict_types = 1);
3namespace TYPO3\CMS\Core\Compatibility;
4
5/*
6 * This file is part of the TYPO3 CMS project.
7 *
8 * It is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, either version 2
10 * of the License, or any later version.
11 *
12 * For the full copyright and license information, please read the
13 * LICENSE.txt file that was distributed with this source code.
14 *
15 * The TYPO3 project - inspiring people to share!
16 */
17
18/**
19 * Trait to support the logging of deprecation of public properties.
20 *
21 * This is useful due to the long list of PHP4 properties have been set to
22 * public previously, which should be removed or moved to "protected" / "private".
23 *
24 * Usage:
25 *
26 * - Use this trait for the class with the properties to change the visibility status or to be removed.
27 * - Set internal class properties to protected.
28 * - Add the phpDoc tag "private" to the property (so IDEs understand that).
29 * - Remove this tag with the next major version.
30 * - Remove trait after last deprecation.
31 *
32 * Note:
33 *
34 * Use this trait for classes only that do not make use of magic accessors otherwise.
35 *
36 * Example usage:
37 *
38 *
39 * class MyControllerClass {
40 *     use PublicPropertyDeprecationTrait;
41 *
42 *     /**
43 *       * List previously publically accessible variables
44 *       * @var array
45 *       *...
46 *     private $deprecatedPublicProperties = [
47 *         'myProperty' => 'Using myProperty is deprecated and will not be possible anymore in TYPO3 v10.0. Use getMyProperty() instead.'
48 *     ];
49 *
50 *     /**
51 *      * This is my property.
52 *      *
53 *      * @var bool
54 *      * @deprecated (if deprecated)
55 *      * @private (if switched to private)
56 *      /
57 *     protected $myProperty = true;
58 * }
59 */
60
61/**
62 * This trait has no public properties by default, ensure to add a $deprecatedPublicProperties to your class
63 * when using this trait.
64 */
65trait PublicPropertyDeprecationTrait
66{
67    /**
68     * Checks if the property of the given name is set.
69     *
70     * Unmarked protected properties must return false as usual.
71     * Marked properties are evaluated by isset().
72     *
73     * This method is not called for public properties.
74     *
75     * @property array $deprecatedPublicProperties List of deprecated public properties
76     * @param string $propertyName
77     * @return bool
78     */
79    public function __isset(string $propertyName)
80    {
81        if (isset($this->deprecatedPublicProperties[$propertyName])) {
82            trigger_error($this->deprecatedPublicProperties[$propertyName], E_USER_DEPRECATED);
83            return isset($this->$propertyName);
84        }
85        return false;
86    }
87
88    /**
89     * Gets the value of the property of the given name if tagged.
90     *
91     * The evaluation is done in the assumption that this method is never
92     * reached for a public property.
93     *
94     * @property array $deprecatedPublicProperties List of deprecated public properties
95     * @param string $propertyName
96     * @return mixed
97     */
98    public function __get(string $propertyName)
99    {
100        if (isset($this->deprecatedPublicProperties[$propertyName])) {
101            trigger_error($this->deprecatedPublicProperties[$propertyName], E_USER_DEPRECATED);
102        }
103        return $this->$propertyName;
104    }
105
106    /**
107     * Sets the property of the given name if tagged.
108     *
109     * Additionally it's allowed to set unknown properties.
110     *
111     * The evaluation is done in the assumption that this method is never
112     * reached for a public property.
113     *
114     * @property array $deprecatedPublicProperties List of deprecated public properties
115     * @param string $propertyName
116     * @param mixed $propertyValue
117     */
118    public function __set(string $propertyName, $propertyValue)
119    {
120        // It's allowed to set an unknown property as public, the check is thus necessary
121        if (property_exists($this, $propertyName) && isset($this->deprecatedPublicProperties[$propertyName])) {
122            trigger_error($this->deprecatedPublicProperties[$propertyName], E_USER_DEPRECATED);
123        }
124        $this->$propertyName = $propertyValue;
125    }
126
127    /**
128     * Unsets the property of the given name if tagged.
129     *
130     * @property array $deprecatedPublicProperties List of deprecated public properties
131     * @param string $propertyName
132     */
133    public function __unset(string $propertyName)
134    {
135        if (isset($this->deprecatedPublicProperties[$propertyName])) {
136            trigger_error($this->deprecatedPublicProperties[$propertyName], E_USER_DEPRECATED);
137        }
138        unset($this->$propertyName);
139    }
140}
141