|
| 1 | +Our Backwards Compatibility Promise |
| 2 | +=================================== |
| 3 | + |
| 4 | +Ensuring smooth upgrades of your projects is our first priority. That's why |
| 5 | +we promise you backwards compatibility (BC) for all minor Symfony releases. |
| 6 | +You probably recognize this strategy as `Semantic Versioning`_. In short, |
| 7 | +Semantic Versioning means that only major releases (such as 2.0, 3.0 etc.) are |
| 8 | +allowed to break backwards compatibility. Minor releases (such as 2.5, 2.6 etc.) |
| 9 | +may introduce new features, but must do so without breaking the existing API of |
| 10 | +that release branch (2.x in the previous example). |
| 11 | + |
| 12 | +.. caution:: |
| 13 | + |
| 14 | + This promise was introduced with Symfony 2.3 and does not apply to previous |
| 15 | + versions of Symfony. |
| 16 | + |
| 17 | +However, backwards compatibility comes in many different flavors. In fact, almost |
| 18 | +every change that we make to the framework can potentially break an application. |
| 19 | +For example, if we add a new method to a class, this will break an application |
| 20 | +which extended this class and added the same method, but with a different |
| 21 | +method signature. |
| 22 | + |
| 23 | +Also, not every BC break has the same impact on application code. While some BC |
| 24 | +breaks require you to make significant changes to your classes or your |
| 25 | +architecture, others are fixed as easily as changing the name of a method. |
| 26 | + |
| 27 | +That's why we created this page for you. The section "Using Symfony Code" will |
| 28 | +tell you how you can ensure that your application won't break completely when |
| 29 | +upgrading to a newer version of the same major release branch. |
| 30 | + |
| 31 | +The second section, "Working on Symfony Code", is targeted at Symfony |
| 32 | +contributors. This section lists detailed rules that every contributor needs to |
| 33 | +follow to ensure smooth upgrades for our users. |
| 34 | + |
| 35 | +Using Symfony Code |
| 36 | +------------------ |
| 37 | + |
| 38 | +If you are using Symfony in your projects, the following guidelines will help |
| 39 | +you to ensure smooth upgrades to all future minor releases of your Symfony |
| 40 | +version. |
| 41 | + |
| 42 | +Using Our Interfaces |
| 43 | +~~~~~~~~~~~~~~~~~~~~ |
| 44 | + |
| 45 | +All interfaces shipped with Symfony can be used in type hints. You can also call |
| 46 | +any of the methods that they declare. We guarantee that we won't break code that |
| 47 | +sticks to these rules. |
| 48 | + |
| 49 | +.. caution:: |
| 50 | + |
| 51 | + The exception to this rule are interfaces tagged with ``@internal``. Such |
| 52 | + interfaces should not be used or implemented. |
| 53 | + |
| 54 | +If you want to implement an interface, you should first make sure that the |
| 55 | +interface is an API interface. You can recognize API interfaces by the ``@api`` |
| 56 | +tag in their source code:: |
| 57 | + |
| 58 | + /** |
| 59 | + * HttpKernelInterface handles a Request to convert it to a Response. |
| 60 | + * |
| 61 | + * @author Fabien Potencier <fabien@symfony.com> |
| 62 | + * |
| 63 | + * @api |
| 64 | + */ |
| 65 | + interface HttpKernelInterface |
| 66 | + { |
| 67 | + // ... |
| 68 | + } |
| 69 | + |
| 70 | +If you implement an API interface, we promise that we won't ever break your |
| 71 | +code. Regular interfaces, by contrast, may be extended between minor releases, |
| 72 | +for example by adding a new method. Be prepared to upgrade your code manually |
| 73 | +if you implement a regular interface. |
| 74 | + |
| 75 | +.. note:: |
| 76 | + |
| 77 | + Even if we do changes that require manual upgrades, we limit ourselves to |
| 78 | + changes that can be upgraded easily. We will always document the precise |
| 79 | + upgrade instructions in the UPGRADE file in Symfony's root directory. |
| 80 | + |
| 81 | +The following table explains in detail which use cases are covered by our |
| 82 | +backwards compatibility promise: |
| 83 | + |
| 84 | ++-----------------------------------------------+---------------+---------------+ |
| 85 | +| Use Case | Regular | API | |
| 86 | ++===============================================+===============+===============+ |
| 87 | +| **If you...** | **Then we guarantee BC...** | |
| 88 | ++-----------------------------------------------+---------------+---------------+ |
| 89 | +| Type hint against the interface | Yes | Yes | |
| 90 | ++-----------------------------------------------+---------------+---------------+ |
| 91 | +| Call a method | Yes | Yes | |
| 92 | ++-----------------------------------------------+---------------+---------------+ |
| 93 | +| **If you implement the interface and...** | **Then we guarantee BC...** | |
| 94 | ++-----------------------------------------------+---------------+---------------+ |
| 95 | +| Implement a method | No [1]_ | Yes | |
| 96 | ++-----------------------------------------------+---------------+---------------+ |
| 97 | +| Add an argument to an implemented method | No [1]_ | Yes | |
| 98 | ++-----------------------------------------------+---------------+---------------+ |
| 99 | +| Add a default value to an argument | Yes | Yes | |
| 100 | ++-----------------------------------------------+---------------+---------------+ |
| 101 | + |
| 102 | +.. include:: _api_tagging.rst.inc |
| 103 | + |
| 104 | +Using Our Classes |
| 105 | +~~~~~~~~~~~~~~~~~ |
| 106 | + |
| 107 | +All classes provided by Symfony may be instantiated and accessed through their |
| 108 | +public methods and properties. |
| 109 | + |
| 110 | +.. caution:: |
| 111 | + |
| 112 | + Classes, properties and methods that bear the tag ``@internal`` as well as |
| 113 | + the classes located in the various ``*\\Tests\\`` namespaces are an |
| 114 | + exception to this rule. They are meant for internal use only and should |
| 115 | + not be accessed by your own code. |
| 116 | + |
| 117 | +Just like with interfaces, we also distinguish between regular and API classes. |
| 118 | +Like API interfaces, API classes are marked with an ``@api`` tag:: |
| 119 | + |
| 120 | + /** |
| 121 | + * Request represents an HTTP request. |
| 122 | + * |
| 123 | + * @author Fabien Potencier <fabien@symfony.com> |
| 124 | + * |
| 125 | + * @api |
| 126 | + */ |
| 127 | + class Request |
| 128 | + { |
| 129 | + // ... |
| 130 | + } |
| 131 | + |
| 132 | +The difference between regular and API classes is that we guarantee full |
| 133 | +backwards compatibility if you extend an API class and override its methods. We |
| 134 | +can't give the same promise for regular classes, because there we may, for |
| 135 | +example, add an optional argument to a method. Consequently, the signature of |
| 136 | +your overridden method wouldn't match anymore and generate a fatal error. |
| 137 | + |
| 138 | +.. note:: |
| 139 | + |
| 140 | + As with interfaces, we limit ourselves to changes that can be upgraded |
| 141 | + easily. We will document the precise ugprade instructions in the UPGRADE |
| 142 | + file in Symfony's root directory. |
| 143 | + |
| 144 | +In some cases, only specific properties and methods are tagged with the ``@api`` |
| 145 | +tag, even though their class is not. In these cases, we guarantee full backwards |
| 146 | +compatibility for the tagged properties and methods (as indicated in the column |
| 147 | +"API" below), but not for the rest of the class. |
| 148 | + |
| 149 | +To be on the safe side, check the following table to know which use cases are |
| 150 | +covered by our backwards compatibility promise: |
| 151 | + |
| 152 | ++-----------------------------------------------+---------------+---------------+ |
| 153 | +| Use Case | Regular | API | |
| 154 | ++===============================================+===============+===============+ |
| 155 | +| **If you...** | **Then we guarantee BC...** | |
| 156 | ++-----------------------------------------------+---------------+---------------+ |
| 157 | +| Type hint against the class | Yes | Yes | |
| 158 | ++-----------------------------------------------+---------------+---------------+ |
| 159 | +| Create a new instance | Yes | Yes | |
| 160 | ++-----------------------------------------------+---------------+---------------+ |
| 161 | +| Extend the class | Yes | Yes | |
| 162 | ++-----------------------------------------------+---------------+---------------+ |
| 163 | +| Access a public property | Yes | Yes | |
| 164 | ++-----------------------------------------------+---------------+---------------+ |
| 165 | +| Call a public method | Yes | Yes | |
| 166 | ++-----------------------------------------------+---------------+---------------+ |
| 167 | +| **If you extend the class and...** | **Then we guarantee BC...** | |
| 168 | ++-----------------------------------------------+---------------+---------------+ |
| 169 | +| Access a protected property | No [1]_ | Yes | |
| 170 | ++-----------------------------------------------+---------------+---------------+ |
| 171 | +| Call a protected method | No [1]_ | Yes | |
| 172 | ++-----------------------------------------------+---------------+---------------+ |
| 173 | +| Override a public property | Yes | Yes | |
| 174 | ++-----------------------------------------------+---------------+---------------+ |
| 175 | +| Override a protected property | No [1]_ | Yes | |
| 176 | ++-----------------------------------------------+---------------+---------------+ |
| 177 | +| Override a public method | No [1]_ | Yes | |
| 178 | ++-----------------------------------------------+---------------+---------------+ |
| 179 | +| Override a protected method | No [1]_ | Yes | |
| 180 | ++-----------------------------------------------+---------------+---------------+ |
| 181 | +| Add a new property | No | No | |
| 182 | ++-----------------------------------------------+---------------+---------------+ |
| 183 | +| Add a new method | No | No | |
| 184 | ++-----------------------------------------------+---------------+---------------+ |
| 185 | +| Add an argument to an overridden method | No [1]_ | Yes | |
| 186 | ++-----------------------------------------------+---------------+---------------+ |
| 187 | +| Add a default value to an argument | Yes | Yes | |
| 188 | ++-----------------------------------------------+---------------+---------------+ |
| 189 | +| Call a private method (via Reflection) | No | No | |
| 190 | ++-----------------------------------------------+---------------+---------------+ |
| 191 | +| Access a private property (via Reflection) | No | No | |
| 192 | ++-----------------------------------------------+---------------+---------------+ |
| 193 | + |
| 194 | +.. include:: _api_tagging.rst.inc |
| 195 | + |
| 196 | +Working on Symfony Code |
| 197 | +----------------------- |
| 198 | + |
| 199 | +Do you want to help us improve Symfony? That's great! However, please stick |
| 200 | +to the rules listed below in order to ensure smooth upgrades for our users. |
| 201 | + |
| 202 | +Changing Interfaces |
| 203 | +~~~~~~~~~~~~~~~~~~~ |
| 204 | + |
| 205 | +This table tells you which changes you are allowed to do when working on |
| 206 | +Symfony's interfaces: |
| 207 | + |
| 208 | +============================================== ============== ============== |
| 209 | +Type of Change Regular API |
| 210 | +============================================== ============== ============== |
| 211 | +Remove entirely No No |
| 212 | +Change name or namespace No No |
| 213 | +Add parent interface Yes [2]_ Yes [3]_ |
| 214 | +Remove parent interface No No |
| 215 | +**Methods** |
| 216 | +Add method Yes [2]_ No |
| 217 | +Remove method No No |
| 218 | +Change name No No |
| 219 | +Move to parent interface Yes Yes |
| 220 | +Add argument without a default value No No |
| 221 | +Add argument with a default value Yes [2]_ No |
| 222 | +Remove argument Yes [4]_ Yes [4]_ |
| 223 | +Add default value to an argument Yes [2]_ No |
| 224 | +Remove default value of an argument No No |
| 225 | +Add type hint to an argument No No |
| 226 | +Remove type hint of an argument Yes [2]_ No |
| 227 | +Change argument type Yes [2]_ [5]_ No |
| 228 | +Change return type Yes [2]_ [6]_ No |
| 229 | +============================================== ============== ============== |
| 230 | + |
| 231 | +Changing Classes |
| 232 | +~~~~~~~~~~~~~~~~ |
| 233 | + |
| 234 | +This table tells you which changes you are allowed to do when working on |
| 235 | +Symfony's classes: |
| 236 | + |
| 237 | +================================================== ============== ============== |
| 238 | +Type of Change Regular API |
| 239 | +================================================== ============== ============== |
| 240 | +Remove entirely No No |
| 241 | +Make final Yes [2]_ No |
| 242 | +Make abstract No No |
| 243 | +Change name or namespace No No |
| 244 | +Change parent class Yes [7]_ Yes [7]_ |
| 245 | +Add interface Yes Yes |
| 246 | +Remove interface No No |
| 247 | +**Public Properties** |
| 248 | +Add public property Yes Yes |
| 249 | +Remove public property No No |
| 250 | +Reduce visibility No No |
| 251 | +Move to parent class Yes Yes |
| 252 | +**Protected Properties** |
| 253 | +Add protected property Yes Yes |
| 254 | +Remove protected property Yes [2]_ No |
| 255 | +Reduce visibility Yes [2]_ No |
| 256 | +Move to parent class Yes Yes |
| 257 | +**Private Properties** |
| 258 | +Add private property Yes Yes |
| 259 | +Remove private property Yes Yes |
| 260 | +**Constructors** |
| 261 | +Add constructor without mandatory arguments Yes [2]_ Yes [2]_ |
| 262 | +Remove constructor Yes [2]_ No |
| 263 | +Reduce visibility of a public constructor No No |
| 264 | +Reduce visibility of a protected constructor Yes [2]_ No |
| 265 | +Move to parent class Yes Yes |
| 266 | +**Public Methods** |
| 267 | +Add public method Yes Yes |
| 268 | +Remove public method No No |
| 269 | +Change name No No |
| 270 | +Reduce visibility No No |
| 271 | +Move to parent class Yes Yes |
| 272 | +Add argument without a default value No No |
| 273 | +Add argument with a default value Yes [2]_ No |
| 274 | +Remove argument Yes [4]_ Yes [4]_ |
| 275 | +Add default value to an argument Yes [2]_ No |
| 276 | +Remove default value of an argument No No |
| 277 | +Add type hint to an argument Yes [8]_ No |
| 278 | +Remove type hint of an argument Yes [2]_ No |
| 279 | +Change argument type Yes [2]_ [5]_ No |
| 280 | +Change return type Yes [2]_ [6]_ No |
| 281 | +**Protected Methods** |
| 282 | +Add protected method Yes Yes |
| 283 | +Remove protected method Yes [2]_ No |
| 284 | +Change name No No |
| 285 | +Reduce visibility Yes [2]_ No |
| 286 | +Move to parent class Yes Yes |
| 287 | +Add argument without a default value Yes [2]_ No |
| 288 | +Add argument with a default value Yes [2]_ No |
| 289 | +Remove argument Yes [4]_ Yes [4]_ |
| 290 | +Add default value to an argument Yes [2]_ No |
| 291 | +Remove default value of an argument Yes [2]_ No |
| 292 | +Add type hint to an argument Yes [2]_ No |
| 293 | +Remove type hint of an argument Yes [2]_ No |
| 294 | +Change argument type Yes [2]_ [5]_ No |
| 295 | +Change return type Yes [2]_ [6]_ No |
| 296 | +**Private Methods** |
| 297 | +Add private method Yes Yes |
| 298 | +Remove private method Yes Yes |
| 299 | +Change name Yes Yes |
| 300 | +Reduce visibility Yes Yes |
| 301 | +Add argument without a default value Yes Yes |
| 302 | +Add argument with a default value Yes Yes |
| 303 | +Remove argument Yes Yes |
| 304 | +Add default value to an argument Yes Yes |
| 305 | +Remove default value of an argument Yes Yes |
| 306 | +Add type hint to an argument Yes Yes |
| 307 | +Remove type hint of an argument Yes Yes |
| 308 | +Change argument type Yes Yes |
| 309 | +Change return type Yes Yes |
| 310 | +================================================== ============== ============== |
| 311 | + |
| 312 | +.. [1] Your code may be broken by changes in the Symfony code. Such changes will |
| 313 | + however be documented in the UPGRADE file. |
| 314 | +
|
| 315 | +.. [2] Should be avoided. When done, this change must be documented in the |
| 316 | + UPGRADE file. |
| 317 | +
|
| 318 | +.. [3] The added parent interface must not introduce any new methods that don't |
| 319 | + exist in the interface already. |
| 320 | +
|
| 321 | +.. [4] Only the last argument(s) of a method may be removed, as PHP does not |
| 322 | + care about additional arguments that you pass to a method. |
| 323 | +
|
| 324 | +.. [5] The argument type may only be changed to a compatible or less specific |
| 325 | + type. The following type changes are allowed: |
| 326 | +
|
| 327 | + =================== ================================================================== |
| 328 | + Original Type New Type |
| 329 | + =================== ================================================================== |
| 330 | + boolean any `scalar type`_ with equivalent `boolean values`_ |
| 331 | + string any `scalar type`_ or object with equivalent `string values`_ |
| 332 | + integer any `scalar type`_ with equivalent `integer values`_ |
| 333 | + float any `scalar type`_ with equivalent `float values`_ |
| 334 | + class ``<C>`` any superclass or interface of ``<C>`` |
| 335 | + interface ``<I>`` any superinterface of ``<I>`` |
| 336 | + =================== ================================================================== |
| 337 | +
|
| 338 | +.. [6] The return type may only be changed to a compatible or more specific |
| 339 | + type. The following type changes are allowed: |
| 340 | +
|
| 341 | + =================== ================================================================== |
| 342 | + Original Type New Type |
| 343 | + =================== ================================================================== |
| 344 | + boolean any `scalar type`_ with equivalent `boolean values`_ |
| 345 | + string any `scalar type`_ or object with equivalent `string values`_ |
| 346 | + integer any `scalar type`_ with equivalent `integer values`_ |
| 347 | + float any `scalar type`_ with equivalent `float values`_ |
| 348 | + array instance of ``ArrayAccess``, ``Traversable`` and ``Countable`` |
| 349 | + ``ArrayAccess`` array |
| 350 | + ``Traversable`` array |
| 351 | + ``Countable`` array |
| 352 | + class ``<C>`` any subclass of ``<C>`` |
| 353 | + interface ``<I>`` any subinterface or implementing class of ``<I>`` |
| 354 | + =================== ================================================================== |
| 355 | +
|
| 356 | +.. [7] When changing the parent class, the original parent class must remain an |
| 357 | + ancestor of the class. |
| 358 | +
|
| 359 | +.. [8] A type hint may only be added if passing a value with a different type |
| 360 | + previously generated a fatal error. |
| 361 | +
|
| 362 | +.. _Semantic Versioning: http://semver.org/ |
| 363 | +.. _scalar type: http://php.net/manual/en/function.is-scalar.php |
| 364 | +.. _boolean values: http://php.net/manual/en/function.boolval.php |
| 365 | +.. _string values: http://www.php.net/manual/en/function.strval.php |
| 366 | +.. _integer values: http://www.php.net/manual/en/function.intval.php |
| 367 | +.. _float values: http://www.php.net/manual/en/function.floatval.php |
0 commit comments