[
  {
    "path": "CODEOWNERS",
    "content": "* @php-fig/secretaries\n/proposed/security* @php-fig/psr-9-10\n/proposed/phpdoc* @php-fig/psr-5\n/proposed/clock* @php-fig/psr-20\n/proposed/internationalization* @php-fig/psr-21\n/proposed/tracing* @php-fig/psr-22\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing to the PHP-FIG\n\nAnybody who subscribes to the Google Group, is part of the PHP-FIG. As soon as\nyou subscribe to the [mailing list](http://groups.google.com/group/php-fig/)\nand/or join the [Discord Server](https://discord.gg/php-fig) you are a PHP-FIG\nCommunity Member, who can influence standards, make suggestions, give feedback,\netc. Only PHP-FIG Voting Members can start or participate in votes, but the\ndiscussion and formation stages involve everyone.\n\nSee the [PHP-FIG FAQ](https://www.php-fig.org/faqs/) for more information.\n\n# Licensing\n\nBy contributing code you agree to license your contribution under the MIT\nlicense.\n\nBy contributing documentation, examples, or any other non-code assets you agree\nto license your contribution under the CC BY 3.0 license. Attribution shall be\ngiven according to the current bylaws of this group.\n\n# Merge & Access Policy\n\nAll Editors, Coordinators and Sponsors of specifications in draft & review stage\nhave access to push to this (php-fig/fig-standards) repository; subject to\nsecretary discretion\n\nAll Editors, Coordinators and Sponsors of specifications have push access to utility\nand interface repositories and retrain this even after acceptance; subject to secretary\ndiscretion.\n\nThe master branch of all repositories are protected and therefore cannot be forced\npushed to.\n\nSecretaries have, and are the only ones to have, full administrative access to all\nrepositories and to the GitHub organisation.\n\n## Guidelines for merging\n\n* Never force push to any branch on a repository in the php-fig organisation\n* All changes must go through pull requests, a commit should never be pushed\ndirectly (excluding initial commits on new interface/util repositories) to master\n* All pull requests relating to a draft PSR must be approved (with a formal +1\ncomment) or merged by the PSR Editor, except in the review phase when the coordinator\nshould seek comment from the editor, but merging is at the coordinator's discretion\n* You must never merge a pull request that affects any file in the repository\nother than those you are on a working group for; you should request a secretary\nor member of that working group (mention @php-fig/psr-x) do so\n* You should never merge your own pull request\n* A change should never be merged to an accepted PSR without approval from\nsecretaries, who will attempt to seek confirmation from the former Editors\n* A change to bylaws shouldn't be merged by anyone other than a secretary\n* Pull requests may be triaged (have labels applied) by anyone with push access,\nno matter which PSR they are on the working group for or which PSR it affects; but\nthey cannot close a pull request or issue affecting other PSRs\n* After approval of a specification, all merges to an interface or utility repository\nmust be approved by a secretary; who is required to give suitable notice and seek\ncomment from the working group team, but it is not required that they approve\n* Tags on utility and interface repositories should be created and PGP signed by\nSecretaries, who should publish their PGP public keys and register them on GitHub\n\nThese guidelines are subject to exceptions and changes at secretaries discretion.\nShould you have any questions please contact the secretaries on info [at] php-fig\n[dot] org. Failure to comply with guidelines will result in revokation of merge\naccess. Merge access is a privilege and not a right.\n\n# Tagging\n\nTagging on utility and interface repository should be done regularly, ideally after\nevery merge, or every batch of merges after PSR approval.\n\nVersioning should follow semantic versioning and primarily just be simple patch\nfix increments (following semantic versioning). The first 1.0.0 tag should be\ncreated on PSR approval.\n\nAll tags should be PGP signed.\n\nA changelog should be provided including a list of changes, crediting the\ncontributor and referencing the pull request/issue.\n"
  },
  {
    "path": "LICENSE-CC.md",
    "content": "Creative Commons Legal Code\n\nAttribution 3.0 Unported\n\n    CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE\n    LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN\n    ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS\n    INFORMATION ON AN \"AS-IS\" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES\n    REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR\n    DAMAGES RESULTING FROM ITS USE.\n\nLicense\n\nTHE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE\nCOMMONS PUBLIC LICENSE (\"CCPL\" OR \"LICENSE\"). THE WORK IS PROTECTED BY\nCOPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS\nAUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.\n\nBY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE\nTO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY\nBE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS\nCONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND\nCONDITIONS.\n\n1. Definitions\n\n a. \"Adaptation\" means a work based upon the Work, or upon the Work and\n    other pre-existing works, such as a translation, adaptation,\n    derivative work, arrangement of music or other alterations of a\n    literary or artistic work, or phonogram or performance and includes\n    cinematographic adaptations or any other form in which the Work may be\n    recast, transformed, or adapted including in any form recognizably\n    derived from the original, except that a work that constitutes a\n    Collection will not be considered an Adaptation for the purpose of\n    this License. For the avoidance of doubt, where the Work is a musical\n    work, performance or phonogram, the synchronization of the Work in\n    timed-relation with a moving image (\"synching\") will be considered an\n    Adaptation for the purpose of this License.\n b. \"Collection\" means a collection of literary or artistic works, such as\n    encyclopedias and anthologies, or performances, phonograms or\n    broadcasts, or other works or subject matter other than works listed\n    in Section 1(f) below, which, by reason of the selection and\n    arrangement of their contents, constitute intellectual creations, in\n    which the Work is included in its entirety in unmodified form along\n    with one or more other contributions, each constituting separate and\n    independent works in themselves, which together are assembled into a\n    collective whole. A work that constitutes a Collection will not be\n    considered an Adaptation (as defined above) for the purposes of this\n    License.\n c. \"Distribute\" means to make available to the public the original and\n    copies of the Work or Adaptation, as appropriate, through sale or\n    other transfer of ownership.\n d. \"Licensor\" means the individual, individuals, entity or entities that\n    offer(s) the Work under the terms of this License.\n e. \"Original Author\" means, in the case of a literary or artistic work,\n    the individual, individuals, entity or entities who created the Work\n    or if no individual or entity can be identified, the publisher; and in\n    addition (i) in the case of a performance the actors, singers,\n    musicians, dancers, and other persons who act, sing, deliver, declaim,\n    play in, interpret or otherwise perform literary or artistic works or\n    expressions of folklore; (ii) in the case of a phonogram the producer\n    being the person or legal entity who first fixes the sounds of a\n    performance or other sounds; and, (iii) in the case of broadcasts, the\n    organization that transmits the broadcast.\n f. \"Work\" means the literary and/or artistic work offered under the terms\n    of this License including without limitation any production in the\n    literary, scientific and artistic domain, whatever may be the mode or\n    form of its expression including digital form, such as a book,\n    pamphlet and other writing; a lecture, address, sermon or other work\n    of the same nature; a dramatic or dramatico-musical work; a\n    choreographic work or entertainment in dumb show; a musical\n    composition with or without words; a cinematographic work to which are\n    assimilated works expressed by a process analogous to cinematography;\n    a work of drawing, painting, architecture, sculpture, engraving or\n    lithography; a photographic work to which are assimilated works\n    expressed by a process analogous to photography; a work of applied\n    art; an illustration, map, plan, sketch or three-dimensional work\n    relative to geography, topography, architecture or science; a\n    performance; a broadcast; a phonogram; a compilation of data to the\n    extent it is protected as a copyrightable work; or a work performed by\n    a variety or circus performer to the extent it is not otherwise\n    considered a literary or artistic work.\n g. \"You\" means an individual or entity exercising rights under this\n    License who has not previously violated the terms of this License with\n    respect to the Work, or who has received express permission from the\n    Licensor to exercise rights under this License despite a previous\n    violation.\n h. \"Publicly Perform\" means to perform public recitations of the Work and\n    to communicate to the public those public recitations, by any means or\n    process, including by wire or wireless means or public digital\n    performances; to make available to the public Works in such a way that\n    members of the public may access these Works from a place and at a\n    place individually chosen by them; to perform the Work to the public\n    by any means or process and the communication to the public of the\n    performances of the Work, including by public digital performance; to\n    broadcast and rebroadcast the Work by any means including signs,\n    sounds or images.\n i. \"Reproduce\" means to make copies of the Work by any means including\n    without limitation by sound or visual recordings and the right of\n    fixation and reproducing fixations of the Work, including storage of a\n    protected performance or phonogram in digital form or other electronic\n    medium.\n\n2. Fair Dealing Rights. Nothing in this License is intended to reduce,\nlimit, or restrict any uses free from copyright or rights arising from\nlimitations or exceptions that are provided for in connection with the\ncopyright protection under copyright law or other applicable laws.\n\n3. License Grant. Subject to the terms and conditions of this License,\nLicensor hereby grants You a worldwide, royalty-free, non-exclusive,\nperpetual (for the duration of the applicable copyright) license to\nexercise the rights in the Work as stated below:\n\n a. to Reproduce the Work, to incorporate the Work into one or more\n    Collections, and to Reproduce the Work as incorporated in the\n    Collections;\n b. to create and Reproduce Adaptations provided that any such Adaptation,\n    including any translation in any medium, takes reasonable steps to\n    clearly label, demarcate or otherwise identify that changes were made\n    to the original Work. For example, a translation could be marked \"The\n    original work was translated from English to Spanish,\" or a\n    modification could indicate \"The original work has been modified.\";\n c. to Distribute and Publicly Perform the Work including as incorporated\n    in Collections; and,\n d. to Distribute and Publicly Perform Adaptations.\n e. For the avoidance of doubt:\n\n     i. Non-waivable Compulsory License Schemes. In those jurisdictions in\n        which the right to collect royalties through any statutory or\n        compulsory licensing scheme cannot be waived, the Licensor\n        reserves the exclusive right to collect such royalties for any\n        exercise by You of the rights granted under this License;\n    ii. Waivable Compulsory License Schemes. In those jurisdictions in\n        which the right to collect royalties through any statutory or\n        compulsory licensing scheme can be waived, the Licensor waives the\n        exclusive right to collect such royalties for any exercise by You\n        of the rights granted under this License; and,\n   iii. Voluntary License Schemes. The Licensor waives the right to\n        collect royalties, whether individually or, in the event that the\n        Licensor is a member of a collecting society that administers\n        voluntary licensing schemes, via that society, from any exercise\n        by You of the rights granted under this License.\n\nThe above rights may be exercised in all media and formats whether now\nknown or hereafter devised. The above rights include the right to make\nsuch modifications as are technically necessary to exercise the rights in\nother media and formats. Subject to Section 8(f), all rights not expressly\ngranted by Licensor are hereby reserved.\n\n4. Restrictions. The license granted in Section 3 above is expressly made\nsubject to and limited by the following restrictions:\n\n a. You may Distribute or Publicly Perform the Work only under the terms\n    of this License. You must include a copy of, or the Uniform Resource\n    Identifier (URI) for, this License with every copy of the Work You\n    Distribute or Publicly Perform. You may not offer or impose any terms\n    on the Work that restrict the terms of this License or the ability of\n    the recipient of the Work to exercise the rights granted to that\n    recipient under the terms of the License. You may not sublicense the\n    Work. You must keep intact all notices that refer to this License and\n    to the disclaimer of warranties with every copy of the Work You\n    Distribute or Publicly Perform. When You Distribute or Publicly\n    Perform the Work, You may not impose any effective technological\n    measures on the Work that restrict the ability of a recipient of the\n    Work from You to exercise the rights granted to that recipient under\n    the terms of the License. This Section 4(a) applies to the Work as\n    incorporated in a Collection, but this does not require the Collection\n    apart from the Work itself to be made subject to the terms of this\n    License. If You create a Collection, upon notice from any Licensor You\n    must, to the extent practicable, remove from the Collection any credit\n    as required by Section 4(b), as requested. If You create an\n    Adaptation, upon notice from any Licensor You must, to the extent\n    practicable, remove from the Adaptation any credit as required by\n    Section 4(b), as requested.\n b. If You Distribute, or Publicly Perform the Work or any Adaptations or\n    Collections, You must, unless a request has been made pursuant to\n    Section 4(a), keep intact all copyright notices for the Work and\n    provide, reasonable to the medium or means You are utilizing: (i) the\n    name of the Original Author (or pseudonym, if applicable) if supplied,\n    and/or if the Original Author and/or Licensor designate another party\n    or parties (e.g., a sponsor institute, publishing entity, journal) for\n    attribution (\"Attribution Parties\") in Licensor's copyright notice,\n    terms of service or by other reasonable means, the name of such party\n    or parties; (ii) the title of the Work if supplied; (iii) to the\n    extent reasonably practicable, the URI, if any, that Licensor\n    specifies to be associated with the Work, unless such URI does not\n    refer to the copyright notice or licensing information for the Work;\n    and (iv) , consistent with Section 3(b), in the case of an Adaptation,\n    a credit identifying the use of the Work in the Adaptation (e.g.,\n    \"French translation of the Work by Original Author,\" or \"Screenplay\n    based on original Work by Original Author\"). The credit required by\n    this Section 4 (b) may be implemented in any reasonable manner;\n    provided, however, that in the case of a Adaptation or Collection, at\n    a minimum such credit will appear, if a credit for all contributing\n    authors of the Adaptation or Collection appears, then as part of these\n    credits and in a manner at least as prominent as the credits for the\n    other contributing authors. For the avoidance of doubt, You may only\n    use the credit required by this Section for the purpose of attribution\n    in the manner set out above and, by exercising Your rights under this\n    License, You may not implicitly or explicitly assert or imply any\n    connection with, sponsorship or endorsement by the Original Author,\n    Licensor and/or Attribution Parties, as appropriate, of You or Your\n    use of the Work, without the separate, express prior written\n    permission of the Original Author, Licensor and/or Attribution\n    Parties.\n c. Except as otherwise agreed in writing by the Licensor or as may be\n    otherwise permitted by applicable law, if You Reproduce, Distribute or\n    Publicly Perform the Work either by itself or as part of any\n    Adaptations or Collections, You must not distort, mutilate, modify or\n    take other derogatory action in relation to the Work which would be\n    prejudicial to the Original Author's honor or reputation. Licensor\n    agrees that in those jurisdictions (e.g. Japan), in which any exercise\n    of the right granted in Section 3(b) of this License (the right to\n    make Adaptations) would be deemed to be a distortion, mutilation,\n    modification or other derogatory action prejudicial to the Original\n    Author's honor and reputation, the Licensor will waive or not assert,\n    as appropriate, this Section, to the fullest extent permitted by the\n    applicable national law, to enable You to reasonably exercise Your\n    right under Section 3(b) of this License (right to make Adaptations)\n    but not otherwise.\n\n5. Representations, Warranties and Disclaimer\n\nUNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR\nOFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY\nKIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE,\nINCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY,\nFITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF\nLATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS,\nWHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION\nOF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU.\n\n6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE\nLAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR\nANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES\nARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS\nBEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n\n7. Termination\n\n a. This License and the rights granted hereunder will terminate\n    automatically upon any breach by You of the terms of this License.\n    Individuals or entities who have received Adaptations or Collections\n    from You under this License, however, will not have their licenses\n    terminated provided such individuals or entities remain in full\n    compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will\n    survive any termination of this License.\n b. Subject to the above terms and conditions, the license granted here is\n    perpetual (for the duration of the applicable copyright in the Work).\n    Notwithstanding the above, Licensor reserves the right to release the\n    Work under different license terms or to stop distributing the Work at\n    any time; provided, however that any such election will not serve to\n    withdraw this License (or any other license that has been, or is\n    required to be, granted under the terms of this License), and this\n    License will continue in full force and effect unless terminated as\n    stated above.\n\n8. Miscellaneous\n\n a. Each time You Distribute or Publicly Perform the Work or a Collection,\n    the Licensor offers to the recipient a license to the Work on the same\n    terms and conditions as the license granted to You under this License.\n b. Each time You Distribute or Publicly Perform an Adaptation, Licensor\n    offers to the recipient a license to the original Work on the same\n    terms and conditions as the license granted to You under this License.\n c. If any provision of this License is invalid or unenforceable under\n    applicable law, it shall not affect the validity or enforceability of\n    the remainder of the terms of this License, and without further action\n    by the parties to this agreement, such provision shall be reformed to\n    the minimum extent necessary to make such provision valid and\n    enforceable.\n d. No term or provision of this License shall be deemed waived and no\n    breach consented to unless such waiver or consent shall be in writing\n    and signed by the party to be charged with such waiver or consent.\n e. This License constitutes the entire agreement between the parties with\n    respect to the Work licensed here. There are no understandings,\n    agreements or representations with respect to the Work not specified\n    here. Licensor shall not be bound by any additional provisions that\n    may appear in any communication from You. This License may not be\n    modified without the mutual written agreement of the Licensor and You.\n f. The rights granted under, and the subject matter referenced, in this\n    License were drafted utilizing the terminology of the Berne Convention\n    for the Protection of Literary and Artistic Works (as amended on\n    September 28, 1979), the Rome Convention of 1961, the WIPO Copyright\n    Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996\n    and the Universal Copyright Convention (as revised on July 24, 1971).\n    These rights and subject matter take effect in the relevant\n    jurisdiction in which the License terms are sought to be enforced\n    according to the corresponding provisions of the implementation of\n    those treaty provisions in the applicable national law. If the\n    standard suite of rights granted under applicable copyright law\n    includes additional rights not granted under this License, such\n    additional rights are deemed to be included in the License; this\n    License is not intended to restrict the license of any rights under\n    applicable law.\n\nCreative Commons Notice\n\n    Creative Commons is not a party to this License, and makes no warranty\n    whatsoever in connection with the Work. Creative Commons will not be\n    liable to You or any party on any legal theory for any damages\n    whatsoever, including without limitation any general, special,\n    incidental or consequential damages arising in connection to this\n    license. Notwithstanding the foregoing two (2) sentences, if Creative\n    Commons has expressly identified itself as the Licensor hereunder, it\n    shall have all rights and obligations of Licensor.\n\n    Except for the limited purpose of indicating to the public that the\n    Work is licensed under the CCPL, Creative Commons does not authorize\n    the use by either party of the trademark \"Creative Commons\" or any\n    related trademark or logo of Creative Commons without the prior\n    written consent of Creative Commons. Any permitted use will be in\n    compliance with Creative Commons' then-current trademark usage\n    guidelines, as may be published on its website or otherwise made\n    available upon request from time to time. For the avoidance of doubt,\n    this trademark restriction does not form part of this License.\n\n    Creative Commons may be contacted at http://creativecommons.org/.\n"
  },
  {
    "path": "LICENSE-MIT.md",
    "content": "Copyright (c) 2013-2017 PHP Framework Interop Group\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n\n"
  },
  {
    "path": "LICENSE.md",
    "content": "# License\n\nUnless stated otherwise, all content is licensed under the Creative Commons\nAttribution License and code licensed under the MIT License.\n\nCopies of all licenses are included in this project's root directory."
  },
  {
    "path": "PER.md",
    "content": "# PHP Evolving Recommendations\n\nA PHP Evolving Recommendation is a meta document accompanied by one or more artifacts that are set to evolve over time with multiple releases.\nFollowing the [PER Workflow Bylaw][workflow], when a PER has the first release, it will be listed here.\n\nAs also described in the [Mission and Structure Bylaw][structure], the Editor of a working group working on a PER is essentially the lead contributor and writer, and they are supported by at least two voting members; the Sponsor, if present, is a Core Committee member that assists the Editor in keeping the evolution process on track.\n\n| Title                            | Editor         | Sponsor          | Last release(s)                              |\n|----------------------------------|----------------|------------------|----------------------------------------------|\n| [Coding Style][per-coding-style] | Larry Garfield | Chris Tankersley | [PER Coding Style][per-coding-style-release] |\n\n\n[workflow]: https://github.com/php-fig/fig-standards/blob/master/bylaws/003-per-workflow.md\n[structure]: https://github.com/php-fig/fig-standards/blob/master/bylaws/001-mission-and-structure.md\n[per-coding-style]: https://github.com/php-fig/per-coding-style/blob/1.0.0/spec.md\n[per-coding-style-release]: https://github.com/php-fig/per-coding-style/releases/latest\n"
  },
  {
    "path": "PSR.md",
    "content": "# PHP Standard Recommendations\n\nAccording to the [PSR Workflow Bylaw][workflow] each PSR has a status as it is being worked on. Once a proposal has passed the Entrance Vote it will be listed here as \"Draft\". Unless a PSR is marked as \"Accepted\" it is subject to change. Draft can change drastically, but Review will only have minor changes.\n\nAs also described in the [PSR Workflow Bylaw][workflow]. The Editor, or editors, of a proposal are essentially the lead contributors and writers of the PSRs and they are supported by two voting members. Those voting members are the Coordinator who is responsible for managing the review stage and votes; and a second sponsor.\n\n## Index by Status\n\n### Accepted\n\n| Num | Title                                | Maintainer                     |\n|:---:|--------------------------------------|--------------------------------|\n| 1   | [Basic Coding Standard][psr1]        | _vacant_                       |\n| 3   | [Logger Interface][psr3]             | Jordi Boggiano                 |\n| 4   | [Autoloading Standard][psr4]         | _vacant_                       |\n| 6   | [Caching Interface][psr6]            | Larry Garfield                 |\n| 7   | [HTTP Message Interface][psr7]       | Matthew Weier O'Phinney        |\n| 11  | [Container Interface][psr11]         | Matthieu Napoli, David Négrier |\n| 12  | [Extended Coding Style Guide][psr12] | Korvin Szanto                  |\n| 13  | [Hypermedia Links][psr13]            | Larry Garfield                 |\n| 14  | [Event Dispatcher][psr14]            | Larry Garfield                 |\n| 15  | [HTTP Handlers][psr15]               | Woody Gilk                     |\n| 16  | [Simple Cache][psr16]                | Paul Dragoonis                 |\n| 17  | [HTTP Factories][psr17]              | Woody Gilk                     |\n| 18  | [HTTP Client][psr18]                 | Tobias Nyholm                  |\n| 20  | [Clock][psr20]                       | Chris Seufert                  |\n\n### Draft\n\n| Num | Title                                | Editor(s)                      | Sponsor                        |\n|:---:|--------------------------------------|--------------------------------|--------------------------------|\n| 5   | [PHPDoc Standard][psr5]              | Chuck Burgess                  | Michael Cullum                 |\n| 19  | [PHPDoc tags][psr19]                 | Chuck Burgess                  | Michael Cullum                 |\n| 21  | [Internationalization][psr21]        | Navarr Barnier                 | Larry Garfield                 |\n| 22  | [Application Tracing][psr22]         | Adam Allport                   | Alessandro Chitolina           |\n\n### Abandoned\n\n| Num | Title                                | Editor(s)                      |\n|:---:|--------------------------------------|--------------------------------|\n| 8   | [Huggable Interface][psr8]           | Larry Garfield                 |\n| 9   | [Security Advisories][psr9]          | Michael Hess                   |\n| 10  | [Security Reporting Process][psr10]  | Michael Hess                   |\n\n### Deprecated\n\n| Num | Title                                |     |\n|:---:|--------------------------------------|-----|\n| 0   | [Autoloading Standard][psr0]         |     |\n| 2   | [Coding Style Guide][psr2]           |     |\n\n## Numerical Index\n\n| Num | Title                                | Editor(s) / Maintainers        | Status     |\n|:---:|--------------------------------------|--------------------------------|------------|\n| 0   | [Autoloading Standard][psr0]         |                                | Deprecated |\n| 1   | [Basic Coding Standard][psr1]        | _vacant_                       | Accepted   |\n| 2   | [Coding Style Guide][psr2]           |                                | Deprecated |\n| 3   | [Logger Interface][psr3]             | Jordi Boggiano                 | Accepted   |\n| 4   | [Autoloading Standard][psr4]         | _vacant_                       | Accepted   |\n| 5   | [PHPDoc Standard][psr5]              | Chuck Burgess                  | Draft      |\n| 6   | [Caching Interface][psr6]            | Larry Garfield                 | Accepted   |\n| 7   | [HTTP Message Interface][psr7]       | Matthew Weier O'Phinney        | Accepted   |\n| 8   | [Huggable Interface][psr8]           | Larry Garfield                 | Abandoned  |\n| 9   | [Security Advisories][psr9]          | Michael Hess                   | Abandoned  |\n| 10  | [Security Reporting Process][psr10]  | Michael Hess                   | Abandoned  |\n| 11  | [Container Interface][psr11]         | Matthieu Napoli, David Négrier | Accepted   |\n| 12  | [Extended Coding Style Guide][psr12] | Korvin Szanto                  | Accepted   |\n| 13  | [Hypermedia Links][psr13]            | Larry Garfield                 | Accepted   |\n| 14  | [Event Dispatcher][psr14]            | Larry Garfield                 | Accepted   |\n| 15  | [HTTP Handlers][psr15]               | Woody Gilk                     | Accepted   |\n| 16  | [Simple Cache][psr16]                | Paul Dragoonis                 | Accepted   |\n| 17  | [HTTP Factories][psr17]              | Woody Gilk                     | Accepted   |\n| 18  | [HTTP Client][psr18]                 | Tobias Nyholm                  | Accepted   |\n| 19  | [PHPDoc tags][psr19]                 | Chuck Burgess                  | Draft      |\n| 20  | [Clock][psr20]                       | Chris Seufert                  | Accepted   |\n| 21  | [Internationalization][psr21]        | Navarr Barnier                 | Draft      |\n| 22  | [Application Tracing][psr22]         | Adam Allport                   | Draft      |\n\n[workflow]: https://github.com/php-fig/fig-standards/blob/master/bylaws/002-psr-workflow.md\n[psr0]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md\n[psr1]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-1-basic-coding-standard.md\n[psr2]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md\n[psr3]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md\n[psr4]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader-meta.md\n[psr5]: https://github.com/php-fig/fig-standards/blob/master/proposed/phpdoc.md\n[psr6]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-6-cache.md\n[psr7]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-7-http-message.md\n[psr8]: https://github.com/php-fig/fig-standards/blob/master/proposed/psr-8-hug/\n[psr9]: https://github.com/php-fig/fig-standards/blob/master/proposed/security-disclosure-publication.md\n[psr10]: https://github.com/php-fig/fig-standards/blob/master/proposed/security-reporting-process.md\n[psr11]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-11-container.md\n[psr12]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-12-extended-coding-style-guide.md\n[psr13]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-13-links.md\n[psr14]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-14-event-dispatcher.md\n[psr15]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-15-request-handlers.md\n[psr16]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-16-simple-cache.md\n[psr17]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-17-http-factory.md\n[psr18]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-18-http-client.md\n[psr19]: https://github.com/php-fig/fig-standards/blob/master/proposed/phpdoc-tags.md\n[psr20]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-20-clock.md\n[psr21]: https://github.com/php-fig/fig-standards/blob/master/proposed/internationalization.md\n[psr22]: https://github.com/php-fig/fig-standards/blob/master/proposed/tracing.md\n"
  },
  {
    "path": "README.md",
    "content": "PHP Framework Interoperability Group\n====================================\n\nThe idea behind the group is for project representatives to talk about the\ncommonalities between our projects and find ways we can work together. Our main\naudience is each other, but we’re very aware that the rest of the PHP community\nis watching. If other folks want to adopt what we’re doing they are welcome to\ndo so, but that is not the aim.\n\nProposing a Standard Recommendation\n------------------------------------\n\nTo propose a PHP Standard Recommendation (PSR):\n\n- fork this repo, create a branch, checkout that branch, add the PSR in\n  `proposed/`, push the branch to GitHub, and send a pull request; or,\n\n- create a ticket to start a discussion on GitHub; or,\n\n- start a conversation on the [mailing list][].\n\n[mailing list]: http://groups.google.com/group/php-fig/\n\nGitHub usage\n------------\n\nAll discussion regarding a PSR happens on the [mailing list][]. Issues filed\nin GitHub are rarely monitored, and PRs are likely to be missed unless a message\nis sent to the mailing list regarding them.  Reviews of a proposed PSR should be\nconducted on the mailing list, not through PR comments for the same reason.\n\nPlease do not simply file an issue or PR and walk-away.  The most likely outcome\nis that it will never get seen or addressed.\n\nRequesting Membership\n---------------------\n\nYou **do not** need to be a voting member to participate in discussion on\nthe [mailing list][].\n\nTo become a voting member, you must send an email to the [mailing list][].\n\n- The subject line should read: `Membership Request: {$your_name} ({$project_name})`\n\n- The body should include your name, the name of (and link to) the project you\n  represent, and other details you feel are relevant.\n\n- Current members will vote on your request.\n\nDo not combine separate membership requests in a single thread; one request\nper thread, please.\n\nLanguage & Translations\n-----------------------\n\nAll PSRs are written in British English or American English (Different specifications\nmay vary, but it is consistent within the same specification). The PHP FIG does not\noffer official translations into other languages but other external entities are free\nto translate the specifications in accordance with the license.\n\nVoting Members\n--------------\n\nThe current list of voting members is available on the [project website][].\n\n[project website]: https://www.php-fig.org/\n"
  },
  {
    "path": "accepted/PSR-0-meta.md",
    "content": "# PSR-0 Meta Document\n\n## 1. Summary\n\nPSR-0 predates the official FIG structure and describes a standard for \nautoloader interoperability. It is superseded by PSR-4. This meta document\nwas added after the PSR has been deprecated. \n\n## 2. People\n\n### 2.1 Editor\n\n* Matthew Weier O'Phinney\n\n"
  },
  {
    "path": "accepted/PSR-0.md",
    "content": "Autoloading Standard\n====================\n\n> **Deprecated** - As of 2014-10-21 PSR-0 has been marked as deprecated. [PSR-4] is now recommended\nas an alternative.\n\n[PSR-4]: https://www.php-fig.org/psr/psr-4/\n\nThe following describes the mandatory requirements that must be adhered\nto for autoloader interoperability.\n\nMandatory\n---------\n\n* A fully-qualified namespace and class must have the following\n  structure `\\<Vendor Name>\\(<Namespace>\\)*<Class Name>`\n* Each namespace must have a top-level namespace (\"Vendor Name\").\n* Each namespace can have as many sub-namespaces as it wishes.\n* Each namespace separator is converted to a `DIRECTORY_SEPARATOR` when\n  loading from the file system.\n* Each `_` character in the CLASS NAME is converted to a\n  `DIRECTORY_SEPARATOR`. The `_` character has no special meaning in the\n  namespace.\n* The fully-qualified namespace and class are suffixed with `.php` when\n  loading from the file system.\n* Alphabetic characters in vendor names, namespaces, and class names may\n  be of any combination of lower case and upper case.\n\nExamples\n--------\n\n* `\\Doctrine\\Common\\IsolatedClassLoader` => `/path/to/project/lib/vendor/Doctrine/Common/IsolatedClassLoader.php`\n* `\\Symfony\\Core\\Request` => `/path/to/project/lib/vendor/Symfony/Core/Request.php`\n* `\\Zend\\Acl` => `/path/to/project/lib/vendor/Zend/Acl.php`\n* `\\Zend\\Mail\\Message` => `/path/to/project/lib/vendor/Zend/Mail/Message.php`\n\nUnderscores in Namespaces and Class Names\n-----------------------------------------\n\n* `\\namespace\\package\\Class_Name` => `/path/to/project/lib/vendor/namespace/package/Class/Name.php`\n* `\\namespace\\package_name\\Class_Name` => `/path/to/project/lib/vendor/namespace/package_name/Class/Name.php`\n\nThe standards we set here should be the lowest common denominator for\npainless autoloader interoperability. You can test that you are\nfollowing these standards by utilizing this sample SplClassLoader\nimplementation which is able to load PHP 5.3 classes.\n\nExample Implementation\n----------------------\n\nBelow is an example function to simply demonstrate how the above\nproposed standards are autoloaded.\n\n```php\n<?php\n\nfunction autoload($className)\n{\n    $className = ltrim($className, '\\\\');\n    $fileName  = '';\n    $namespace = '';\n    if ($lastNsPos = strrpos($className, '\\\\')) {\n        $namespace = substr($className, 0, $lastNsPos);\n        $className = substr($className, $lastNsPos + 1);\n        $fileName  = str_replace('\\\\', DIRECTORY_SEPARATOR, $namespace) . DIRECTORY_SEPARATOR;\n    }\n    $fileName .= str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';\n\n    require $fileName;\n}\nspl_autoload_register('autoload');\n```\n\nSplClassLoader Implementation\n-----------------------------\n\nThe following gist is a sample SplClassLoader implementation that can\nload your classes if you follow the autoloader interoperability\nstandards proposed above. It is the current recommended way to load PHP\n5.3 classes that follow these standards.\n\n* [http://gist.github.com/221634](http://gist.github.com/221634)\n\n"
  },
  {
    "path": "accepted/PSR-1-basic-coding-standard-meta.md",
    "content": "# PSR-1 Meta Document\n\n## 1. Summary\n\nThis section of the standard comprises what should be considered the standard\ncoding elements that are required to ensure a high level of technical\ninteroperability between shared PHP code. This meta document is added after the\ndocument was accepted. \n\n## 2. People\n\n### 2.1 Editor\n\n* Paul M. Jones\n\n"
  },
  {
    "path": "accepted/PSR-1-basic-coding-standard.md",
    "content": "# Basic Coding Standard\n\nThis section of the standard comprises what should be considered the standard\ncoding elements that are required to ensure a high level of technical\ninteroperability between shared PHP code.\n\nThe key words \"MUST\", \"MUST NOT\", \"REQUIRED\", \"SHALL\", \"SHALL NOT\", \"SHOULD\",\n\"SHOULD NOT\", \"RECOMMENDED\", \"MAY\", and \"OPTIONAL\" in this document are to be\ninterpreted as described in [RFC 2119].\n\n[RFC 2119]: http://www.ietf.org/rfc/rfc2119.txt\n[PSR-0]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md\n[PSR-4]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader.md\n\n## 1. Overview\n\n- Files MUST use only `<?php` and `<?=` tags.\n\n- Files MUST use only UTF-8 without BOM for PHP code.\n\n- Files SHOULD *either* declare symbols (classes, functions, constants, etc.)\n  *or* cause side-effects (e.g. generate output, change .ini settings, etc.)\n  but SHOULD NOT do both.\n\n- Namespaces and classes MUST follow an \"autoloading\" PSR: [[PSR-0], [PSR-4]].\n\n- Class names MUST be declared in `StudlyCaps`.\n\n- Class constants MUST be declared in all upper case with underscore separators.\n\n- Method names MUST be declared in `camelCase`.\n\n## 2. Files\n\n### 2.1. PHP Tags\n\nPHP code MUST use the long `<?php ?>` tags or the short-echo `<?= ?>` tags; it\nMUST NOT use the other tag variations.\n\n### 2.2. Character Encoding\n\nPHP code MUST use only UTF-8 without BOM.\n\n### 2.3. Side Effects\n\nA file SHOULD declare new symbols (classes, functions, constants,\netc.) and cause no other side effects, or it SHOULD execute logic with side\neffects, but SHOULD NOT do both.\n\nThe phrase \"side effects\" means execution of logic not directly related to\ndeclaring classes, functions, constants, etc., *merely from including the\nfile*.\n\n\"Side effects\" include but are not limited to: generating output, explicit\nuse of `require` or `include`, connecting to external services, modifying ini\nsettings, emitting errors or exceptions, modifying global or static variables,\nreading from or writing to a file, and so on.\n\nThe following is an example of a file with both declarations and side effects;\ni.e, an example of what to avoid:\n\n```php\n<?php\n// side effect: change ini settings\nini_set('error_reporting', E_ALL);\n\n// side effect: loads a file\ninclude \"file.php\";\n\n// side effect: generates output\necho \"<html>\\n\";\n\n// declaration\nfunction foo()\n{\n    // function body\n}\n```\n\nThe following example is of a file that contains declarations without side\neffects; i.e., an example of what to emulate:\n\n```php\n<?php\n// declaration\nfunction foo()\n{\n    // function body\n}\n\n// conditional declaration is *not* a side effect\nif (! function_exists('bar')) {\n    function bar()\n    {\n        // function body\n    }\n}\n```\n\n## 3. Namespace and Class Names\n\nNamespaces and classes MUST follow an \"autoloading\" PSR: [[PSR-0], [PSR-4]].\n\nThis means each class is in a file by itself, and is in a namespace of at\nleast one level: a top-level vendor name.\n\nClass names MUST be declared in `StudlyCaps`.\n\nCode written for PHP 5.3 and after MUST use formal namespaces.\n\nFor example:\n\n```php\n<?php\n// PHP 5.3 and later:\nnamespace Vendor\\Model;\n\nclass Foo\n{\n}\n```\n\nCode written for 5.2.x and before SHOULD use the pseudo-namespacing convention\nof `Vendor_` prefixes on class names.\n\n```php\n<?php\n// PHP 5.2.x and earlier:\nclass Vendor_Model_Foo\n{\n}\n```\n\n## 4. Class Constants, Properties, and Methods\n\nThe term \"class\" refers to all classes, interfaces, and traits.\n\n### 4.1. Constants\n\nClass constants MUST be declared in all upper case with underscore separators.\nFor example:\n\n```php\n<?php\nnamespace Vendor\\Model;\n\nclass Foo\n{\n    const VERSION = '1.0';\n    const DATE_APPROVED = '2012-06-01';\n}\n```\n\n### 4.2. Properties\n\nThis guide intentionally avoids any recommendation regarding the use of\n`$StudlyCaps`, `$camelCase`, or `$under_score` property names.\n\nWhatever naming convention is used SHOULD be applied consistently within a\nreasonable scope. That scope may be vendor-level, package-level, class-level,\nor method-level.\n\n### 4.3. Methods\n\nMethod names MUST be declared in `camelCase()`.\n"
  },
  {
    "path": "accepted/PSR-11-container-meta.md",
    "content": "# Container Meta Document\n\n## 1. Introduction\n\nThis document describes the process and discussions that led to the Container PSR.\nIts goal is to explain the reasons behind each decision.\n\n## 2. Why bother?\n\nThere are dozens of dependency injection containers out there, and these\nDI containers have very different ways to store entries.\n\n- Some are based on callbacks (Pimple, Laravel, ...)\n- Others are based on configuration (Symfony, ZF, ...), with various formats\n  (PHP arrays, YAML files, XML files...)\n- Some can leverage factories...\n- Some have a PHP API to build entries (PHP-DI, ZF, Symfony, Mouf...)\n- Some can do auto-wiring (Laravel, PHP-DI, ...)\n- Others can wire entries based on annotations (PHP-DI, JMS Bundle...)\n- Some have a graphical user interface (Mouf...)\n- Some can compile configuration files to PHP classes (Symfony, ZF...)\n- Some can do aliasing...\n- Some can use proxies to provide lazy loading of dependencies...\n\nSo when you look at the big picture, there is a very large number of ways in\nwhich the DI problem can be tackled, and therefore a big number of different\nimplementations. However, all the DI containers out there are answering the\nsame need: they offer a way for the application to retrieve a set of\nconfigured objects (usually services).\n\nBy standardizing the way entries are fetched from a container, frameworks and\nlibraries using the Container PSR could work with any compatible container.\nThat would allow end users to choose their own container based on their own preferences.\n\n## 3. Scope\n### 3.1. Goals\n\nThe goal set by the Container PSR is to standardize how frameworks and libraries make use of a\ncontainer to obtain objects and parameters.\n\nIt is important to distinguish the two usages of a container:\n\n- configuring entries\n- fetching entries\n\nMost of the time, those two sides are not used by the same party.\nWhile it is often end users who tend to configure entries, it is generally the framework that fetches\nentries to build the application.\n\nThis is why this interface focuses only on how entries can be fetched from a container.\n\n### 3.2. Non-goals\n\nHow entries are set in the container and how they are configured is out of the\nscope of this PSR. This is what makes a container implementation unique. Some\ncontainers have no configuration at all (they rely on autowiring), others rely\non PHP code defined via callback, others on configuration files... This standard\nonly focuses on how entries are fetched.\n\nAlso, naming conventions used for entries are not part of the scope of this\nPSR. Indeed, when you look at naming conventions, there are 2 strategies:\n\n- the identifier is the class name, or an interface name (used mostly\n  by frameworks with an autowiring capability)\n- the identifier is a common name (closer to a variable name), which is\n  mostly used by frameworks relying on configuration.\n\nBoth strategies have their strengths and weaknesses. The goal of this PSR\nis not to choose one convention over the other. Instead, the user can simply\nuse aliasing to bridge the gap between 2 containers with different naming strategies.\n\n## 4. Recommended usage: Container PSR and the Service Locator\n\nThe PSR states that:\n\n> \"users SHOULD NOT pass a container into an object, so the object\n> can retrieve *its own dependencies*. Users doing so are using the container as a Service Locator.\n> Service Locator usage is generally discouraged.\"\n\n```php\n// This is not OK, you are using the container as a service locator\nclass BadExample\n{\n    public function __construct(ContainerInterface $container)\n    {\n        $this->db = $container->get('db');\n    }\n}\n\n// Instead, please consider injecting directly the dependencies\nclass GoodExample\n{\n    public function __construct($db)\n    {\n        $this->db = $db;\n    }\n}\n// You can then use the container to inject the $db object into your $goodExample object.\n```\n\nIn the `BadExample` you should not inject the container because:\n\n- it makes the code **less interoperable**: by injecting the container, you have\n  to use a container compatible with the Container PSR. With the other\n  option, your code can work with ANY container.\n- you are forcing the developer into naming its entry \"db\". This naming could\n  conflict with another package that has the same expectations for another service.\n- it is harder to test.\n- it is not directly clear from your code that the `BadExample` class will need\n  the \"db\" service. Dependencies are hidden.\n\nVery often, the `ContainerInterface` will be used by other packages. As a end-user\nPHP developer using a framework, it is unlikely you will ever need to use containers\nor type-hint on the `ContainerInterface` directly.\n\nWhether using the Container PSR into your code is considered a good practice or not boils down to\nknowing if the objects you are retrieving are **dependencies** of the object referencing\nthe container or not. Here are a few more examples:\n\n```php\nclass RouterExample\n{\n    // ...\n\n    public function __construct(ContainerInterface $container)\n    {\n        $this->container = $container;\n    }\n\n    public function getRoute($request)\n    {\n        $controllerName = $this->getContainerEntry($request->getUrl());\n        // This is OK, the router is finding the matching controller entry, the controller is\n        // not a dependency of the router\n        $controller = $this->container->get($controllerName);\n        // ...\n    }\n}\n```\n\nIn this example, the router is transforming the URL into a controller entry name,\nthen fetches the controller from the container. A controller is not really a\ndependency of the router. As a rule of thumb, if your object is *computing*\nthe entry name among a list of entries that can vary, your use case is certainly legitimate.\n\nAs an exception, factory objects whose only purpose is to create and return new instances may use\nthe service locator pattern. The factory must then implement an interface so that it can itself\nbe replaced by another factory using the same interface.\n\n```php\n// ok: a factory interface + implementation to create an object\ninterface FactoryInterface\n{\n    public function newInstance();\n}\n\nclass ExampleFactory implements FactoryInterface\n{\n    protected $container;\n\n    public function __construct(ContainerInterface $container)\n    {\n        $this->container = $container;\n    }\n\n    public function newInstance()\n    {\n        return new Example($this->container->get('db'));\n    }\n}\n```\n\n## 5. History\n\nBefore submitting the Container PSR to the PHP-FIG, the `ContainerInterface` was\nfirst proposed in a project named [container-interop](https://github.com/container-interop/container-interop/).\nThe goal of the project was to provide a test-bed for implementing the `ContainerInterface`,\nand to pave the way for the Container PSR.\n\nIn the rest of this meta document, you will see frequent references to\n`container-interop.`\n\n## 6. Interface name\n\nThe interface name is the same as the one discussed for `container-interop`\n(only the namespace is changed to match the other PSRs).\nIt has been thoroughly discussed on `container-interop` [[4]](#link_naming_discussion) and was decided by a vote [[5]](#link_naming_vote).\n\nThe list of options considered with their respective votes are:\n\n- `ContainerInterface`: +8\n- `ProviderInterface`: +2\n- `LocatorInterface`: 0\n- `ReadableContainerInterface`: -5\n- `ServiceLocatorInterface`: -6\n- `ObjectFactory`: -6\n- `ObjectStore`: -8\n- `ConsumerInterface`: -9\n\n## 7. Interface methods\n\nThe choice of which methods the interface would contain was made after a statistical analysis of existing containers. [[6]](#link_statistical_analysis).\n\nThe summary of the analysis showed that:\n\n- all containers offer a method to get an entry by its id\n- a large majority name such method `get()`\n- for all containers, the `get()` method has 1 mandatory parameter of type string\n- some containers have an optional additional argument for `get()`, but it doesn't have the same purpose between containers\n- a large majority of the containers offer a method to test if it can return an entry by its id\n- a majority name such method `has()`\n- for all containers offering `has()`, the method has exactly 1 parameter of type string\n- a large majority of the containers throw an exception rather than returning null when an entry is not found in `get()`\n- a large majority of the containers don't implement `ArrayAccess`\n\nThe question of whether to include methods to define entries has been discussed at the very start of the container-interop project [[4]](#link_naming_discussion).\nIt has been judged that such methods do not belong in the interface described here because it is out of its scope\n(see the \"Goal\" section).\n\nAs a result, the `ContainerInterface` contains two methods:\n\n- `get()`, returning anything, with one mandatory string parameter. Should throw an exception if the entry is not found.\n- `has()`, returning a boolean, with one mandatory string parameter.\n\n### 7.1. Number of parameters in `get()` method\n\nWhile `ContainerInterface` only defines one mandatory parameter in `get()`, it is not incompatible with\nexisting containers that have additional optional parameters. PHP allows an implementation to offer more parameters\nas long as they are optional, because the implementation *does* satisfy the interface.\n\nDifference with container-interop: [The container-interop spec](https://github.com/container-interop/container-interop/blob/master/docs/ContainerInterface.md) stated that:\n\n> While `ContainerInterface` only defines one mandatory parameter in `get()`, implementations MAY accept additional optional parameters.\n\nThis sentence was removed from PSR-11 because:\n\n- It is something that stems from OO principles in PHP, so this is not directly related to PSR-11\n- We do not want to encourage implementors to add additional parameters as we recommend coding against the interface and not the implementation\n\nHowever, some implementations have extra optional parameters; that's technically legal. Such implementations are compatible with PSR-11. [[11]](#link_get_optional_parameters)\n\n### 7.2. Type of the `$id` parameter\n\nThe type of the `$id` parameter in `get()` and `has()` has been discussed in the container-interop project.\n\nWhile `string` is used in all the containers that were analyzed, it was suggested that allowing\nanything (such as objects) could allow containers to offer a more advanced query API.\n\nAn example given was to use the container as an object builder. The `$id` parameter would then be an\nobject that would describe how to create an instance.\n\nThe conclusion of the discussion [[7]](#link_method_and_parameters_details) was that this was beyond the scope of getting entries from a container without\nknowing how the container provided them, and it was more fit for a factory.\n\n### 7.3. Exceptions thrown\n\nThis PSR provides 2 interfaces meant to be implemented by container exceptions.\n\n#### 7.3.1 Base exception\n\nThe `Psr\\Container\\ContainerExceptionInterface` is the base interface. It SHOULD be implemented by custom exceptions thrown directly by the container.\n\nIt is expected that any exception that is part of the domain of the container implements the `ContainerExceptionInterface`. A few examples:\n\n- if a container relies on a configuration file and if that configuration file is flawed, the container might throw an `InvalidFileException` implementing the `ContainerExceptionInterface`.\n- if a cyclic dependency is detected between dependencies, the container might throw an `CyclicDependencyException` implementing the `ContainerExceptionInterface`.\n\nHowever, if the exception is thrown by some code out of the container's scope (for instance an exception thrown while instantiating an entry), the container is not required to wrap this exception in a custom exception implementing the `ContainerExceptionInterface`.\n\nThe usefulness of the base exception interface was questioned: it is not an exception one would typically catch [[8]](#link_base_exception_usefulness).\n\nHowever, most PHP-FIG members considered it to be a best practice. Base exception interface are implemented in previous PSRs and several member projects. The base exception interface was therefore kept.\n\n#### 7.3.2 Not found exception\n\nA call to the `get` method with a non-existing id must throw an exception implementing the `Psr\\Container\\NotFoundExceptionInterface`.\n\nFor a given identifier:\n\n- if the `has` method returns `false`, then the `get` method MUST throw a `Psr\\Container\\NotFoundExceptionInterface`.\n- if the `has` method returns `true`, this does not mean that the `get` method will succeed and throw no exception. It can even throw a `Psr\\Container\\NotFoundExceptionInterface` if one of the dependencies of the requested entry is missing.\n\nTherefore, when a user catches the `Psr\\Container\\NotFoundExceptionInterface`, it has 2 possible meanings [[9]](#link_not_found_behaviour):\n\n- the requested entry does not exist (bad request)\n- or a dependency of the requested entry does not exist (i.e. the container is misconfigured)\n\nThe user can however easily make a distinction with a call to `has`.\n\nIn pseudo-code:\n\n```php\nif (!$container->has($id)) {\n    // The requested instance does not exist\n    return;\n}\ntry {\n    $entry = $container->get($id);\n} catch (NotFoundExceptionInterface $e) {\n    // Since the requested entry DOES exist, a NotFoundExceptionInterface means that the container is misconfigured and a dependency is missing.\n}\n```\n\n## 8. Implementations\n\nAt the time of writing, the following projects already implement and/or consume the `container-interop` version of the interface.\n\n### Implementors\n- [Acclimate](https://github.com/jeremeamia/acclimate-container)\n- [Aura.DI](https://github.com/auraphp/Aura.Di)\n- [dcp-di](https://github.com/estelsmith/dcp-di)\n- [League Container](https://github.com/thephpleague/container)\n- [Mouf](http://mouf-php.com)\n- [Njasm Container](https://github.com/njasm/container)\n- [PHP-DI](http://php-di.org)\n- [PimpleInterop](https://github.com/moufmouf/pimple-interop)\n- [XStatic](https://github.com/jeremeamia/xstatic)\n- [Zend ServiceManager](https://github.com/zendframework/zend-servicemanager)\n\n### Middleware\n- [Alias-Container](https://github.com/thecodingmachine/alias-container)\n- [Prefixer-Container](https://github.com/thecodingmachine/prefixer-container)\n\n### Consumers\n- [Behat](https://github.com/Behat/Behat)\n- [interop.silex.di](https://github.com/thecodingmachine/interop.silex.di)\n- [mindplay/middleman](https://github.com/mindplay-dk/middleman)\n- [PHP-DI Invoker](https://github.com/PHP-DI/Invoker)\n- [Prophiler](https://github.com/fabfuel/prophiler)\n- [Silly](https://github.com/mnapoli/silly)\n- [Slim](https://github.com/slimphp/Slim)\n- [Splash](http://mouf-php.com/packages/mouf/mvc.splash-common/version/8.0-dev/README.md)\n- [Zend Expressive](https://github.com/zendframework/zend-expressive)\n\nThis list is not comprehensive and should be only taken as an example showing that there is considerable interest in the PSR.\n\n## 9. People\n\n### 9.1 Editors\n\n* [Matthieu Napoli](https://github.com/mnapoli)\n* [David Négrier](https://github.com/moufmouf)\n\n### 9.2 Sponsors\n\n* [Matthew Weier O'Phinney](https://github.com/weierophinney) (Coordinator)\n* [Korvin Szanto](https://github.com/KorvinSzanto)\n\n### 9.3 Contributors\n\nAre listed here all people that contributed in the discussions or votes (on container-interop and during migration to PSR-11), by alphabetical order:\n\n* [Alexandru Pătrănescu](https://github.com/drealecs)\n* [Amy Stephen](https://github.com/AmyStephen)\n* [Ben Peachey](https://github.com/potherca)\n* [David Négrier](https://github.com/moufmouf)\n* [Don Gilbert](https://github.com/dongilbert)\n* [Jason Judge](https://github.com/judgej)\n* [Jeremy Lindblom](https://github.com/jeremeamia)\n* [Larry Garfield](https://github.com/crell)\n* [Marco Pivetta](https://github.com/Ocramius)\n* [Matthieu Napoli](https://github.com/mnapoli)\n* [Nelson J Morais](https://github.com/njasm)\n* [Paul M. Jones](https://github.com/pmjones)\n* [Phil Sturgeon](https://github.com/philsturgeon)\n* [Stephan Hochdörfer](https://github.com/shochdoerfer)\n* [Taylor Otwell](https://github.com/taylorotwell)\n\n## 10. Relevant links\n\n1. [Discussion about the container PSR and the service locator](https://groups.google.com/forum/#!topic/php-fig/pyTXRvLGpsw)\n1. [Container-interop's `ContainerInterface.php`](https://github.com/container-interop/container-interop/blob/master/src/Interop/Container/ContainerInterface.php)\n1. [List of all issues](https://github.com/container-interop/container-interop/issues?labels=ContainerInterface&milestone=&page=1&state=closed)\n1. <a name=\"link_naming_discussion\"></a>[Discussion about the interface name and container-interop scope](https://github.com/container-interop/container-interop/issues/1)\n1. <a name=\"link_naming_vote\"></a>[Vote for the interface name](https://github.com/container-interop/container-interop/wiki/%231-interface-name:-Vote)\n1. <a name=\"link_statistical_analysis\"></a>[Statistical analysis of existing containers method names](https://gist.github.com/mnapoli/6159681)\n1. <a name=\"link_method_and_parameters_details\"></a>[Discussion about the method names and parameters](https://github.com/container-interop/container-interop/issues/6)\n1. <a name=\"link_base_exception_usefulness\"></a>[Discussion about the usefulness of the base exception](https://groups.google.com/forum/#!topic/php-fig/_vdn5nLuPBI)\n1. <a name=\"link_not_found_behaviour\"></a>[Discussion about the `NotFoundExceptionInterface`](https://groups.google.com/forum/#!topic/php-fig/I1a2Xzv9wN8)\n1. <a name=\"link_get_optional_parameters\"></a>Discussion about get optional parameters [in container-interop](https://github.com/container-interop/container-interop/issues/6) and on the [PHP-FIG mailing list](https://groups.google.com/forum/#!topic/php-fig/zY6FAG4-oz8)\n\n## 11. Errata\n\n## Type additions\n\nThe 1.1 release of the `psr/container` package includes scalar parameter types. The\n2.0 release of the package includes return types. This structure leverages PHP\n7.2 covariance support to allow for a gradual upgrade process.\n\nImplementers MAY add return types to their own packages at their discretion,\nprovided that:\n\n- the return types match those in the 2.0 package.\n- the implementation specifies a minimum PHP version of 7.2.0 or later.\n\nImplementers MAY add parameter types to their own packages in a new major\nrelease, either at the same time as adding return types or in a subsequent\nrelease, provided that:\n\n- the parameter types match those in the 1.1 package.\n- the implementation specifies a minimum PHP version of 7.2.0.\n- the implementation depends on `\"psr/container\": \"^1.1 || ^2.0\"` so as to exclude\n  the untyped 1.0 version.\n\nImplementers are encouraged but not required to transition their packages toward\nthe 2.0 version of the package at their earliest convenience.\n"
  },
  {
    "path": "accepted/PSR-11-container.md",
    "content": "# Container interface\n\nThis document describes a common interface for dependency injection containers.\n\nThe goal set by `ContainerInterface` is to standardize how frameworks and libraries make use of a\ncontainer to obtain objects and parameters (called *entries* in the rest of this document).\n\nThe key words \"MUST\", \"MUST NOT\", \"REQUIRED\", \"SHALL\", \"SHALL NOT\", \"SHOULD\",\n\"SHOULD NOT\", \"RECOMMENDED\", \"MAY\", and \"OPTIONAL\" in this document are to be\ninterpreted as described in [RFC 2119][].\n\nThe word `implementor` in this document is to be interpreted as someone\nimplementing the `ContainerInterface` in a dependency injection-related library or framework.\nUsers of dependency injection containers (DIC) are referred to as `user`.\n\n[RFC 2119]: http://tools.ietf.org/html/rfc2119\n\n## 1. Specification\n\n### 1.1 Basics\n\n#### 1.1.1 Entry identifiers\n\nAn entry identifier is any PHP-legal string of at least one character that uniquely identifies an item within a container.  An entry identifier is an opaque string, so callers SHOULD NOT assume that the structure of the string carries any semantic meaning.\n\n#### 1.1.2 Reading from a container\n\n- The `Psr\\Container\\ContainerInterface` exposes two methods: `get` and `has`.\n\n- `get` takes one mandatory parameter: an entry identifier, which MUST be a string.\n  `get` can return anything (a *mixed* value), or throw a `NotFoundExceptionInterface` if the identifier\n  is not known to the container. Two successive calls to `get` with the same\n  identifier SHOULD return the same value. However, depending on the `implementor`\n  design and/or `user` configuration, different values might be returned, so\n  `user` SHOULD NOT rely on getting the same value on 2 successive calls.\n\n- `has` takes one unique parameter: an entry identifier, which MUST be a string.\n  `has` MUST return `true` if an entry identifier is known to the container and `false` if it is not.\n  If `has($id)` returns false, `get($id)` MUST throw a `NotFoundExceptionInterface`.\n\n### 1.2 Exceptions\n\nExceptions directly thrown by the container SHOULD implement the\n[`Psr\\Container\\ContainerExceptionInterface`](#container-exception).\n\nA call to the `get` method with a non-existing id MUST throw a\n[`Psr\\Container\\NotFoundExceptionInterface`](#not-found-exception).\n\n### 1.3 Recommended usage\n\nUsers SHOULD NOT pass a container into an object so that the object can retrieve *its own dependencies*.\nThis means the container is used as a [Service Locator](https://en.wikipedia.org/wiki/Service_locator_pattern)\nwhich is a pattern that is generally discouraged.\n\nPlease refer to section 4 of the META document for more details.\n\n## 2. Package\n\nThe interfaces and classes described as well as relevant exceptions are provided as part of the\n[psr/container](https://packagist.org/packages/psr/container) package.\n\nPackages providing a PSR container implementation should declare that they provide `psr/container-implementation` `1.0.0`.\n\nProjects requiring an implementation should require `psr/container-implementation` `1.0.0`.\n\n## 3. Interfaces\n\n<a name=\"container-interface\"></a>\n### 3.1. `Psr\\Container\\ContainerInterface`\n\n```php\n<?php\nnamespace Psr\\Container;\n\n/**\n * Describes the interface of a container that exposes methods to read its entries.\n */\ninterface ContainerInterface\n{\n    /**\n     * Finds an entry of the container by its identifier and returns it.\n     *\n     * @param string $id Identifier of the entry to look for.\n     *\n     * @throws NotFoundExceptionInterface  No entry was found for **this** identifier.\n     * @throws ContainerExceptionInterface Error while retrieving the entry.\n     *\n     * @return mixed Entry.\n     */\n    public function get($id);\n\n    /**\n     * Returns true if the container can return an entry for the given identifier.\n     * Returns false otherwise.\n     *\n     * `has($id)` returning true does not mean that `get($id)` will not throw an exception.\n     * It does however mean that `get($id)` will not throw a `NotFoundExceptionInterface`.\n     *\n     * @param string $id Identifier of the entry to look for.\n     *\n     * @return bool\n     */\n    public function has($id);\n}\n```\n\n\nSince [psr/container version 1.1](https://packagist.org/packages/psr/container#1.1.0),\nthe above interface has been updated to add argument type hints.\n\nSince [psr/container version 2.0](https://packagist.org/packages/psr/container#2.0.0),\nthe above interface has been updated to add return type hints (but only to the\n`has()` method).\n\n<a name=\"container-exception\"></a>\n### 3.2. `Psr\\Container\\ContainerExceptionInterface`\n\n```php\n<?php\nnamespace Psr\\Container;\n\n/**\n * Base interface representing a generic exception in a container.\n */\ninterface ContainerExceptionInterface\n{\n}\n```\n\n<a name=\"not-found-exception\"></a>\n### 3.3. `Psr\\Container\\NotFoundExceptionInterface`\n\n```php\n<?php\nnamespace Psr\\Container;\n\n/**\n * No entry was found in the container.\n */\ninterface NotFoundExceptionInterface extends ContainerExceptionInterface\n{\n}\n```\n"
  },
  {
    "path": "accepted/PSR-12-extended-coding-style-guide-meta.md",
    "content": "Extended Coding Style Guide Meta Document\n=========================================\n\n# 1. Summary\n\nThis document describes the process and discussions that led to the Extended Coding\nStyle PSR. Its goal is to explain the reasons behind each decision.\n\n# 2. Why Bother?\n\nPSR-2 was accepted in 2012 and since then a number of changes have been made to PHP,\nmost notably recent changes for PHP 7, which have implications for coding style\nguidelines. Whilst PSR-2 is very comprehensive of PHP functionality that existed at\nthe time of writing, new functionality is very open to interpretation. PSR-12 seeks\nto provide a set way that both coding style tools can implement, projects can declare\nadherence to and developers can easily relate on between different projects for these\ncoding style reducing cognitive friction.\n\nPSR-2 was created based upon the common practices of the PHP-FIG projects at the time\nbut ultimately this meant it was a compromise of many of the different projects' guidelines.\nThe repercussions of projects changing their coding guidelines to align with PSR-2 (Almost\nall projects do align with PSR-1, even if it is not explicitly stated) were seen to be too\ngreat (losing git history, huge changesets and breaking existing patches/pull requests).\n\nPSR-2 required adopters to reformat large amounts of existing code which stifled adoption.\nTo help alleviate this issue with PSR-12, we have taken a more prescriptive approach and\ndefined the standards for new language features as they are released.\n\nHowever it is for a lack of wanting to be dictatorial that we will aim to apply PSR-2\nstyling, rationale and stances (Described in Section 4, Approaches) in PSR-12 instead of\nestablishing new conventions.\n\n# 3. Scope\n\n## 3.1. Goals\n\nThis PSR shares the same goals as PSR-2.\n\n> The intent of this guide is to reduce cognitive friction when scanning code from\n> different authors. It does so by enumerating a shared set of rules and expectations\n> about how to format PHP code.\n> When various authors collaborate across multiple projects, it helps to have one set\n> of guidelines to be used among all those projects. Thus, the benefit of this guide is\n> not in the rules themselves, but in the sharing of those rules.\n\nThis PSR is an extension of PSR-2, and therefore also an extension of PSR-1. The basis of\nPSR-12 is PSR-2 and therefore a list of differences is provided below to assist with migration\nbut it should be considered as an independent specification.\n\nThis PSR will include coding style guidelines related to new functionality added to PHP\nafter the publication of PSR-2; this includes PHP 5.5, PHP 5.6 and PHP 7.0. This PSR will\nalso include clarifications on the text of PSR-2, as described in the PSR-2 Errata.\n\n## 3.2. Non-Goals\n\nIt is not the intention of this PSR to add entirely new coding style guidelines. PSR-12 will\nalso not change anything stipulated in PSR-1 and PSR-2.\n\n# 4. Approaches\n\nThe overarching approach is to attempt to apply existing PSR-2 styling and rationale to\nnew functionality as opposed to establishing new conventions.\n\n## 4.1. Strict Types Declarations\n\nThere was a discussion about whether or not strict types should be enforced in the standard\nhttps://github.com/cs-extended/fig-standards/issues/7. All were in agreement we should only\nuse a MUST or MUST NOT statement and avoid the use of a SHOULD statement and nobody wanted\nto say that strict types could not be declared. The discussion was whether it should be\nconsidered a coding style item which should be covered or whether it was out of scope and it\nwas decided to be out of scope of a coding style guide.\n\n## 4.2. Finally and Return Types Declaration Spacing\n\nNumerous different options were suggested and they can be seen\n[here for return type declarations](https://gist.github.com/michaelcullum/c025f3870c9ea1dd2668#file-returntypesspacing-php) or\n[here for finally blocks](https://gist.github.com/michaelcullum/c025f3870c9ea1dd2668#file-finallyblocks-php)\nand the current implementation was chosen due to consistency with other parts of the PSR-12\nspecification that came from PSR-2.\n\n## 4.3. Enforcing short form for all type keywords\n\nPHP 7.0 introduced [scalar types declaration](http://php.net/manual/en/functions.arguments.php#functions.arguments.type-declaration)\nwhich does not support long type aliases. Therefore it makes sense to enforce primary short type forms to be used to\nhave uniform syntax and prevent possible confusion.\n\n## 4.4. Public Survey\n\nIn order to settle things using data, survey was conducted and responses from 142 people\nincluding 17 project representatives were gathered:\n\n### 4.4.1. PHP-FIG Representative Results\n\n| Representative          | Project           | Compound namespaces with a depth of two or more MUST not be used | Header statement grouping and ordering | Declare statements must each be on their own line | Declare statements in PHP files containing markup | Declare statements have no spaces: `declare(strict_types=1);` | Block declare statement formatting | `new` keyword usage, parenthesis required |Return type declaration formatting |Use statement leading slashes disallowed | Block namespace declaration formatting | General operator spacing |Try, Catch, Finally formatting | Anonymous class declaration formatting | Keyword casing, only lower case | Type keywords, short form only |\n| --------------          | -------           | ---------------------------------------------------- | ---------------------------------- | ----------------------------------------- | ------------------------------------------- | -------------------------------------------------------- | ------------------------------- | ------------------------------------- |------------------------------- |------------------------------------ | ----------------------------------- | ---------------------- |--------------------------- | ----------------------------------- | --------------------------- | -------------------------- |\n| Alexander Makarov       |  Yii framework    | ✓ | ✓ | ✓ | ❌ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |\n| Korvin Szanto           | concrete5         | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |\n| Leo Feyer               | Contao            | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |\n| Larry Garfield          | Drupal            | ✓ | ✓ | ✓ | ✓ | ✓ | ❌ | ✓ | ✓ | ✓ | ❌ | ✓ | ✓ | ❌ | ✓ | ✓ |\n| André R.                | eZ                | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |\n| Jan Schneider           | Horde             | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |\n| Karsten Dambekalns      | Neos and Flow     | ✓ | ✓ | ✓ | ✓ | ❌ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |\n| Andres Gutierrez        | Phalcon           | ❌ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |\n| Ryan Thompson           | PyroCMS           | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ❌ | ❌ | ✓ | ✓ | ✓ | ✓ | ✓ |\n| Matteo Beccati          | Revive Adserver   | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ❌ | ✓ | ✓ | ✓ | ✓ |\n| Damian Mooyman          | SilverStripe      | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |\n| Brian Retterer          | Stormpath PHP SDK | ✓ | ✓ | ✓ | ❌ | ❌ | ✓ | ❌ | ✓ | ❌ | ✓ | ✓ | ✓ | ✓ | ❌ | ❌ |\n| Matthew Weier O'Phinney | Zend Framework    | ❌ | ✓ | ✓ | ❌ | ✓ | ✓ | ✓ | ❌ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |\n| Jordi Boggiano          | Composer          | ❌ | ❌ | ❌ | ✓ | ✓ | ✓ | ❌ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |\n| Ben Marks               | Magento           | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |\n| Chuck Burgess           | PEAR              | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |\n|                         | **Totals**:       |13/3|15/1|15/1|13/3|14/2|15/1|14/2|15/1|14/2|14/2|15/1|16/0|15/1|15/1|15/1|\n\n### 4.4.2. General non-representative voters\n\n| Question | For | Against | Percentage For |\n| -------- | --- | ------- | -------------- |\n| Compound namespaces required depth | 114 | 12 | 89.47% |\n| Header statement grouping and ordering | 113 | 13 | 88.5% |\n| Declare statements must each be on their own line | 120 | 6 | 95% |\n| Declare statements in PHP files containing markup | 119 | 7 | 94.12% |\n| Declare statements have no spaces | 116 | 10 | 91.38% |\n| Block declare statement formatting | 118 | 8 | 93.22% |\n| `new` keyword usage, parenthesis required | 116 | 10 | 91.38% |\n| Return type declaration formatting | 115 | 11 | 90.43% |\n| Use statement leading slashes disallowed | 118 | 8 | 93.22% |\n| Block namespace declaration formatting | 120 | 6 | 95% |\n| General operator spacing | 123 | 3 | 97.56% |\n| Try, Catch, Finally formatting | 124 | 2 | 98.39% |\n| Anonymous class declaration formatting | 117 | 9 | 92.31% |\n| Keyword casing, only lower case | 124 | 2 | 98.39% |\n| Type keywords, short form only | 121 | 5 | 95.87% |\n\n## 4.5. Multiline Function Arguments Mixed With Multiline Return\n\nA potential readability issue [was raised on the mailing list](https://groups.google.com/d/msg/php-fig/ULSL4gqK8GY/cgDELuPOCQAJ).\nWe reviewed options for changes to the specification that could provide better readability and\nthe floated option was to require a blank line after the opening bracket of a function if the\narguments and the return are both multiline. Instead it was pointed out that this specification\n_already_ allows you to decide where you'd like to add blank lines and so we will leave it to\nthe implementors to decide.\n\n# 5. Changelog from PSR-2\n\nPlease note this changelog is not a verbose list of changes from PSR-2 but highlights the most\nnotable changes. It should be considered a new specification and therefore you should read the\nspecification for a full understanding of its contents.\n\n## 5.1. New Statements\n\n* Lowercase for all keywords - Section 2.5\n* Short form for all type keywords - Section 2.5\n* Use statement grouping - Section 3\n* Use statement blocks - Section 3\n* Declare statement/Strict types declaration usage - Section 3\n* Parentheses are always required for class instantiation - Section 4\n* Typed properties - Section 4.3\n* Return type declarations - Section 4.5\n* Variadic and reference argument operators - Section 4.5\n* Type hints - Section 4.5\n* Add finally block - Section 5.6\n* Operators - Section 6\n* Unary operators - Section 6.1\n* Binary operators - Section 6.2\n* Ternary operators - Section 6.3\n* Anonymous classes - Section 8\n\n## 5.2. Clarifications and Errata\n\n* Adjust 'methods' to 'methods and functions' in a number of instances - Throughout\n* Adjust references to classes and interfaces to also include traits - Throughout\n* StudlyCaps meaning clarified as PascalCase - Section 2.1\n* The last line should not be blank but contain an EOL character - Section 2.2\n* Blank lines may be added for readability except where explicitly forbidden within the PSR - Section 2.3\n* PSR-2 errata statement about multi-line arguments - Section 4\n* PSR-2 errata statement about extending multiple interfaces - Section 4\n* Forbid blank lines before/after closing/opening braces for classes - Section 4\n\n# 6. People\n\n## 6.1.  Editor:\n* Korvin Szanto\n\n## 6.2. Sponsor:\n\n* Chris Tankersley\n\n## 6.3. Working Group Members:\n\n* Alessandro Lai\n* Alexander Makarov\n* Michael Cullum\n* Robert Deutz\n\n## 6.4. Special Thanks\n\n* Michael Cullum for drafting the original specification\n* Alexandar Makarov for coordinating the draft during PHP-FIG 2.0\n* Cees-Jan Kiewiet for moral support\n\n# 7. Votes\n\n* **Entrance Vote:** https://groups.google.com/forum/?utm_medium=email&utm_source=footer#!msg/php-fig/P9atZLOcUBM/_jwkvlYKEAAJ\n* **Approval Vote:** https://groups.google.com/forum/#!topic/php-fig/1uaeSMaDGbk\n\n# 8. Relevant Links\n\n_**Note:** Order descending chronologically._\n\n* [Inspiration Mailing List Thread](https://groups.google.com/forum/?utm_medium=email&utm_source=footer#!topic/php-fig/wh9avopSR9k)\n* [Initial Mailing List PSR Proposal Thread](https://groups.google.com/forum/?utm_medium=email&utm_source=footer#!topic/php-fig/MkFacLdfGso)\n"
  },
  {
    "path": "accepted/PSR-12-extended-coding-style-guide.md",
    "content": "# Extended Coding Style Guide\n\nThe key words \"MUST\", \"MUST NOT\", \"REQUIRED\", \"SHALL\", \"SHALL NOT\", \"SHOULD\",\n\"SHOULD NOT\", \"RECOMMENDED\", \"MAY\", and \"OPTIONAL\" in this document are to be\ninterpreted as described in [RFC 2119][].\n\n[RFC 2119]: http://tools.ietf.org/html/rfc2119\n\n## Overview\n\nThis specification extends, expands and replaces [PSR-2][], the coding style guide and\nrequires adherence to [PSR-1][], the basic coding standard.\n\nLike [PSR-2][], the intent of this specification is to reduce cognitive friction when\nscanning code from different authors. It does so by enumerating a shared set of rules\nand expectations about how to format PHP code. This PSR seeks to provide a set way that\ncoding style tools can implement, projects can declare adherence to and developers\ncan easily relate to between different projects. When various authors collaborate\nacross multiple projects, it helps to have one set of guidelines to be used among\nall those projects. Thus, the benefit of this guide is not in the rules themselves\nbut the sharing of those rules.\n\n[PSR-2][] was accepted in 2012 and since then a number of changes have been made to PHP\nwhich has implications for coding style guidelines. Whilst [PSR-2] is very comprehensive\nof PHP functionality that existed at the time of writing, new functionality is very\nopen to interpretation. This PSR, therefore, seeks to clarify the content of PSR-2 in\na more modern context with new functionality available, and make the errata to PSR-2\nbinding.\n\n### Previous language versions\n\nThroughout this document, any instructions MAY be ignored if they do not exist in versions\nof PHP supported by your project.\n\n### Example\n\nThis example encompasses some of the rules below as a quick overview:\n\n```php\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Vendor\\Package;\n\nuse Vendor\\Package\\{ClassA as A, ClassB, ClassC as C};\nuse Vendor\\Package\\SomeNamespace\\ClassD as D;\n\nuse function Vendor\\Package\\{functionA, functionB, functionC};\n\nuse const Vendor\\Package\\{ConstantA, ConstantB, ConstantC};\n\nclass Foo extends Bar implements FooInterface\n{\n    public function sampleFunction(int $a, int $b = null): array\n    {\n        if ($a === $b) {\n            bar();\n        } elseif ($a > $b) {\n            $foo->bar($arg1);\n        } else {\n            BazClass::bar($arg2, $arg3);\n        }\n    }\n\n    final public static function bar()\n    {\n        // method body\n    }\n}\n```\n\n## 2. General\n\n### 2.1 Basic Coding Standard\n\nCode MUST follow all rules outlined in [PSR-1].\n\nThe term 'StudlyCaps' in PSR-1 MUST be interpreted as PascalCase where the first letter of\neach word is capitalized including the very first letter.\n\n### 2.2 Files\n\nAll PHP files MUST use the Unix LF (linefeed) line ending only.\n\nAll PHP files MUST end with a non-blank line, terminated with a single LF.\n\nThe closing `?>` tag MUST be omitted from files containing only PHP.\n\n### 2.3 Lines\n\nThere MUST NOT be a hard limit on line length.\n\nThe soft limit on line length MUST be 120 characters.\n\nLines SHOULD NOT be longer than 80 characters; lines longer than that SHOULD\nbe split into multiple subsequent lines of no more than 80 characters each.\n\nThere MUST NOT be trailing whitespace at the end of lines.\n\nBlank lines MAY be added to improve readability and to indicate related\nblocks of code except where explicitly forbidden.\n\nThere MUST NOT be more than one statement per line.\n\n### 2.4 Indenting\n\nCode MUST use an indent of 4 spaces for each indent level, and MUST NOT use\ntabs for indenting.\n\n### 2.5 Keywords and Types\n\nAll PHP reserved keywords and types [[1]][keywords][[2]][types] MUST be in lower case.\n\nAny new types and keywords added to future PHP versions MUST be in lower case.\n\nShort form of type keywords MUST be used i.e. `bool` instead of `boolean`,\n`int` instead of `integer` etc.\n\n## 3. Declare Statements, Namespace, and Import Statements\n\nThe header of a PHP file may consist of a number of different blocks. If present,\neach of the blocks below MUST be separated by a single blank line, and MUST NOT contain\na blank line. Each block MUST be in the order listed below, although blocks that are\nnot relevant may be omitted.\n\n* Opening `<?php` tag.\n* File-level docblock.\n* One or more declare statements.\n* The namespace declaration of the file.\n* One or more class-based `use` import statements.\n* One or more function-based `use` import statements.\n* One or more constant-based `use` import statements.\n* The remainder of the code in the file.\n\nWhen a file contains a mix of HTML and PHP, any of the above sections may still\nbe used. If so, they MUST be present at the top of the file, even if the\nremainder of the code consists of a closing PHP tag and then a mixture of HTML and\nPHP.\n\nWhen the opening `<?php` tag is on the first line of the file, it MUST be on its\nown line with no other statements unless it is a file containing markup outside of PHP\nopening and closing tags.\n\nImport statements MUST never begin with a leading backslash as they\nmust always be fully qualified.\n\nThe following example illustrates a complete list of all blocks:\n\n```php\n<?php\n\n/**\n * This file contains an example of coding styles.\n */\n\ndeclare(strict_types=1);\n\nnamespace Vendor\\Package;\n\nuse Vendor\\Package\\{ClassA as A, ClassB, ClassC as C};\nuse Vendor\\Package\\SomeNamespace\\ClassD as D;\nuse Vendor\\Package\\AnotherNamespace\\ClassE as E;\n\nuse function Vendor\\Package\\{functionA, functionB, functionC};\nuse function Another\\Vendor\\functionD;\n\nuse const Vendor\\Package\\{CONSTANT_A, CONSTANT_B, CONSTANT_C};\nuse const Another\\Vendor\\CONSTANT_D;\n\n/**\n * FooBar is an example class.\n */\nclass FooBar\n{\n    // ... additional PHP code ...\n}\n\n```\n\nCompound namespaces with a depth of more than two MUST NOT be used. Therefore the\nfollowing is the maximum compounding depth allowed:\n```php\n<?php\n\nuse Vendor\\Package\\SomeNamespace\\{\n    SubnamespaceOne\\ClassA,\n    SubnamespaceOne\\ClassB,\n    SubnamespaceTwo\\ClassY,\n    ClassZ,\n};\n```\n\nAnd the following would not be allowed:\n\n```php\n<?php\n\nuse Vendor\\Package\\SomeNamespace\\{\n    SubnamespaceOne\\AnotherNamespace\\ClassA,\n    SubnamespaceOne\\ClassB,\n    ClassZ,\n};\n```\n\nWhen wishing to declare strict types in files containing markup outside PHP\nopening and closing tags, the declaration MUST be on the first line of the file\nand include an opening PHP tag, the strict types declaration and closing tag.\n\nFor example:\n```php\n<?php declare(strict_types=1) ?>\n<html>\n<body>\n    <?php\n        // ... additional PHP code ...\n    ?>\n</body>\n</html>\n```\n\nDeclare statements MUST contain no spaces and MUST be exactly `declare(strict_types=1)`\n(with an optional semicolon terminator).\n\nBlock declare statements are allowed and MUST be formatted as below. Note position of\nbraces and spacing:\n```php\ndeclare(ticks=1) {\n    // some code\n}\n```\n\n## 4. Classes, Properties, and Methods\n\nThe term \"class\" refers to all classes, interfaces, and traits.\n\nAny closing brace MUST NOT be followed by any comment or statement on the\nsame line.\n\nWhen instantiating a new class, parentheses MUST always be present even when\nthere are no arguments passed to the constructor.\n\n```php\nnew Foo();\n```\n\n### 4.1 Extends and Implements\n\nThe `extends` and `implements` keywords MUST be declared on the same line as\nthe class name.\n\nThe opening brace for the class MUST go on its own line; the closing brace\nfor the class MUST go on the next line after the body.\n\nOpening braces MUST be on their own line and MUST NOT be preceded or followed\nby a blank line.\n\nClosing braces MUST be on their own line and MUST NOT be preceded by a blank\nline.\n\n```php\n<?php\n\nnamespace Vendor\\Package;\n\nuse FooClass;\nuse BarClass as Bar;\nuse OtherVendor\\OtherPackage\\BazClass;\n\nclass ClassName extends ParentClass implements \\ArrayAccess, \\Countable\n{\n    // constants, properties, methods\n}\n```\n\nLists of `implements` and, in the case of interfaces, `extends` MAY be split\nacross multiple lines, where each subsequent line is indented once. When doing\nso, the first item in the list MUST be on the next line, and there MUST be only\none interface per line.\n\n```php\n<?php\n\nnamespace Vendor\\Package;\n\nuse FooClass;\nuse BarClass as Bar;\nuse OtherVendor\\OtherPackage\\BazClass;\n\nclass ClassName extends ParentClass implements\n    \\ArrayAccess,\n    \\Countable,\n    \\Serializable\n{\n    // constants, properties, methods\n}\n```\n\n### 4.2 Using traits\n\nThe `use` keyword used inside the classes to implement traits MUST be\ndeclared on the next line after the opening brace.\n\n```php\n<?php\n\nnamespace Vendor\\Package;\n\nuse Vendor\\Package\\FirstTrait;\n\nclass ClassName\n{\n    use FirstTrait;\n}\n```\n\nEach individual trait that is imported into a class MUST be included\none-per-line and each inclusion MUST have its own `use` import statement.\n\n```php\n<?php\n\nnamespace Vendor\\Package;\n\nuse Vendor\\Package\\FirstTrait;\nuse Vendor\\Package\\SecondTrait;\nuse Vendor\\Package\\ThirdTrait;\n\nclass ClassName\n{\n    use FirstTrait;\n    use SecondTrait;\n    use ThirdTrait;\n}\n```\n\nWhen the class has nothing after the `use` import statement, the class\nclosing brace MUST be on the next line after the `use` import statement.\n\n```php\n<?php\n\nnamespace Vendor\\Package;\n\nuse Vendor\\Package\\FirstTrait;\n\nclass ClassName\n{\n    use FirstTrait;\n}\n```\n\nOtherwise, it MUST have a blank line after the `use` import statement.\n\n```php\n<?php\n\nnamespace Vendor\\Package;\n\nuse Vendor\\Package\\FirstTrait;\n\nclass ClassName\n{\n    use FirstTrait;\n\n    private $property;\n}\n```\n\nWhen using the `insteadof` and `as` operators they must be used as follows taking\nnote of indentation, spacing, and new lines.\n\n```php\n<?php\n\nclass Talker\n{\n    use A;\n    use B {\n        A::smallTalk insteadof B;\n    }\n    use C {\n        B::bigTalk insteadof C;\n        C::mediumTalk as FooBar;\n    }\n}\n```\n\n### 4.3 Properties and Constants\n\nVisibility MUST be declared on all properties.\n\nVisibility MUST be declared on all constants if your project PHP minimum\nversion supports constant visibilities (PHP 7.1 or later).\n\nThe `var` keyword MUST NOT be used to declare a property.\n\nThere MUST NOT be more than one property declared per statement.\n\nProperty names MUST NOT be prefixed with a single underscore to indicate\nprotected or private visibility. That is, an underscore prefix explicitly has\nno meaning.\n\nThere MUST be a space between type declaration and property name.\n\nA property declaration looks like the following:\n\n```php\n<?php\n\nnamespace Vendor\\Package;\n\nclass ClassName\n{\n    public $foo = null;\n    public static int $bar = 0;\n}\n```\n\n### 4.4 Methods and Functions\n\nVisibility MUST be declared on all methods.\n\nMethod names MUST NOT be prefixed with a single underscore to indicate\nprotected or private visibility. That is, an underscore prefix explicitly has\nno meaning.\n\nMethod and function names MUST NOT be declared with space after the method name. The\nopening brace MUST go on its own line, and the closing brace MUST go on the\nnext line following the body. There MUST NOT be a space after the opening\nparenthesis, and there MUST NOT be a space before the closing parenthesis.\n\nA method declaration looks like the following. Note the placement of\nparentheses, commas, spaces, and braces:\n\n```php\n<?php\n\nnamespace Vendor\\Package;\n\nclass ClassName\n{\n    public function fooBarBaz($arg1, &$arg2, $arg3 = [])\n    {\n        // method body\n    }\n}\n```\n\nA function declaration looks like the following. Note the placement of\nparentheses, commas, spaces, and braces:\n\n```php\n<?php\n\nfunction fooBarBaz($arg1, &$arg2, $arg3 = [])\n{\n    // function body\n}\n```\n\n### 4.5 Method and Function Arguments\n\nIn the argument list, there MUST NOT be a space before each comma, and there\nMUST be one space after each comma.\n\nMethod and function arguments with default values MUST go at the end of the argument\nlist.\n\n```php\n<?php\n\nnamespace Vendor\\Package;\n\nclass ClassName\n{\n    public function foo(int $arg1, &$arg2, $arg3 = [])\n    {\n        // method body\n    }\n}\n```\n\nArgument lists MAY be split across multiple lines, where each subsequent line\nis indented once. When doing so, the first item in the list MUST be on the\nnext line, and there MUST be only one argument per line.\n\nWhen the argument list is split across multiple lines, the closing parenthesis\nand opening brace MUST be placed together on their own line with one space\nbetween them.\n\n```php\n<?php\n\nnamespace Vendor\\Package;\n\nclass ClassName\n{\n    public function aVeryLongMethodName(\n        ClassTypeHint $arg1,\n        &$arg2,\n        array $arg3 = []\n    ) {\n        // method body\n    }\n}\n```\n\nWhen you have a return type declaration present, there MUST be one space after\nthe colon followed by the type declaration. The colon and declaration MUST be\non the same line as the argument list closing parenthesis with no spaces between\nthe two characters.\n\n```php\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Vendor\\Package;\n\nclass ReturnTypeVariations\n{\n    public function functionName(int $arg1, $arg2): string\n    {\n        return 'foo';\n    }\n\n    public function anotherFunction(\n        string $foo,\n        string $bar,\n        int $baz\n    ): string {\n        return 'foo';\n    }\n}\n```\n\nIn nullable type declarations, there MUST NOT be a space between the question mark\nand the type.\n\n```php\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Vendor\\Package;\n\nclass ReturnTypeVariations\n{\n    public function functionName(?string $arg1, ?int &$arg2): ?string\n    {\n        return 'foo';\n    }\n}\n```\n\nWhen using the reference operator `&` before an argument, there MUST NOT be\na space after it, like in the previous example.\n\nThere MUST NOT be a space between the variadic three dot operator and the argument\nname:\n\n```php\npublic function process(string $algorithm, ...$parts)\n{\n    // processing\n}\n```\n\nWhen combining both the reference operator and the variadic three dot operator,\nthere MUST NOT be any space between the two of them:\n\n```php\npublic function process(string $algorithm, &...$parts)\n{\n    // processing\n}\n```\n\n### 4.6 `abstract`, `final`, and `static`\n\nWhen present, the `abstract` and `final` declarations MUST precede the\nvisibility declaration.\n\nWhen present, the `static` declaration MUST come after the visibility\ndeclaration.\n\n```php\n<?php\n\nnamespace Vendor\\Package;\n\nabstract class ClassName\n{\n    protected static $foo;\n\n    abstract protected function zim();\n\n    final public static function bar()\n    {\n        // method body\n    }\n}\n```\n\n### 4.7 Method and Function Calls\n\nWhen making a method or function call, there MUST NOT be a space between the\nmethod or function name and the opening parenthesis, there MUST NOT be a space\nafter the opening parenthesis, and there MUST NOT be a space before the\nclosing parenthesis. In the argument list, there MUST NOT be a space before\neach comma, and there MUST be one space after each comma.\n\n```php\n<?php\n\nbar();\n$foo->bar($arg1);\nFoo::bar($arg2, $arg3);\n```\n\nArgument lists MAY be split across multiple lines, where each subsequent line\nis indented once. When doing so, the first item in the list MUST be on the\nnext line, and there MUST be only one argument per line. A single argument being\nsplit across multiple lines (as might be the case with an anonymous function or\narray) does not constitute splitting the argument list itself.\n\n```php\n<?php\n\n$foo->bar(\n    $longArgument,\n    $longerArgument,\n    $muchLongerArgument\n);\n```\n\n```php\n<?php\n\nsomefunction($foo, $bar, [\n  // ...\n], $baz);\n\n$app->get('/hello/{name}', function ($name) use ($app) {\n    return 'Hello ' . $app->escape($name);\n});\n```\n\n## 5. Control Structures\n\nThe general style rules for control structures are as follows:\n\n- There MUST be one space after the control structure keyword\n- There MUST NOT be a space after the opening parenthesis\n- There MUST NOT be a space before the closing parenthesis\n- There MUST be one space between the closing parenthesis and the opening\n  brace\n- The structure body MUST be indented once\n- The body MUST be on the next line after the opening brace\n- The closing brace MUST be on the next line after the body\n\nThe body of each structure MUST be enclosed by braces. This standardizes how\nthe structures look and reduces the likelihood of introducing errors as new\nlines get added to the body.\n\n### 5.1 `if`, `elseif`, `else`\n\nAn `if` structure looks like the following. Note the placement of parentheses,\nspaces, and braces; and that `else` and `elseif` are on the same line as the\nclosing brace from the earlier body.\n\n```php\n<?php\n\nif ($expr1) {\n    // if body\n} elseif ($expr2) {\n    // elseif body\n} else {\n    // else body;\n}\n```\n\nThe keyword `elseif` SHOULD be used instead of `else if` so that all control\nkeywords look like single words.\n\nExpressions in parentheses MAY be split across multiple lines, where each\nsubsequent line is indented at least once. When doing so, the first condition\nMUST be on the next line. The closing parenthesis and opening brace MUST be\nplaced together on their own line with one space between them. Boolean\noperators between conditions MUST always be at the beginning or at the end of\nthe line, not a mix of both.\n\n```php\n<?php\n\nif (\n    $expr1\n    && $expr2\n) {\n    // if body\n} elseif (\n    $expr3\n    && $expr4\n) {\n    // elseif body\n}\n```\n\n### 5.2 `switch`, `case`\n\nA `switch` structure looks like the following. Note the placement of\nparentheses, spaces, and braces. The `case` statement MUST be indented once\nfrom `switch`, and the `break` keyword (or other terminating keywords) MUST be\nindented at the same level as the `case` body. There MUST be a comment such as\n`// no break` when fall-through is intentional in a non-empty `case` body.\n\n```php\n<?php\n\nswitch ($expr) {\n    case 0:\n        echo 'First case, with a break';\n        break;\n    case 1:\n        echo 'Second case, which falls through';\n        // no break\n    case 2:\n    case 3:\n    case 4:\n        echo 'Third case, return instead of break';\n        return;\n    default:\n        echo 'Default case';\n        break;\n}\n```\n\nExpressions in parentheses MAY be split across multiple lines, where each\nsubsequent line is indented at least once. When doing so, the first condition\nMUST be on the next line. The closing parenthesis and opening brace MUST be\nplaced together on their own line with one space between them. Boolean\noperators between conditions MUST always be at the beginning or at the end of\nthe line, not a mix of both.\n\n```php\n<?php\n\nswitch (\n    $expr1\n    && $expr2\n) {\n    // structure body\n}\n```\n\n### 5.3 `while`, `do while`\n\nA `while` statement looks like the following. Note the placement of\nparentheses, spaces, and braces.\n\n```php\n<?php\n\nwhile ($expr) {\n    // structure body\n}\n```\n\nExpressions in parentheses MAY be split across multiple lines, where each\nsubsequent line is indented at least once. When doing so, the first condition\nMUST be on the next line. The closing parenthesis and opening brace MUST be\nplaced together on their own line with one space between them. Boolean\noperators between conditions MUST always be at the beginning or at the end of\nthe line, not a mix of both.\n\n```php\n<?php\n\nwhile (\n    $expr1\n    && $expr2\n) {\n    // structure body\n}\n```\n\nSimilarly, a `do while` statement looks like the following. Note the placement\nof parentheses, spaces, and braces.\n\n```php\n<?php\n\ndo {\n    // structure body;\n} while ($expr);\n```\n\nExpressions in parentheses MAY be split across multiple lines, where each\nsubsequent line is indented at least once. When doing so, the first condition\nMUST be on the next line. Boolean operators between conditions MUST\nalways be at the beginning or at the end of the line, not a mix of both.\n\n```php\n<?php\n\ndo {\n    // structure body;\n} while (\n    $expr1\n    && $expr2\n);\n```\n\n### 5.4 `for`\n\nA `for` statement looks like the following. Note the placement of parentheses,\nspaces, and braces.\n\n```php\n<?php\n\nfor ($i = 0; $i < 10; $i++) {\n    // for body\n}\n```\n\nExpressions in parentheses MAY be split across multiple lines, where each\nsubsequent line is indented at least once. When doing so, the first expression\nMUST be on the next line. The closing parenthesis and opening brace MUST be\nplaced together on their own line with one space between them.\n\n```php\n<?php\n\nfor (\n    $i = 0;\n    $i < 10;\n    $i++\n) {\n    // for body\n}\n```\n\n### 5.5 `foreach`\n\nA `foreach` statement looks like the following. Note the placement of\nparentheses, spaces, and braces.\n\n```php\n<?php\n\nforeach ($iterable as $key => $value) {\n    // foreach body\n}\n```\n\n### 5.6 `try`, `catch`, `finally`\n\nA `try-catch-finally` block looks like the following. Note the placement of\nparentheses, spaces, and braces.\n\n```php\n<?php\n\ntry {\n    // try body\n} catch (FirstThrowableType $e) {\n    // catch body\n} catch (OtherThrowableType | AnotherThrowableType $e) {\n    // catch body\n} finally {\n    // finally body\n}\n```\n\n## 6. Operators\n\nStyle rules for operators are grouped by arity (the number of operands they take).\n\nWhen space is permitted around an operator, multiple spaces MAY be\nused for readability purposes.\n\nAll operators not described here are left undefined.\n\n### 6.1. Unary operators\n\nThe increment/decrement operators MUST NOT have any space between\nthe operator and operand.\n```php\n$i++;\n++$j;\n```\n\nType casting operators MUST NOT have any space within the parentheses:\n```php\n$intValue = (int) $input;\n```\n\n### 6.2. Binary operators\n\nAll binary [arithmetic][], [comparison][], [assignment][], [bitwise][],\n[logical][], [string][], and [type][] operators MUST be preceded and\nfollowed by at least one space:\n```php\nif ($a === $b) {\n    $foo = $bar ?? $a ?? $b;\n} elseif ($a > $b) {\n    $foo = $a + $b * $c;\n}\n```\n\n### 6.3. Ternary operators\n\nThe conditional operator, also known simply as the ternary operator, MUST be\npreceded and followed by at least one space around both the `?`\nand `:` characters:\n```php\n$variable = $foo ? 'foo' : 'bar';\n```\n\nWhen the middle operand of the conditional operator is omitted, the operator\nMUST follow the same style rules as other binary [comparison][] operators:\n```php\n$variable = $foo ?: 'bar';\n```\n\n## 7. Closures\n\nClosures MUST be declared with a space after the `function` keyword, and a\nspace before and after the `use` keyword.\n\nThe opening brace MUST go on the same line, and the closing brace MUST go on\nthe next line following the body.\n\nThere MUST NOT be a space after the opening parenthesis of the argument list\nor variable list, and there MUST NOT be a space before the closing parenthesis\nof the argument list or variable list.\n\nIn the argument list and variable list, there MUST NOT be a space before each\ncomma, and there MUST be one space after each comma.\n\nClosure arguments with default values MUST go at the end of the argument\nlist.\n\nIf a return type is present, it MUST follow the same rules as with normal\nfunctions and methods; if the `use` keyword is present, the colon MUST follow\nthe `use` list closing parentheses with no spaces between the two characters.\n\nA closure declaration looks like the following. Note the placement of\nparentheses, commas, spaces, and braces:\n\n```php\n<?php\n\n$closureWithArgs = function ($arg1, $arg2) {\n    // body\n};\n\n$closureWithArgsAndVars = function ($arg1, $arg2) use ($var1, $var2) {\n    // body\n};\n\n$closureWithArgsVarsAndReturn = function ($arg1, $arg2) use ($var1, $var2): bool {\n    // body\n};\n```\n\nArgument lists and variable lists MAY be split across multiple lines, where\neach subsequent line is indented once. When doing so, the first item in the\nlist MUST be on the next line, and there MUST be only one argument or variable\nper line.\n\nWhen the ending list (whether of arguments or variables) is split across\nmultiple lines, the closing parenthesis and opening brace MUST be placed\ntogether on their own line with one space between them.\n\nThe following are examples of closures with and without argument lists and\nvariable lists split across multiple lines.\n\n```php\n<?php\n\n$longArgs_noVars = function (\n    $longArgument,\n    $longerArgument,\n    $muchLongerArgument\n) {\n   // body\n};\n\n$noArgs_longVars = function () use (\n    $longVar1,\n    $longerVar2,\n    $muchLongerVar3\n) {\n   // body\n};\n\n$longArgs_longVars = function (\n    $longArgument,\n    $longerArgument,\n    $muchLongerArgument\n) use (\n    $longVar1,\n    $longerVar2,\n    $muchLongerVar3\n) {\n   // body\n};\n\n$longArgs_shortVars = function (\n    $longArgument,\n    $longerArgument,\n    $muchLongerArgument\n) use ($var1) {\n   // body\n};\n\n$shortArgs_longVars = function ($arg) use (\n    $longVar1,\n    $longerVar2,\n    $muchLongerVar3\n) {\n   // body\n};\n```\n\nNote that the formatting rules also apply when the closure is used directly\nin a function or method call as an argument.\n\n```php\n<?php\n\n$foo->bar(\n    $arg1,\n    function ($arg2) use ($var1) {\n        // body\n    },\n    $arg3\n);\n```\n\n## 8. Anonymous Classes\n\nAnonymous Classes MUST follow the same guidelines and principles as closures\nin the above section.\n\n```php\n<?php\n\n$instance = new class {};\n```\n\nThe opening brace MAY be on the same line as the `class` keyword so long as\nthe list of `implements` interfaces does not wrap. If the list of interfaces\nwraps, the brace MUST be placed on the line immediately following the last\ninterface.\n\n```php\n<?php\n\n// Brace on the same line\n$instance = new class extends \\Foo implements \\HandleableInterface {\n    // Class content\n};\n\n// Brace on the next line\n$instance = new class extends \\Foo implements\n    \\ArrayAccess,\n    \\Countable,\n    \\Serializable\n{\n    // Class content\n};\n```\n\n[PSR-1]: https://www.php-fig.org/psr/psr-1/\n[PSR-2]: https://www.php-fig.org/psr/psr-2/\n[keywords]: http://php.net/manual/en/reserved.keywords.php\n[types]: http://php.net/manual/en/reserved.other-reserved-words.php\n[arithmetic]: http://php.net/manual/en/language.operators.arithmetic.php\n[assignment]: http://php.net/manual/en/language.operators.assignment.php\n[comparison]: http://php.net/manual/en/language.operators.comparison.php\n[bitwise]: http://php.net/manual/en/language.operators.bitwise.php\n[logical]: http://php.net/manual/en/language.operators.logical.php\n[string]: http://php.net/manual/en/language.operators.string.php\n[type]: http://php.net/manual/en/language.operators.type.php\n"
  },
  {
    "path": "accepted/PSR-13-links-meta.md",
    "content": "# Link Definition Meta Document\n\n## 1. Summary\n\nHypermedia links are becoming an increasingly important part of the web, in both HTML contexts\nand various API format contexts. However, there is no single common hypermedia format, nor\nis there a common way to represent Links between formats.\n\nThis specification aims to provide PHP developers with a simple, common way of representing a\nhypermedia link independently of the serialization format that is used. That in turn allows\na system to serialize a response with hypermedia links into one or more wire formats independently\nof the process of deciding what those links should be.\n\n## 2. Scope\n\n### 2.1 Goals\n\n* This specification aims to extract and standardize hypermedia link representation between different\nformats.\n\n### 2.2 Non-Goals\n\n* This specification does not seek to standardize or favor any particular hypermedia serialization format.\n\n## 3. Design Decisions\n\n### Why no mutator methods?\n\nOne of the key targets for this specification is PSR-7 Response objects.  Response objects by design must be\nimmutable.  Other value-object implementations likely would also require an immutable interface.\n\nAdditionally, some Link Provider objects may not be value objects but other objects within a given\ndomain, which are able to generate Links on the fly, perhaps off of a database result or other underlying\nrepresentation.  In those cases a writeable provider definition would be incompatible.\n\nTherefore, this specification splits accessor methods and evolvable methods into separate interfaces,\nallowing objects to implement just the read-only or evolvable versions as appropriate to their use case.\n\n### Why is rel on a Link object multi-value?\n\nDifferent hypermedia standards handle multiple links with the same relationship differently. Some have a single\nlink that has multiple rel's defined. Others have a single rel entry that then contains multiple links.\n\nDefining each Link uniquely but allowing it to have multiple rels provides a most-compatible-denominator definition.\nA single LinkInterface object may be serialized to one or more link entries in a given hypermedia format, as\nappropriate.  However, specifying multiple link objects each with a single rel yet the same URI is also legal, and\na hypermedia format can serialize that as appropriate, too.\n\n### Why is a LinkProviderInterface needed?\n\nIn many contexts, a set of links will be attached to some other object.  Those objects may be used in situations\nwhere all that is relevant is their links, or some subset of their links. For example, various different value\nobjects may be defined that represent different REST formats such as HAL, JSON-LD, or Atom.  It may be useful\nto extract those links from such an object uniformly for further processing. For instance, next/previous links\nmay be extracted from an object and added to a PSR-7 Response object as Link headers.  Alternatively, many links\nwould make sense to represent with a \"preload\" link relationship, which would indicate to an HTTP 2-compatible\nweb server that the linked resources should be streamed to a client in anticipation of a subsequent request.\n\nAll of those cases are independent of the payload or encoding of the object. By providing a common interface\nto access such links, we enable generic handling of the links themselves regardless of the value object or\ndomain object that is producing them.\n\n## 4. People\n\n### 4.1 Editor(s)\n\n* Larry Garfield\n\n### 4.2 Sponsors\n\n* Matthew Weier O'Phinney (coordinator)\n* Marc Alexander\n\n### 4.3 Contributors\n\n* Evert Pot\n\n## 5. Votes\n\n## 6. Relevant links\n\n* [What's in a link?](http://evertpot.com/whats-in-a-link/) by Evert Pot\n* [FIG Link Working Group List](https://groups.google.com/forum/#!forum/php-fig-link)\n\n## 7. Errata\n\n### 7.1 Type additions\n\nThe 1.1 release of the `psr/link` package includes scalar parameter types.  The 2.0 release of the package includes return types.  This structure leverages PHP 7.2 covariance support to allow for a gradual upgrade process, but requires PHP 8.0 for type compatibility.\n\nImplementers MAY add return types to their own packages at their discretion, provided that:\n\n* the return types match those in the 2.0 package.\n* the implementation specifies a minimum PHP version of 8.0.0 or later.\n\nImplementers MAY add parameter types to their own packages in a new major release, either at the same time as adding return types or in a subsequent release, provided that:\n\n* the parameter types match those in the 1.1 package.\n* the implementation specifies a minimum PHP version of 8.0.0 or later.\n* the implementation depends on `\"psr/link\": \"^1.1 || ^2.0\"` so as to exclude the untyped 1.0 version.\n\nImplementers are encouraged but not required to transition their packages toward the 2.0 version of the package at their earliest convenience.\n\n### 7.2 Attribute type handling\n\nThe original specification contained an inconsistency regarding array values for attributes.  The text of the specification states in section 1.2 that attribute values (as passed to `EvolvableLinkInterface::withAttribute()`) could be of multiple types, some of which allowed for special handling (such as booleans or arrays).  However, the docblock for that method specified that the `$value` parameter had to be a string, which was incorrect.\n\nTo address this issue, the interface has been corrected in later releases to allow `$value` to be of type `string|\\Stringable|int|float|bool|array`.  Implementers SHOULD treat a `Stringable` object the same as a `string` parameter.  Implementers MAY serialize `int`, `float`, or `bool` in alternate, type-aware ways for a particular serialization format as appropriate.  Other object types or resources remain disallowed.\n\nMultiple calls to `withAttribute()` with the same `$name` MUST override previously provided values, as the spec already states.  To provide multiple values to a particular attribute, pass an `array` with the desired values.\n\nAll other guidelines and requirements in section 1.2 remain valid.\n"
  },
  {
    "path": "accepted/PSR-13-links.md",
    "content": "# Link definition interfaces\n\nHypermedia links are becoming an increasingly important part of the web, in both HTML contexts\nand various API format contexts. However, there is no single common hypermedia format, nor\nis there a common way to represent links between formats.\n\nThis specification aims to provide PHP developers with a simple, common way of representing a\nhypermedia link independently of the serialization format that is used. That in turn allows\na system to serialize a response with hypermedia links into one or more wire formats independently\nof the process of deciding what those links should be.\n\nThe key words \"MUST\", \"MUST NOT\", \"REQUIRED\", \"SHALL\", \"SHALL NOT\", \"SHOULD\",\n\"SHOULD NOT\", \"RECOMMENDED\", \"MAY\", and \"OPTIONAL\" in this document are to be\ninterpreted as described in [RFC 2119](http://tools.ietf.org/html/rfc2119).\n\n### References\n\n- [RFC 2119](http://tools.ietf.org/html/rfc2119)\n- [RFC 4287](https://tools.ietf.org/html/rfc4287)\n- [RFC 5988](https://tools.ietf.org/html/rfc5988)\n- [RFC 6570](https://tools.ietf.org/html/rfc6570)\n- [IANA Link Relations Registry](http://www.iana.org/assignments/link-relations/link-relations.xhtml)\n- [Microformats Relations List](http://microformats.org/wiki/existing-rel-values#HTML5_link_type_extensions)\n\n## 1. Specification\n\n### 1.1 Basic links\n\nA Hypermedia Link consists of, at minimum:\n- A URI representing the target resource being referenced.\n- A relationship defining how the target resource relates to the source.\n\nVarious other attributes of the Link may exist, depending on the format used. As additional attributes\nare not well-standardized or universal, this specification does not seek to standardize them.\n\nFor the purposes of this specification, the following definitions apply.\n\n*    **Implementing Object** - An object that implements one of the interfaces defined by this\nspecification.\n\n*    **Serializer** - A library or other system that takes one or more Link objects and produces\na serialized representation of it in some defined format.\n\n### 1.2 Attributes\n\nAll links MAY include zero or more additional attributes beyond the URI and relationship.\nThere is no formal registry of the values that are allowed here, and validity of values\nis dependent on context and often on a particular serialization format. Commonly supported\nvalues include 'hreflang', 'title', and 'type'.\n\nSerializers MAY omit attributes on a link object if required to do so by the serialization\nformat. However, serializers SHOULD encode all provided attributes possible in order to\nallow for user-extension unless prevented by a serialization format's definition.\n\nSome attributes (commonly `hreflang`) may appear more than once in their context. Therefore,\nan attribute value MAY be an array of values rather than a simple value. Serializers MAY\nencode that array in whatever format is appropriate for the serialized format (such\nas a space-separated list, comma-separated list, etc.). If a given attribute is not\nallowed to have multiple values in a particular context, serializers MUST use the first\nvalue provided and ignore all subsequent values.\n\nIf an attribute value is boolean `true`, serializers MAY use abbreviated forms if appropriate\nand supported by a serialization format. For example, HTML permits attributes to\nhave no value when the attribute's presence has a boolean meaning. This rule applies\nif and only if the attribute is boolean `true`, not for any other \"truthy\" value\nin PHP such as integer 1.\n\nIf an attribute value is boolean `false`, serializers SHOULD omit the attribute entirely\nunless doing so changes the semantic meaning of the result. This rule applies if\nand only if the attribute is boolean `false`, not for any other \"falsey\" value in PHP\nsuch as integer 0.\n\n### 1.3 Relationships\n\nLink relationships are defined as strings, and are either a simple keyword in\ncase of a publicly defined relationship or an absolute URI in the case of a\nprivate relationships.\n\nIn case a simple keyword is used, it SHOULD match one from the IANA registry at:\n\nhttp://www.iana.org/assignments/link-relations/link-relations.xhtml\n\nOptionally the microformats.org registry MAY be used, but this may not be valid\nin every context:\n\nhttp://microformats.org/wiki/existing-rel-values\n\nA relationship that is not defined in one of the above registries or a similar\npublic registry is considered \"private\", that is, specific to a particular\napplication or use case. Such relationships MUST use an absolute URI.\n\n## 1.4 Link Templates\n\n[RFC 6570](https://tools.ietf.org/html/rfc6570) defines a format for URI templates, that is,\na pattern for a URI that is expected to be filled in with values provided by a client\ntool. Some hypermedia formats support templated links while others do not, and may\nhave a special way to denote that a link is a template. A Serializer for a format\nthat does not support URI Templates MUST ignore any templated Links it encounters.\n\n## 1.5 Evolvable providers\n\nIn some cases, a Link Provider may need the ability to have additional links\nadded to it. In others, a link provider is necessarily read-only, with links\nderived at runtime from some other data source. For that reason, modifiable providers\nare a secondary interface that may optionally be implemented.\n\nAdditionally, some Link Provider objects, such as PSR-7 Response objects, are\nby design immutable. That means methods to add links to them in-place would be\nincompatible. Therefore, the `EvolvableLinkProviderInterface`'s single method\nrequires that a new object be returned, identical to the original but with\nan additional Link object included.\n\n## 1.6 Evolvable link objects\n\nLink objects are in most cases value objects. As such, allowing them to evolve\nin the same fashion as PSR-7 value objects is a useful option. For that reason,\nan additional EvolvableLinkInterface is included that provides methods to\nproduce new object instances with a single change. The same model is used by PSR-7\nand, thanks to PHP's copy-on-write behavior, is still CPU and memory efficient.\n\nThere is no evolvable method for templated values, however, as the templated value of a\nlink is based exclusively on the href value. It MUST NOT be set independently, but\nderived from whether or not the href value is an RFC 6570 link template.\n\n## 2. Package\n\nThe interfaces and classes described are provided as part of the\n[psr/link](https://packagist.org/packages/psr/link) package.\n\n## 3. Interfaces\n\n### 3.1 `Psr\\Link\\LinkInterface`\n\n```php\n<?php\n\nnamespace Psr\\Link;\n\n/**\n * A readable link object.\n */\ninterface LinkInterface\n{\n    /**\n     * Returns the target of the link.\n     *\n     * The target link must be one of:\n     * - An absolute URI, as defined by RFC 5988.\n     * - A relative URI, as defined by RFC 5988. The base of the relative link\n     *     is assumed to be known based on context by the client.\n     * - A URI template as defined by RFC 6570.\n     *\n     * If a URI template is returned, isTemplated() MUST return True.\n     *\n     * @return string\n     */\n    public function getHref();\n\n    /**\n     * Returns whether or not this is a templated link.\n     *\n     * @return bool\n     *   True if this link object is templated, False otherwise.\n     */\n    public function isTemplated();\n\n    /**\n     * Returns the relationship type(s) of the link.\n     *\n     * This method returns 0 or more relationship types for a link, expressed\n     * as an array of strings.\n     *\n     * @return string[]\n     */\n    public function getRels();\n\n    /**\n     * Returns a list of attributes that describe the target URI.\n     *\n     * @return array\n     *   A key-value list of attributes, where the key is a string and the value\n     *  is either a PHP primitive or an array of PHP strings. If no values are\n     *  found an empty array MUST be returned.\n     */\n    public function getAttributes();\n}\n```\n\n### 3.2 `Psr\\Link\\EvolvableLinkInterface`\n\n```php\n<?php\n\nnamespace Psr\\Link;\n\n/**\n * An evolvable link value object.\n */\ninterface EvolvableLinkInterface extends LinkInterface\n{\n    /**\n     * Returns an instance with the specified href.\n     *\n     * @param string $href\n     *   The href value to include. It must be one of:\n     *     - An absolute URI, as defined by RFC 5988.\n     *     - A relative URI, as defined by RFC 5988. The base of the relative link\n     *       is assumed to be known based on context by the client.\n     *     - A URI template as defined by RFC 6570.\n     *     - An object implementing __toString() that produces one of the above\n     *       values.\n     *\n     * An implementing library SHOULD evaluate a passed object to a string\n     * immediately rather than waiting for it to be returned later.\n     *\n     * @return static\n     */\n    public function withHref($href);\n\n    /**\n     * Returns an instance with the specified relationship included.\n     *\n     * If the specified rel is already present, this method MUST return\n     * normally without errors, but without adding the rel a second time.\n     *\n     * @param string $rel\n     *   The relationship value to add.\n     * @return static\n     */\n    public function withRel($rel);\n\n    /**\n     * Returns an instance with the specified relationship excluded.\n     *\n     * If the specified rel is already not present, this method MUST return\n     * normally without errors.\n     *\n     * @param string $rel\n     *   The relationship value to exclude.\n     * @return static\n     */\n    public function withoutRel($rel);\n\n    /**\n     * Returns an instance with the specified attribute added.\n     *\n     * If the specified attribute is already present, it will be overwritten\n     * with the new value.\n     *\n     * @param string $attribute\n     *   The attribute to include.\n     * @param string $value\n     *   The value of the attribute to set.\n     * @return static\n     */\n    public function withAttribute($attribute, $value);\n\n    /**\n     * Returns an instance with the specified attribute excluded.\n     *\n     * If the specified attribute is not present, this method MUST return\n     * normally without errors.\n     *\n     * @param string $attribute\n     *   The attribute to remove.\n     * @return static\n     */\n    public function withoutAttribute($attribute);\n}\n```\n\n#### 3.2 `Psr\\Link\\LinkProviderInterface`\n\n```php\n<?php\n\nnamespace Psr\\Link;\n\n/**\n * A link provider object.\n */\ninterface LinkProviderInterface\n{\n    /**\n     * Returns an iterable of LinkInterface objects.\n     *\n     * The iterable may be an array or any PHP \\Traversable object. If no links\n     * are available, an empty array or \\Traversable MUST be returned.\n     *\n     * @return LinkInterface[]|\\Traversable\n     */\n    public function getLinks();\n\n    /**\n     * Returns an iterable of LinkInterface objects that have a specific relationship.\n     *\n     * The iterable may be an array or any PHP \\Traversable object. If no links\n     * with that relationship are available, an empty array or \\Traversable MUST be returned.\n     *\n     * @return LinkInterface[]|\\Traversable\n     */\n    public function getLinksByRel($rel);\n}\n```\n\n#### 3.3 `Psr\\Link\\EvolvableLinkProviderInterface`\n\n```php\n<?php\n\nnamespace Psr\\Link;\n\n/**\n * An evolvable link provider value object.\n */\ninterface EvolvableLinkProviderInterface extends LinkProviderInterface\n{\n    /**\n     * Returns an instance with the specified link included.\n     *\n     * If the specified link is already present, this method MUST return normally\n     * without errors. The link is present if $link is === identical to a link\n     * object already in the collection.\n     *\n     * @param LinkInterface $link\n     *   A link object that should be included in this collection.\n     * @return static\n     */\n    public function withLink(LinkInterface $link);\n\n    /**\n     * Returns an instance with the specified link removed.\n     *\n     * If the specified link is not present, this method MUST return normally\n     * without errors. The link is present if $link is === identical to a link\n     * object already in the collection.\n     *\n     * @param LinkInterface $link\n     *   The link to remove.\n     * @return static\n     */\n    public function withoutLink(LinkInterface $link);\n}\n```\n\nSince [psr/link version 1.1](https://packagist.org/packages/psr/link#1.1.0), the above interfaces have been updated to add argument type hints.\nSince [psr/link version 2.0](https://packagist.org/packages/psr/link#2.0.0), the above interfaces have been updated to add return type hints.  References to `array|\\Traversable` have been replaced with `iterable`.\n"
  },
  {
    "path": "accepted/PSR-14-event-dispatcher-meta.md",
    "content": "Event Dispatcher Meta Document\n==============================\n\n## 1. Summary\n\nThe purpose of this document is to describe the rationale and logic behind the Event Dispatcher specification.\n\n## 2. Why Bother?\n\nMany libraries, components, and frameworks have long supported mechanisms for allowing arbitrary third party code to interact with them.  Most are variations on the classic Observer pattern, often mediated through an intermediary object or service.  Others take a more Aspect-Oriented Programming (AOP) approach.  Nonetheless all have the same basic concept: interrupt program flow at a fixed point to provide information to arbitrary third party libraries with information about the action being performed and allow them to either react or influence the program behavior.\n\nThis is a well-established model, but a standard mechanism by which libraries do so will allow them to interoperate with more and more varied third party libraries with less effort by both the original developer and extension developers.\n\n## 3. Scope\n\n### 3.1 Goals\n\n* Simplify and standardize the process by which libraries and components may expose themselves to extension via \"events\" so that they may be more easily incorporated into applications and frameworks.\n* Simplify and standardize the process by which libraries and components may register an interest in responding to an Event so that they may be more easily incorporated into arbitrary applications and frameworks.\n* To the extent feasible, ease the process for existing code bases to transition toward this specification.\n\n### 3.2 Non-Goals\n\n* Asynchronous systems often have a concept of an \"event loop\" to manage interleaving coroutines.  That is an unrelated matter and explicitly irrelevant to this specification.\n* Storage systems implementing an \"Event Source\" pattern also have a concept of an \"event\".  That is unrelated to the Events discussed here and explicitly out of scope.\n* Strict backward compatibility with existing event systems is not a priority and is not expected.\n* While this specification will undoubtedly suggest implementation patterns, it does not seek to define One True Event Dispatcher Implementation, only how callers and Listeners communicate with that Dispatcher.\n\n## 4. Approaches\n\n### 4.1 Use cases considered\n\nThe Working Group identified four possible workflows for event passing, based on use cases seen in the wild in various systems.\n\n* One-way notification.  (\"I did a thing, if you care.\")\n* Object enhancement.  (\"Here's a thing, please modify it before I do something with it.\")\n* Collection.  (\"Give me all your things, that I may do something with that list.\")\n* Alternative chain.  (\"Here's a thing; the first one of you that can handle it do so, then stop.\")\n\nOn further review, the Working Goup determined that:\n\n* Collection was a special case of object enhancement (the collection being the object that is enhanced).\n* Alternative chain is similarly a special case of object enhancement, as the signature is identical and the dispatch workflow is nearly identical, albeit with an extra check included.\n* One-way notification is a degenerate case of the others, or can be represented as such.\n\nAlthough in concept one-way notification can be done asynchronously (including delaying it through a queue), in practice, few explicit implementations of that model exist, providing fewer places from which to draw guidance on details (such as proper error handling).  After much consideration, the Working Group elected not to provide an explicitly separate workflow for one-way notification as it could be adequately represented as a degenerate case of the others.\n\n### 4.2 Example applications\n\n* Indicating that some change in system configuration or some user action has occurred and allowing other systems to react in ways that do not affect program flow (such as sending an email or logging the action).\n* Passing an object to a series of Listeners to allow it to be modified before it is saved to a persistence system.\n* Passing a collection to a series of Listeners to allow them to register values with it or modify existing values so that the Emitter may act on all of the collected information.\n* Passing some contextual information to a series of Listeners so that all of them may \"vote\" on what action to take, with the Emitter deciding based on the aggregate information provided.\n* Passing an object to a series of Listeners and allowing any Listener to terminate the process early before other Listeners have completed.\n\n### 4.3 Immutable events\n\nInitially the Working Group wished to define all Events as immutable message objects, similar to PSR-7.  However, that proved problematic in all but the one-way notification case.  In the other scenarios, Listeners needed a way to return data to the caller.  In concept, there were three possible avenues:\n\n* Make the Event mutable and modify it in place.\n* Require that Events be evolvable (immutable but with `with*()` methods like PSR-7 and PSR-13) and that Listeners return the Event to pass along.\n* Make the Event immutable, but aggregate and return the return value from each Listener.\n\nHowever, Stoppable Events (the alternative chain case) also needed to have a channel by which to indicate that further Listeners should not be called.  That could be done either by:\n\n* Modifying the Event (e.g., calling a `stopPropagation()` method)\n* Returning a sentinel value from the Listener (`true` or `false`) to indicate that propagation should terminate.\n* Evolving the Event to be stopped (`withPropagationStopped()`)\n\nEach of these alternatives have drawbacks. The first means that, at least for the purposes of indicating propagation status, Events must be mutable. The second requires that Listeners return a value, at least when they intend to halt event propagation; this could have ramifications with existing libraries, and potential issues in terms of documentation. The third requires that Listeners return the Event or mutated Event in all cases, and would require Dispatchers to test to ensure that the returned value is of the same type as the value passed to the Listener; it effectively puts an onus both on consumers and implementers, thus raising more potential integration issues.\n\nAdditionally, a desired feature was the ability to derive whether or not to stop propagation based on values collected from the Listeners.  (For example, to stop when one of them has provided a certain value, or after at least three of them have indicated a \"reject this request\" flag, or similar.)  While technically possible to implement as an evolvable object, such behavior is intrinsically stateful, so would be highly cumbersome for both implementers and users.\n\nHaving Listeners return evolvable Events also posed a challenge.  That pattern is not used by any known implementations in PHP or elsewhere.  It also relies on the Listener to remember to return the Event (additional work for the Listener author) and to not return some other, new object that might not be fully compatible with later Listeners (such as a subclass or superclass of the Event).\n\nImmutable Events also rely on the Event author to respect the admonition to be immutable.  Events are, by nature, very loosely designed, and the potential for implementers to ignore that part of the spec, even inadvertently, is high.\n\nThat left two possible options:\n\n* Allow Events to be mutable.\n* Require, but be unable to enforce, immutable Events with a high-ceremony interface, more work for Listener authors, and a higher potential for breakage that may not be detectable at compile time.\n\nBy \"high-ceremony\", we imply that verbose syntax and/or implementations would be required.  In the former case, Listener authors would need to (a) create a new Event instance with the propagation flag toggled, and (b) return the new Event instance so that the Dispatcher could examine it:\n\n```php\nfunction (SomeEvent $event) : SomeEvent\n{\n    // do some work\n    return $event->withPropagationStopped();\n}\n```\n\nThe latter case, Dispatcher implementations, would require checks on the return value:\n\n```php\nforeach ($provider->getListenersForEvent($event) as $listener) {\n    $returnedEvent = $listener($event);\n    \n    if (! $returnedEvent instanceof $event) {\n        // This is an exceptional case!\n        // \n        // We now have an event of a different type, or perhaps nothing was\n        // returned by the listener. An event of a different type might mean:\n        // \n        // - we need to trigger the new event\n        // - we have an event mismatch, and should raise an exception\n        // - we should attempt to trigger the remaining listeners anyway\n        // \n        // In the case of nothing being returned, this could mean any of:\n        // \n        // - we should continue triggering, using the original event\n        // - we should stop triggering, and treat this as a request to\n        //   stop propagation\n        // - we should raise an exception, because the listener did not\n        //   return what was expected\n        //\n        // In short, this becomes very hard to specify, or enforce.\n    }\n\n    if ($returnedEvent instanceof StoppableEventInterface\n        && $returnedEvent->isPropagationStopped()\n    ) {\n        break;\n    }\n}\n```\n\nIn both situations, we would be introducing more potential edge cases, with little benefit, and few language-level mechanisms to guide developers to correct implementation.\n\nGiven these options, the Working Group felt mutable Events were the safer alternative.\n\nThat said, *there is no requirement that an Event be mutable*.  Implementers should provide mutator methods on an Event object *if and only if it is necessary* and appropriate to the use case at hand.\n\n### 4.4 Listener registration\n\nExperimentation during development of the specification determined that there were a wide range of viable, legitimate means by which a Dispatcher could be informed of a Listener.  A Listener:\n\n* could be registered explicitly;\n* could be registered explicitly based on reflection of its signature;\n* could be registered with a numeric priority order;\n* could be registered using a before/after mechanism to control ordering more precisely;\n* could be registered from a service container;\n* could use a pre-compile step to generate code;\n* could be based on method names on objects in the Event itself;\n* could be limited to certain situations or contexts based on arbitrarily complex logic (only for certain users, only on certain days, only if certain system settings are present, etc).\n\nThese and other mechanisms all exist in the wild today in PHP, all are valid use cases worth supporting, and few if any can be conveniently represented as a special case of another.  That is, standardizing one way, or even a small set of ways, to inform the system of a Listener turned out to be impractical if not impossible without cutting off many use cases that should be supported.\n\nThe Working Group therefore chose to encapsulate the registration of Listeners behind the `ListenerProviderInterface`.  A Provider object may have an explicit registration mechanism available, or multiple such mechanisms, or none.  It could also be generated code produced by some compile step.  However, that also splits the responsibility of managing the process of dispatching an Event from the process of mapping an Event to Listeners.  That way different implementations may be mixed-and-matched with different Provider mechanisms as needed.\n\nIt is even possible, and potentially advisable, to allow libraries to include their own Providers that get aggregated into a common Provider that aggregates their Listeners to return to the Dispatcher.  That is one possible way to handle arbitrary Listener registration within an arbitrary framework, although the Working Group is clear that is not the only option.\n\nWhile combining the Dispatcher and Provider into a single object is a valid and permissible degenerate case, it is NOT RECOMMENDED as it reduces the flexibility of system integrators.  Instead, the Provider SHOULD be composed as a dependent object.\n\n### 4.5 Deferred listeners\n\nThe specification requires that the callables returned by a Provider MUST all be invoked (unless propagation is explicitly stopped) before the Dispatcher returns.  However, the specification also explicitly states that Listeners may enqueue Events for later processing rather than taking immediate action.  It is also entirely permissible for a Provider to accept registration of a callable, but then wrap it in another callable before returning it to the Dispatcher.  (In that case, the wrapper is the Listener from the Dispatcher's point of view.)  That allows all of the following behaviors to be legal:\n\n* Providers return callable Listeners that were provided to them.\n* Providers return callables that create an entry in a queue that will react to the Event with another callable at some later point in time.\n* Listeners may themselves create an entry in a queue that will react to the Event at some later point in time.\n* Listeners or Providers may trigger an asynchronous task, if running in an environment with support for asynchronous behavior (assuming that the result of the asynchronous task is not needed by the Emitter.)\n* Providers may perform such delay or wrapping on Listeners selectively based on arbitrary logic.\n\nThe net result is that Providers and Listeners are responsible for determining when it is safe to defer a response to an Event until some later time.  In that case, the Provider or Listener is explicitly opting out of being able to pass meaningful data back to the Emitter, but the Working Group determined that they were in the best position to know if it was safe to do so.\n\nWhile technically a side effect of the design, it is essentially the same approach used by Laravel (as of Laravel 5) and has been proven in the wild.\n\n### 4.6 Return values\n\nPer the spec, a Dispatcher MUST return the Event passed by the Emitter.  This is specified to provide a more ergonomic experience for users, allowing short-hands similar to the following:\n\n```php\n$event = $dispatcher->dispatch(new SomeEvent('some context'));\n\n$items = $dispatcher->dispatch(new ItemCollector())->getItems();\n```\n\nThe `EventDispatcher::dispatch()` interface, however, has no return type specified.  That is primarily for backward compatibility with existing implementations to make it easier for them to adopt the new interface.  Additionally, as Events can be any arbitrary object the return type could only have been `object`, which would provide only minimal (albeit non-zero) value, as that type declaration would not provide IDEs with any useful information nor would it effectively enforce that the same Event is returned.  The method return was thus left syntactically untyped.  However, returning the same Event object from `dispatch()` is still a requirement and failure to do so is a violation of the specification.\n\n## 5. People\n\nThe Event Manager Working Group consisted of:\n\n### 5.1 Editor\n\n* Larry Garfield\n\n### 5.2 Sponsor\n\n* Cees-Jan Kiewiet\n\n### 5.3 Working Group Members\n\n* Benjamin Mack\n* Elizabeth Smith\n* Ryan Weaver\n* Matthew Weier O'Phinney\n\n## 6. Votes\n\n* [Entrance vote](https://groups.google.com/d/topic/php-fig/6kQFX-lhuk4/discussion)\n* [Review Period Initiation](https://groups.google.com/d/topic/php-fig/sR4oEQC3Gz8/discussion)\n* [Acceptance](https://groups.google.com/d/topic/php-fig/o4ZSu7vJi2w/discussion)\n\n## 7. Relevant Links\n\n* [Inspiration Mailing List Thread][]\n* [Entrance vote][]\n* [Informal poll on package structure][]\n* [Informal poll on naming structure][]\n\n[Inspiration Mailing List Thread]: https://groups.google.com/forum/#!topic/php-fig/-EJOStgxAwY\n[Entrance vote]: https://groups.google.com/d/topic/php-fig/6kQFX-lhuk4/discussion\n[Informal poll on package structure]: https://docs.google.com/forms/d/1fvhYUH6xvPgJ1UW9I-3pMGPUtxkt5_Ph6_x_3qXHIuM/edit#responses\n[Informal poll on naming structure]: https://docs.google.com/forms/d/1Rs6APuwNx4k2VzJbTgieeNvN48kLu7CG8qn6Dd2FhTw/edit#responses\n"
  },
  {
    "path": "accepted/PSR-14-event-dispatcher.md",
    "content": "Event Dispatcher\n================\n\nEvent Dispatching is a common and well-tested mechanism to allow developers to inject logic into an application easily and consistently.\n\nThe goal of this PSR is to establish a common mechanism for event-based extension and collaboration so that libraries and components may be reused more freely between various applications and frameworks.\n\nThe key words \"MUST\", \"MUST NOT\", \"REQUIRED\", \"SHALL\", \"SHALL NOT\", \"SHOULD\", \"SHOULD NOT\", \"RECOMMENDED\", \"MAY\", and \"OPTIONAL\" in this document are to be interpreted as described in [RFC 2119][].\n\n[RFC 2119]: http://tools.ietf.org/html/rfc2119\n\n## Goal\n\nHaving common interfaces for dispatching and handling events allows developers to create libraries that can interact with many frameworks and other libraries in a common fashion.\n\nSome examples:\n\n* A security framework that will prevent saving/accessing data when a user doesn't have permission.\n* A common full page caching system.\n* Libraries that extend other libraries, regardless of what framework they are both integrated into.\n* A logging package to track all actions taken within the application\n\n## Definitions\n\n* **Event** - An Event is a message produced by an *Emitter*.  It may be any arbitrary PHP object.\n* **Listener** - A Listener is any PHP callable that expects to be passed an Event.  Zero or more Listeners may be passed the same Event.  A Listener MAY enqueue some other asynchronous behavior if it so chooses.\n* **Emitter** - An Emitter is any arbitrary code that wishes to dispatch an Event.  This is also known as the \"calling code\".  It is not represented by any particular data structure but refers to the use case.\n* **Dispatcher** - A Dispatcher is a service object that is given an Event object by an Emitter.  The Dispatcher is responsible for ensuring that the Event is passed to all relevant Listeners, but MUST defer determining the responsible listeners to a Listener Provider.\n* **Listener Provider** - A Listener Provider is responsible for determining what Listeners are relevant for a given Event, but MUST NOT call the Listeners itself.  A Listener Provider may specify zero or more relevant Listeners.\n\n## Events\n\nEvents are objects that act as the unit of communication between an Emitter and appropriate Listeners.\n\nEvent objects MAY be mutable should the use case call for Listeners providing information back to the Emitter.  However, if no such bidirectional communication is needed then it is RECOMMENDED that the Event be defined as immutable; i.e., defined such that it lacks mutator methods.\n\nImplementers MUST assume that the same object will be passed to all Listeners.\n\nIt is RECOMMENDED, but NOT REQUIRED, that Event objects support lossless serialization and deserialization; `$event == unserialize(serialize($event))` SHOULD hold true.  Objects MAY leverage PHP’s `Serializable` interface, `__sleep()` or `__wakeup()` magic methods, or similar language functionality if appropriate.\n\n## Stoppable Events\n\nA **Stoppable Event** is a special case of Event that contains additional ways to prevent further Listeners from being called.  It is indicated by implementing the `StoppableEventInterface`.\n\nAn Event that implements `StoppableEventInterface` MUST return `true` from `isPropagationStopped()` when whatever Event it represents has been completed.  It is up to the implementer of the class to determine when that is.  For example, an Event that is asking for a PSR-7 `RequestInterface` object to be matched with a corresponding `ResponseInterface` object could have a `setResponse(ResponseInterface $res)` method for a Listener to call, which causes `isPropagationStopped()` to return `true`.\n\n## Listeners\n\nA Listener may be any PHP callable.  A Listener MUST have one and only one parameter, which is the Event to which it responds.  Listeners SHOULD type hint that parameter as specifically as is relevant for their use case; that is, a Listener MAY type hint against an interface to indicate it is compatible with any Event type that implements that interface, or to a specific implementation of that interface.\n\nA Listener SHOULD have a `void` return, and SHOULD type hint that return explicitly.  A Dispatcher MUST ignore return values from Listeners.\n\nA Listener MAY delegate actions to other code. That includes a Listener being a thin wrapper around an object that runs the actual business logic.\n\nA Listener MAY enqueue information from the Event for later processing by a secondary process, using cron, a queue server, or similar techniques.  It MAY serialize the Event object itself to do so; however, care should be taken that not all Event objects may be safely serializable. A secondary process MUST assume that any changes it makes to an Event object will NOT propagate to other Listeners.\n\n## Dispatcher\n\nA Dispatcher is a service object implementing `EventDispatcherInterface`.  It is responsible for retrieving Listeners from a Listener Provider for the Event dispatched, and invoking each Listener with that Event.\n\nA Dispatcher:\n\n* MUST call Listeners synchronously in the order they are returned from a ListenerProvider.\n* MUST return the same Event object it was passed after it is done invoking Listeners.\n* MUST NOT return to the Emitter until all Listeners have executed.\n\nIf passed a Stoppable Event, a Dispatcher\n\n* MUST call `isPropagationStopped()` on the Event before each Listener has been called.  If that method returns `true` it MUST return the Event to the Emitter immediately and MUST NOT call any further Listeners.  This implies that if an Event is passed to the Dispatcher that always returns `true` from `isPropagationStopped()`, zero listeners will be called.\n\nA Dispatcher SHOULD assume that any Listener returned to it from a Listener Provider is type-safe.  That is, the Dispatcher SHOULD assume that calling `$listener($event)` will not produce a `TypeError`.\n\n### Error handling\n\nAn Exception or Error thrown by a Listener MUST block the execution of any further Listeners.  An Exception or Error thrown by a Listener MUST be allowed to propagate back up to the Emitter.\n\nA Dispatcher MAY catch a thrown object to log it, allow additional action to be taken, etc., but then MUST rethrow the original throwable.\n\n## Listener Provider\n\nA Listener Provider is a service object responsible for determining what Listeners are relevant to and should be called for a given Event.  It may determine both what Listeners are relevant and the order in which to return them by whatever means it chooses.  That MAY include:\n\n* Allowing for some form of registration mechanism so that implementers may assign a Listener to an Event in a fixed order.\n* Deriving a list of applicable Listeners through reflection based on the type and implemented interfaces of the Event.\n* Generating a compiled list of Listeners ahead of time that may be consulted at runtime.\n* Implementing some form of access control so that certain Listeners will only be called if the current user has a certain permission.\n* Extracting some information from an object referenced by the Event, such as an Entity, and calling pre-defined lifecycle methods on that object.\n* Delegating its responsibility to one or more other Listener Providers using some arbitrary logic.\n\nAny combination of the above, or other mechanisms, MAY be used as desired.\n\nListener Providers SHOULD use the class name of an Event to differentiate one event from another.  They MAY also consider any other information on the event as appropriate.\n\nListener Providers MUST treat parent types identically to the Event's own type when determining listener applicability.  In the following case:\n\n```php\nclass A {}\n\nclass B extends A {}\n\n$b = new B();\n\nfunction listener(A $event): void {};\n```\n\nA Listener Provider MUST treat `listener()` as an applicable listener for `$b`, as it is type compatible, unless some other criteria prevents it from doing so.\n\n## Object composition\n\nA Dispatcher SHOULD compose a Listener Provider to determine relevant listeners.  It is RECOMMENDED that a Listener Provider be implemented as a distinct object from the Dispatcher but that is NOT REQUIRED.\n\n## Interfaces\n\n```php\nnamespace Psr\\EventDispatcher;\n\n/**\n * Defines a dispatcher for events.\n */\ninterface EventDispatcherInterface\n{\n    /**\n     * Provide all relevant listeners with an event to process.\n     *\n     * @param object $event\n     *   The object to process.\n     *\n     * @return object\n     *   The Event that was passed, now modified by listeners.\n     */\n    public function dispatch(object $event);\n}\n```\n\n```php\nnamespace Psr\\EventDispatcher;\n\n/**\n * Mapper from an event to the listeners that are applicable to that event.\n */\ninterface ListenerProviderInterface\n{\n    /**\n     * @param object $event\n     *   An event for which to return the relevant listeners.\n     * @return iterable<callable>\n     *   An iterable (array, iterator, or generator) of callables.  Each\n     *   callable MUST be type-compatible with $event.\n     */\n    public function getListenersForEvent(object $event): iterable;\n}\n```\n\n```php\nnamespace Psr\\EventDispatcher;\n\n/**\n * An Event whose processing may be interrupted when the event has been handled.\n *\n * A Dispatcher implementation MUST check to determine if an Event\n * is marked as stopped after each listener is called.  If it is then it should\n * return immediately without calling any further Listeners.\n */\ninterface StoppableEventInterface\n{\n    /**\n     * Is propagation stopped?\n     *\n     * This will typically only be used by the Dispatcher to determine if the\n     * previous listener halted propagation.\n     *\n     * @return bool\n     *   True if the Event is complete and no further listeners should be called.\n     *   False to continue calling listeners.\n     */\n    public function isPropagationStopped(): bool;\n}\n```\n"
  },
  {
    "path": "accepted/PSR-15-request-handlers-meta.md",
    "content": "HTTP Server Request Handlers Meta Document\n==========================================\n\n## 1. Summary\n\nThe purpose of this PSR is to define formal interfaces for HTTP server request\nhandlers (\"request handlers\") and HTTP server request middleware (\"middleware\")\nthat are compatible with HTTP messages as defined in [PSR-7][psr7] or subsequent\nreplacement PSRs.\n\n_Note: All references to \"request handlers\" and \"middleware\" are specific to\n**server request** processing._\n\n[psr7]: https://www.php-fig.org/psr/psr-7/\n\n## 2. Why Bother?\n\nThe HTTP messages specification does not contain any reference to request\nhandlers or middleware.\n\nRequest handlers are a fundamental part of any web application. The handler is\nthe component that receives a request and produces a response. Nearly all code\nthat works with HTTP messages will have some kind of request handler.\n\n[Middleware][middleware] has existed for many years in the PHP ecosystem. The\ngeneral concept of reusable middleware was popularized by [StackPHP][stackphp].\nSince the release of HTTP messages as a PSR, many frameworks have adopted\nmiddleware that use HTTP message interfaces.\n\nAgreeing on formal request handler and middleware interfaces eliminates several\nproblems and has a number of benefits:\n\n* Provides a formal standard for developers to commit to.\n* Enables any middleware component to run in any compatible framework.\n* Eliminates duplication of similar interfaces defined by various frameworks.\n* Avoids minor discrepancies in method signatures.\n\n[middleware]: https://en.wikipedia.org/wiki/Middleware\n[stackphp]: http://stackphp.com/\n\n## 3. Scope\n\n### 3.1 Goals\n\n* Create a request handler interface that uses HTTP messages.\n* Create a middleware interface that uses HTTP messages.\n* Implement request handler and middleware signatures that are based on\n  best practices.\n* Ensure that request handlers and middleware will be compatible with any\n  implementation of HTTP messages.\n\n### 3.2 Non-Goals\n\n* Attempting to define the mechanism by which HTTP responses are created.\n* Attempting to define interfaces for client/asynchronous middleware.\n* Attempting to define how middleware is dispatched.\n\n## 4. Request Handler Approaches\n\nThere are many approaches to request handlers that use HTTP messages. However,\nthe general process is the same in all of them:\n\nGiven an HTTP request, produce an HTTP response for that request.\n\nThe internal requirements of that process will vary from framework to framework\nand application to application. This proposal makes no effort to determine what\nthat process should be.\n\n## 5. Middleware Approaches\n\nThere are currently two common approaches to middleware that use HTTP messages.\n\n### 5.1 Double Pass\n\nThe signature used by most middleware implementations has been mostly the same\nand is based on [Express middleware][express], which is defined as:\n\n```\nfn(request, response, next): response\n```\n\n[express]: http://expressjs.com/en/guide/writing-middleware.html\n\nBased on the middleware implementations already used by frameworks that have\nadopted this signature, the following commonalities are observed:\n\n* The middleware is defined as a [callable][php-callable].\n* The middleware is passed 3 arguments during invocation:\n  1. A `ServerRequestInterface` implementation.\n  2. A `ResponseInterface` implementation.\n  3. A `callable` that receives the request and response to delegate to the next middleware.\n\n[php-callable]: http://php.net/manual/language.types.callable.php\n\nA significant number of projects provide and/or use exactly the same interface.\nThis approach is often referred to as \"double pass\" in reference to both the\nrequest and response being passed to the middleware.\n\n#### 5.1.1 Projects Using Double Pass\n\n* [mindplay/middleman v1](https://github.com/mindplay-dk/middleman/blob/1.0.0/src/MiddlewareInterface.php#L24)\n* [relay/relay v1](https://github.com/relayphp/Relay.Relay/blob/1.0.0/src/MiddlewareInterface.php#L24)\n* [slim/slim v3](https://github.com/slimphp/Slim/blob/3.4.0/Slim/MiddlewareAwareTrait.php#L66-L75)\n* [zendframework/zend-stratigility v1](https://github.com/zendframework/zend-stratigility/blob/1.0.0/src/MiddlewarePipe.php#L69-L79)\n\n#### 5.1.2 Middleware Implementing Double Pass\n\n* [bitexpert/adroit](https://github.com/bitExpert/adroit)\n* [akrabat/rka-ip-address-middleware](https://github.com/akrabat/rka-ip-address-middleware)\n* [akrabat/rka-scheme-and-host-detection-middleware](https://github.com/akrabat/rka-scheme-and-host-detection-middleware)\n* [bear/middleware](https://github.com/bearsunday/BEAR.Middleware)\n* [los/api-problem](https://github.com/Lansoweb/api-problem)\n* [los/los-rate-limit](https://github.com/Lansoweb/LosRateLimit)\n* [monii/monii-action-handler-psr7-middleware](https://github.com/monii/monii-action-handler-psr7-middleware)\n* [monii/monii-nikic-fast-route-psr7-middleware](https://github.com/monii/monii-nikic-fast-route-psr7-middleware)\n* [monii/monii-response-assertion-psr7-middleware](https://github.com/monii/monii-response-assertion-psr7-middleware)\n* [mtymek/blast-base-url](https://github.com/mtymek/blast-base-url)\n* [ocramius/psr7-session](https://github.com/Ocramius/PSR7Session)\n* [oscarotero/psr7-middlewares](https://github.com/oscarotero/psr7-middlewares)\n* [php-middleware/block-robots](https://github.com/php-middleware/block-robots)\n* [php-middleware/http-authentication](https://github.com/php-middleware/http-authentication)\n* [php-middleware/log-http-messages](https://github.com/php-middleware/log-http-messages)\n* [php-middleware/maintenance](https://github.com/php-middleware/maintenance)\n* [php-middleware/phpdebugbar](https://github.com/php-middleware/phpdebugbar)\n* [php-middleware/request-id](https://github.com/php-middleware/request-id)\n* [relay/middleware](https://github.com/relayphp/Relay.Middleware)\n\nThe primary downside of this interface is that the while the interface itself is\na callable, there is currently no way to strictly type a closure.\n\n### 5.2 Single Pass (Lambda)\n\nThe other approach to middleware is much closer to [StackPHP][stackphp] style\nand is defined as:\n\n```\nfn(request, next): response\n```\n\nMiddleware taking this approach generally has the following commonalities:\n\n* The middleware is defined with a specific interface with a method that takes\n  the request for processing.\n* The middleware is passed 2 arguments during invocation:\n  1. An HTTP request message.\n  2. A request handler to which the middleware can delegate the responsibility\n     of producing an HTTP response message.\n\nIn this form, middleware has no access to a response until one is generated by\nthe request handler. Middleware can then modify the response before returning it.\n\nThis approach is often referred to as \"single pass\" or \"lambda\" in reference to\nonly the request being passed to the middleware.\n\n#### 5.2.1 Projects Using Single Pass\n\nThere are fewer examples of this approach within projects using HTTP messages,\nwith one notable exception.\n\n[Guzzle middleware][guzzle-middleware] is focused on outgoing (client) requests\nand uses this signature:\n\n```php\nfunction (RequestInterface $request, array $options): ResponseInterface\n```\n\n#### 5.2.2 Additional Projects Using Single Pass\n\nThere are also significant projects that predate HTTP messages using this approach.\n\n[StackPHP][stackphp] is based on [Symfony HttpKernel][httpkernel] and supports\nmiddleware with this signature:\n\n```php\nfunction handle(Request $request, $type, $catch): Response\n```\n\n_Note: While Stack has multiple arguments, a response object is not included._\n\n[Laravel middleware][laravel-middleware] uses Symfony components and supports\nmiddleware with this signature:\n\n```php\nfunction handle(Request $request, callable $next): Response\n```\n\n[guzzle-middleware]: http://docs.guzzlephp.org/en/latest/handlers-and-middleware.html\n[httpkernel]: https://symfony.com/doc/2.0/components/http_kernel/introduction.html\n[laravel-middleware]: https://laravel.com/docs/master/middleware\n\n### 5.3 Comparison of Approaches\n\nThe single pass approach to middleware has been well established in the PHP\ncommunity for many years. This is most evident with the large number of packages\nthat are based around StackPHP.\n\nThe double pass approach is much newer but has been almost universally used by\nearly adopters of HTTP messages (PSR-7).\n\n### 5.4 Chosen Approach\n\nDespite the nearly universal adoption of the double-pass approach, there are\nsignificant issues regarding implementation.\n\nThe most severe is that passing an empty response has no guarantees that the\nresponse is in a usable state. This is further exacerbated by the fact that a\nmiddleware may modify the response before passing it for further processing.\n\nFurther compounding the problem is that there is no way to ensure that the\nresponse body has not been written to, which can lead to incomplete output or\nerror responses being sent with cache headers attached. It is also possible\nto end up with [corrupted body content][rob-allen-filtering] when writing over\nexisting body content if the new content is shorter than the original. The most\neffective way to resolve these issues is to always provide a fresh stream when\nmodifying the body of a message.\n\n[rob-allen-filtering]: https://akrabat.com/filtering-the-psr-7-body-in-middleware/\n\nSome have argued that passing the response helps ensure dependency inversion.\nWhile it is true that it helps avoid depending on a specific implementation of\nHTTP messages, the problem can also be resolved by injecting factories into the\nmiddleware to create HTTP message objects, or by injecting empty message instances.\nWith the creation of HTTP Factories in [PSR-17][psr17], a standard approach to\nhandling dependency inversion is possible.\n\n[psr17]: https://github.com/php-fig/fig-standards/blob/master/proposed/http-factory/http-factory-meta.md\n\nA more subjective, but also important, concern is that existing double-pass\nmiddleware typically uses the `callable` type hint to refer to middleware.\nThis makes strict typing impossible, as there is no assurance that the `callable`\nbeing passed implements a middleware signature, which reduces runtime safety.\n\n**Due to these significant issues, the lambda approach has been chosen for this proposal.**\n\n## 6. Design Decisions\n\n### 6.1 Request Handler Design\n\nThe `RequestHandlerInterface` defines a single method that accepts a request and\nMUST return a response. The request handler MAY delegate to another handler.\n\n#### Why is a server request required?\n\nTo make it clear that the request handler can only be used in a server side context.\nIn an client side context, a [promise][promises] would likely be returned instead\nof a response.\n\n[promises]: https://promisesaplus.com/\n\n#### Why the term \"handler\"?\n\nThe term \"handler\" means something designated to manage or control. In terms of\nrequest processing, a request handler is the point where the request must be\nacted upon to create a response.\n\nAs opposed to the term \"delegate\", which was used in a previous version of this\nspecification, the internal behavior of this interface is not specified.\nAs long as the request handler ultimately produces a response, it is valid.\n\n#### Why doesn't request handler use `__invoke`?\n\nUsing `__invoke` is less transparent than using a named method. It also makes\nit easier to call the request handler when it is assigned to a class variable,\nwithout using `call_user_func` or other less common syntax.\n\n_See [PHP-FIG discussion of FrameInterface][] for\n additional information._\n\n### 6.2 Middleware Design\n\nThe `MiddlewareInterface` defines a single method that accepts an HTTP request\nand a request handler and must return a response. The middleware may:\n\n- Evolve the request before passing it to the request handler.\n- Evolve the response received from the request handler before returning it.\n- Create and return a response without passing the request to the request handler,\n  thereby handling the request itself.\n\nWhen delegating from one middleware to another in a sequence, one approach for\ndispatching systems is to use an intermediary request handler composing the\nmiddleware sequence as a way to link middleware together. The final or innermost\nmiddleware will act as a gateway to application code and generate a response\nfrom its results; alternately, the middleware MAY delegate this responsibility\nto a dedicated request handler.\n\n#### Why doesn't middleware use `__invoke`?\n\nDoing so would conflict with existing middleware that implements the double-pass\napproach and may want to implement the middleware interface for purposes of\nforward compatibility with this specification.\n\n#### Why the name `process()`?\n\nWe reviewed a number of existing monolithic and middleware frameworks to\ndetermine what method(s) each defined for processing incoming requests. We found\nthe following were commonly used:\n\n- `__invoke` (within middleware systems, such as Slim, Expressive, Relay, etc.)\n- `handle` (in particular, software derived from Symfony's [HttpKernel][HttpKernel])\n- `dispatch` (Zend Framework's [DispatchableInterface][DispatchableInterface])\n\n[HttpKernel]: https://symfony.com/doc/current/components/http_kernel.html\n[DispatchableInterface]: https://github.com/zendframework/zend-stdlib/blob/980ce463c29c1a66c33e0eb67961bba895d0e19e/src/DispatchableInterface.php\n\nWe chose to allow a forward-compatible approach for such classes to repurpose\nthemselves as middleware (or middleware compatible with this specification),\nand thus needed to choose a name not in common usage. As such, we chose\n`process`, to indicate _processing_ a request.\n\n#### Why is a server request required?\n\nTo make it clear that the middleware can only be used in a synchronous, server\nside context.\n\nWhile not all middleware will need to use the additional methods defined by the\nserver request interface, outbound requests are typically processed asynchronously\nand would typically return a [promise][promises] of a response. (This is primarily\ndue to the fact that multiple requests can be made in parallel and processed as\nthey are returned.) It is outside the scope of this proposal to address the needs\nof asynchronous request/response life cycles.\n\nAttempting to define client middleware would be premature at this point. Any future\nproposal that is focused on client side request processing should have the opportunity\nto define a standard that is specific to the nature of asynchronous middleware.\n\n_See [PHP-FIG discussion about client vs server side middleware][] for additional information._\n\n#### What is the role of the request handler?\n\nMiddleware has the following roles:\n\n- Producing a response on its own. If specific request conditions are met, the\n  middleware can produce and return a response.\n\n- Returning the result of the request handler. In cases where the middleware\n  cannot produce its own response, it can delegate to the request handler to\n  produce one; sometimes this may involve providing a transformed request (e.g.,\n  to inject a request attribute, or the results of parsing the request body).\n\n- Manipulating and returning the response produced by the request handler. In\n  some cases, the middleware may be interested in manipulating the response\n  the request handler returns (e.g., to gzip the response body, to add CORS\n  headers, etc.). In such cases, the middleware will capture the response\n  returned by the request handler, and return a transformed response on\n  completion.\n\nIn these latter two cases, the middleware may have code such as the following:\n\n```php\n// Straight delegation:\nreturn $handler->handle($request);\n\n// Capturing the response to manipulate:\n$response = $handler->handle($request);\n```\n\nHow the handler acts is entirely up to the developer, so long as it produces a\nresponse.\n\nIn one common scenario, the handler implements a _queue_ or a _stack_ of\nmiddleware instances internally. In such cases, calling\n`$handler->handle($request)` will advance the internal pointer, pull the\nmiddleware associated with that pointer, and call it using\n`$middleware->process($request, $this)`. If no more middleware exists, it will\ngenerally either raise an exception or return a canned response.\n\nAnother possibility is for  _routing middleware_ that matches the incoming\nserver request to a specific handler, and then returns the response generated by\nexecuting that handler. If unable to route to a handler, it would instead\nexecute the handler provided to the middleware. (This sort of mechanism can even\nbe used in conjunction with middleware queues and stacks.)\n\n### 6.3 Example Interface Interactions\n\nThe two interfaces, `RequestHandlerInterface` and `MiddlewareInterface`, were\ndesigned to work in conjunction with one another. Middleware gains flexibility\nwhen de-coupled from any over-arching application layer, and instead only\nrelying on the provided request handler to produce a response.\n\nTwo approaches to middleware dispatch systems that the Working Group observed\nand/or implemented are demonstrated below. Additionally, examples of re-usable\nmiddleware are provided to demonstrate how to write middleware that is\nloosely-coupled.\n\nPlease note that these are not suggested as definitive or exclusive approaches\nto defining middleware dispatch systems.\n\n#### Queue-based request handler\n\nIn this approach, a request handler maintains a queue of middleware, and a\nfallback response to return if the queue is exhausted without returning a\nresponse. When executing the first middleware, the queue passes itself as a\nrequest handler to the middleware.\n\n```php\nclass QueueRequestHandler implements RequestHandlerInterface\n{\n    private $middleware = [];\n    private $fallbackHandler;\n    \n    public function __construct(RequestHandlerInterface $fallbackHandler)\n    {\n        $this->fallbackHandler = $fallbackHandler;\n    }\n    \n    public function add(MiddlewareInterface $middleware)\n    {\n        $this->middleware[] = $middleware;\n    }\n    \n    public function handle(ServerRequestInterface $request): ResponseInterface\n    {\n        // Last middleware in the queue has called on the request handler.\n        if (0 === count($this->middleware)) {\n            return $this->fallbackHandler->handle($request);\n        }\n        \n        $middleware = array_shift($this->middleware);\n        return $middleware->process($request, $this);\n    }\n}\n```\n\nAn application bootstrap might then look like this:\n\n```php\n// Fallback handler:\n$fallbackHandler = new NotFoundHandler();\n\n// Create request handler instance:\n$app = new QueueRequestHandler($fallbackHandler);\n\n// Add one or more middleware:\n$app->add(new AuthorizationMiddleware());\n$app->add(new RoutingMiddleware());\n\n// execute it:\n$response = $app->handle(ServerRequestFactory::fromGlobals());\n```\n\nThis system has two request handlers: one that will produce a response if the\nlast middleware delegates to the request handler, and one for dispatching the\nmiddleware layers. (In this example, the `RoutingMiddleware` will likely execute\ncomposed handlers on a successful route match; see more on that below.)\n\nThis approach has the following benefits:\n\n- Middleware does not need to know anything about any other middleware or how it\n  is composed in the application.\n- The `QueueRequestHandler` is agnostic of the PSR-7 implementation in use.\n- Middleware is executed in the order it is added to the application, making the\n  code explicit.\n- Generation of the \"fallback\" response is delegated to the application\n  developer. This allows the developer to determine whether that should be a\n  \"404 Not Found\" condition, a default page, etc.\n\n#### Decoration-based request handler\n\nIn this approach, a request handler implementation decorates both a middleware\ninstance and a fallback request handler to pass to it. The application is built\nfrom the outside-in, passing each request handler \"layer\" to the next outer one.\n\n```php\nclass DecoratingRequestHandler implements RequestHandlerInterface\n{\n    private $middleware;\n    private $nextHandler;\n\n    public function __construct(MiddlewareInterface $middleware, RequestHandlerInterface $nextHandler)\n    {\n        $this->middleware = $middleware;\n        $this->nextHandler = $nextHandler;\n    }\n\n    public function handle(ServerRequestInterface $request): ResponseInterface\n    {\n        return $this->middleware->process($request, $this->nextHandler);\n    }\n}\n\n// Create a response prototype to return if no middleware can produce a response\n// on its own. This could be a 404, 500, or default page.\n$responsePrototype = (new Response())->withStatus(404);\n$innerHandler = new class ($responsePrototype) implements RequestHandlerInterface {\n    private $responsePrototype;\n\n    public function __construct(ResponseInterface $responsePrototype)\n    {\n        $this->responsePrototype = $responsePrototype;\n    }\n\n    public function handle(ServerRequestInterface $request): ResponseInterface\n    {\n        return $this->responsePrototype;\n    }\n};\n\n$layer1 = new DecoratingRequestHandler(new RoutingMiddleware(), $innerHandler);\n$layer2 = new DecoratingRequestHandler(new AuthorizationMiddleware(), $layer1);\n\n$response = $layer2->handle(ServerRequestFactory::fromGlobals());\n```\n\nSimilar to the queue-based middleware, request handlers serve two purposes in\nthis system:\n\n- Producing a fallback response if no other layer does.\n- Dispatching middleware.\n\n#### Reusable Middleware Examples\n\nIn the examples above, we have two middleware composed in each. In order for\nthese to work in either situation, we need to write them such that they interact\nappropriately.\n\nImplementors of middleware striving for maximum interoperability may want to\nconsider the following guidelines:\n\n- Test the request for a required condition. If it does not satisfy that\n  condition, use a composed prototype response or a composed response factory\n  to generate and return a response.\n\n- If pre-conditions are met, delegate creation of the response to the provided\n  request handler, optionally providing a \"new\" request by manipulating the\n  provided request (e.g., `$handler->handle($request->withAttribute('foo',\n  'bar')`).\n\n- Either pass the response returned by the request handler unaltered, or provide\n  a new response by manipulating the one returned (e.g., `return\n  $response->withHeader('X-Foo-Bar', 'baz')`).\n\nThe `AuthorizationMiddleware` is one that will exercise all three of these guidelines:\n\n- If authorization is required, but the request is not authorized, it will use a\n  composed prototype response to produce an \"unauthorized\" response.\n- If authorization is not required, it will delegate the request to the handler\n  without changes.\n- If authorization is required and the request is authorized, it will delegate\n  the request to the handler, and sign the response returned based on the request.\n\n```php\nclass AuthorizationMiddleware implements MiddlewareInterface\n{\n    private $authorizationMap;\n\n    public function __construct(AuthorizationMap $authorizationMap)\n    {\n        $this->authorizationMap = $authorizationMap;\n    }\n\n    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface\n    {\n        if (! $this->authorizationMap->needsAuthorization($request)) {\n            return $handler->handle($request);\n        }\n\n        if (! $this->authorizationMap->isAuthorized($request)) {\n            return $this->authorizationMap->prepareUnauthorizedResponse();\n        }\n\n        $response = $handler->handle($request);\n        return $this->authorizationMap->signResponse($response, $request);\n    }\n}\n```\n\nNote that the middleware is not concerned with how the request handler is\nimplemented; it merely uses it to produce a response when pre-conditions have\nbeen met.\n\nThe `RoutingMiddleware` implementation described below follows a similar\nprocess: it analyzes the request to see if it matches known routes. In this\nparticular implementation, routes map to request handlers, and the middleware\nessentially delegates to them in order to produce a response. However, in the\ncase that no route is matched, it will execute the handler passed to it to\nproduce the response to return.\n\n```php\nclass RoutingMiddleware implements MiddlewareInterface\n{\n    private $router;\n\n    public function __construct(Router $router)\n    {\n        $this->router = $router;\n    }\n\n    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface\n    {\n        $result = $this->router->match($request);\n\n        if ($result->isSuccess()) {\n            return $result->getHandler()->handle($request);\n        }\n\n        return $handler->handle($request);\n    }\n}\n```\n\n## 7. People\n\nThis PSR was produced by a FIG Working Group with the following members:\n\n* Matthew Weier O'Phinney (sponsor), <mweierophinney@gmail.com>\n* Woody Gilk (editor), <woody.gilk@gmail.com>\n* Glenn Eggleton\n* Matthieu Napoli\n* Oscar Otero\n* Korvin Szanto\n* Stefano Torresi\n\nThe working group would also like to acknowledge the contributions of:\n\n* Jason Coward, <jason@opengeek.com>\n* Paul M. Jones, <pmjones88@gmail.com>\n* Rasmus Schultz, <rasmus@mindplay.dk>\n\n## 8. Votes\n\n* [Working Group Formation](https://groups.google.com/d/msg/php-fig/rPFRTa0NODU/tIU9BZciAgAJ)\n* [Review Period Initiation](https://groups.google.com/d/msg/php-fig/mfTrFinTvEM/PiYvU2S6BAAJ)\n* [Acceptance](https://groups.google.com/d/msg/php-fig/bhQmHt39hJE/ZCYrK_O2AQAJ)\n\n## 9. Relevant Links\n\n_**Note:** Order descending chronologically._\n\n* [PHP-FIG mailing list thread][]\n* [The PHP League middleware proposal][]\n* [PHP-FIG discussion of FrameInterface][]\n* [PHP-FIG discussion about client vs server side middleware][]\n\n## 10. Errata\n\n...\n\n[PHP-FIG mailing list thread]: https://groups.google.com/d/msg/php-fig/vTtGxdIuBX8/NXKieN9vDQAJ\n[The PHP League middleware proposal]: https://groups.google.com/d/msg/thephpleague/jyztj-Nz_rw/I4lHVFigAAAJ\n[PHP-FIG discussion of FrameInterface]: https://groups.google.com/d/msg/php-fig/V12AAcT_SxE/aRXmNnIVCwAJ\n[PHP-FIG discussion about client vs server side middleware]: https://groups.google.com/d/topic/php-fig/vBk0BRgDe2s/discussion\n"
  },
  {
    "path": "accepted/PSR-15-request-handlers.md",
    "content": "HTTP Server Request Handlers\n============================\n\nThis document describes common interfaces for HTTP server request handlers\n(\"request handlers\") and HTTP server middleware components (\"middleware\")\nthat use HTTP messages as described by [PSR-7][psr7] or subsequent\nreplacement PSRs.\n\nHTTP request handlers are a fundamental part of any web application. Server-side\ncode receives a request message, processes it, and produces a response message.\nHTTP middleware is a way to move common request and response processing away from\nthe application layer.\n\nThe interfaces described in this document are abstractions for request handlers\nand middleware.\n\n_Note: All references to \"request handlers\" and \"middleware\" are specific to\n**server request** processing._\n\nThe key words \"MUST\", \"MUST NOT\", \"REQUIRED\", \"SHALL\", \"SHALL NOT\", \"SHOULD\",\n\"SHOULD NOT\", \"RECOMMENDED\", \"MAY\", and \"OPTIONAL\" in this document are to be\ninterpreted as described in [RFC 2119][rfc2119].\n\n[psr7]: https://www.php-fig.org/psr/psr-7/\n[rfc2119]: http://tools.ietf.org/html/rfc2119\n\n### References\n\n- [PSR-7][psr7]\n- [RFC 2119][rfc2119]\n\n## 1. Specification\n\n### 1.1 Request Handlers\n\nA request handler is an individual component that processes a request and\nproduces a response, as defined by PSR-7.\n\nA request handler MAY throw an exception if request conditions prevent it from\nproducing a response. The type of exception is not defined.\n\nRequest handlers using this standard MUST implement the following interface:\n\n- `Psr\\Http\\Server\\RequestHandlerInterface`\n\n### 1.2 Middleware\n\nA middleware component is an individual component participating, often together\nwith other middleware components, in the processing of an incoming request and\nthe creation of a resulting response, as defined by PSR-7.\n\nA middleware component MAY create and return a response without delegating to\na request handler, if sufficient conditions are met.\n\nMiddleware using this standard MUST implement the following interface:\n\n- `Psr\\Http\\Server\\MiddlewareInterface`\n\n### 1.3 Generating Responses\n\nIt is RECOMMENDED that any middleware or request handler that generates a response\nwill either compose a prototype of a PSR-7 `ResponseInterface` or a factory capable\nof generating a `ResponseInterface` instance in order to prevent dependence on a\nspecific HTTP message implementation.\n\n### 1.4 Handling Exceptions\n\nIt is RECOMMENDED that any application using middleware includes a component\nthat catches exceptions and converts them into responses. This middleware SHOULD\nbe the first component executed and wrap all further processing to ensure that\na response is always generated.\n\n## 2. Interfaces\n\n### 2.1 Psr\\Http\\Server\\RequestHandlerInterface\n\nThe following interface MUST be implemented by request handlers.\n\n```php\nnamespace Psr\\Http\\Server;\n\nuse Psr\\Http\\Message\\ResponseInterface;\nuse Psr\\Http\\Message\\ServerRequestInterface;\n\n/**\n * Handles a server request and produces a response.\n *\n * An HTTP request handler process an HTTP request in order to produce an\n * HTTP response.\n */\ninterface RequestHandlerInterface\n{\n    /**\n     * Handles a request and produces a response.\n     *\n     * May call other collaborating code to generate the response.\n     */\n    public function handle(ServerRequestInterface $request): ResponseInterface;\n}\n```\n\n### 2.2 Psr\\Http\\Server\\MiddlewareInterface\n\nThe following interface MUST be implemented by compatible middleware components.\n\n```php\nnamespace Psr\\Http\\Server;\n\nuse Psr\\Http\\Message\\ResponseInterface;\nuse Psr\\Http\\Message\\ServerRequestInterface;\n\n/**\n * Participant in processing a server request and response.\n *\n * An HTTP middleware component participates in processing an HTTP message:\n * by acting on the request, generating the response, or forwarding the\n * request to a subsequent middleware and possibly acting on its response.\n */\ninterface MiddlewareInterface\n{\n    /**\n     * Process an incoming server request.\n     *\n     * Processes an incoming server request in order to produce a response.\n     * If unable to produce the response itself, it may delegate to the provided\n     * request handler to do so.\n     */\n    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface;\n}\n```\n"
  },
  {
    "path": "accepted/PSR-16-simple-cache-meta.md",
    "content": "# PSR-16 Meta Document\n\n## 1. Summary\n\nCaching is a common way to improve the performance of any project, and many\nlibraries make use or could make use of it. Interoperability at this level\nmeans libraries can drop their own caching implementations and easily rely\non the one given to them by the framework, or another dedicated cache\nlibrary the user picked.\n\n## 2. Why Bother?\n\nPSR-6 solves this problem already, but in a rather formal and verbose way for\nwhat the most simple use cases need. This simpler approach aims to build a\nstandardized layer of simplicity on top of the existing PSR-6 interfaces.\n\n## 3. Scope\n\n### 3.1 Goals\n\n* A simple interface for cache operations.\n* Basic support for operations on multiple keys for performance (round-trip-time)\n  reasons.\n* Providing an adapter class that turns a PSR-6 implementation into a\n  PSR-Simple-Cache one.\n* It should be possible to expose both caching PSRs from a caching library.\n\n### 3.2 Non-Goals\n\n* Solving all possible edge cases, PSR-6 does this well already.\n\n## 4. Approaches\n\nThe approach chosen here is very barebones by design, as it is to be used\nonly by the most simple cases. It does not have to be implementable by all\npossible cache backends, nor be usable for all usages. It is merely a layer\nof convenience on top of PSR-6.\n\n## 5. People\n\n### 5.1 Editor(s)\n\n* Paul Dragoonis (@dragoonis)\n\n### 5.2 Sponsors\n\n* Jordi Boggiano (@seldaek) - Composer (Coordinator)\n* Fabien Potencier (@fabpot) - Symfony\n\n### 5.3 Contributors\n\nFor their role in the writing the initial version of this cache PSR:\n\n* Evert Pot (@evert)\n* Florin Pățan (@dlsniper)\n\nFor being an early reviewer\n\n* Daniel Messenger (@dannym87)\n\n## 6. Votes\n\n* **Entrance Vote:**  https://groups.google.com/d/topic/php-fig/vyQTKHS6pJ8/discussion\n* **Acceptance Vote:**  https://groups.google.com/d/msg/php-fig/A8e6GvDRGIk/HQBJGEhbDQAJ\n\n## 7. Relevant Links\n\n* [Survey of existing cache implementations][1], by @dragoonis\n\n[1]: https://docs.google.com/spreadsheet/ccc?key=0Ak2JdGialLildEM2UjlOdnA4ekg3R1Bfeng5eGlZc1E#gid=0\n\n## 8. Errata\n\n### 8.1 Throwable\n\nThe 2.0 release of the `psr/simple-cache` package updates `Psr\\SimpleCache\\CacheException` to extend `\\Throwable`.  This is considered a backwards compatible change for implementing libraries as of PHP 7.4.\n\n### 8.2 Type additions\n\nThe 2.0 release of the `psr/simple-cache` package includes scalar parameter types and increases the minimum PHP version to 8.0.  This is considered a backwards compatible change for implementing libraries as PHP 7.2 introduces covariance for parameters.  Any implementation of 1.0 is compatible with 2.0. For calling libraries, however, this reduces the types that they may pass (as previously any parameter that could be cast to string could be accepted) and as such requires incrementing the major version.\n\nThe 3.0 release includes return types.  Return types break backwards compatibility for implementing libraries as PHP does not support return type widening.\n\nImplementing libraries **MAY** add return types to their own packages at their discretion, provided that:\n\n* the return types match those in the 3.0 package.\n* the implementation specifies a minimum PHP version of 8.0.0 or later\n* the implementation depends on `\"psr/simple-cache\": \"^2 || ^3\"` so as to exclude the untyped 1.0 version.\n\nImplementing libraries **MAY** add parameter types to their own package in a new minor release, either at the same time as adding return types or in a subsequent release, provided that:\n\n* the parameter types match or widen those in the 2.0 package\n* the implementation specifies a minimum PHP version of 8.0 if using mixed or union types or later.\n* the implementation depends on `\"psr/simple-cache\": \"^2 || ^3\"` so as to exclude the untyped 1.0 version.\n\nImplementing libraries are encouraged, but not required to transition their packages toward the 3.0 version of the package at their earliest convenience.\n\nCalling libraries are encouraged to ensure they are sending the correct types and to update their requirement to `\"psr/simple-cache\": \"^1 || ^2 || ^3\"` at their earliest convenience.\n"
  },
  {
    "path": "accepted/PSR-16-simple-cache.md",
    "content": "Common Interface for Caching Libraries\n======================================\n\nThis document describes a simple yet extensible interface for a cache item and\na cache driver.\n\nThe key words \"MUST\", \"MUST NOT\", \"REQUIRED\", \"SHALL\", \"SHALL NOT\", \"SHOULD\",\n\"SHOULD NOT\", \"RECOMMENDED\", \"MAY\", and \"OPTIONAL\" in this document are to be\ninterpreted as described in [RFC 2119][].\n\nThe final implementations MAY decorate the objects with more\nfunctionality than the one proposed but they MUST implement the indicated\ninterfaces/functionality first.\n\n[RFC 2119]: http://tools.ietf.org/html/rfc2119\n\n# 1. Specification\n\n## 1.1 Introduction\n\nCaching is a common way to improve the performance of any project, making\ncaching libraries one of the most common features of many frameworks and\nlibraries. Interoperability at this level means libraries can drop their\nown caching implementations and easily rely on the one given to them by the\nframework, or another dedicated cache library.\n\nPSR-6 solves this problem already, but in a rather formal and verbose way for\nwhat the most simple use cases need. This simpler approach aims to build a\nstandardized streamlined interface for common cases. It is independent of\nPSR-6 but has been designed to make compatibility with PSR-6 as straightforward\nas possible.\n\n## 1.2 Definitions\n\nDefinitions for Calling Library, Implementing Library, TTL, Expiration and Key\nare copied from PSR-6 as the same assumptions are true.\n\n*    **Calling Library** - The library or code that actually needs the cache\nservices. This library will utilize caching services that implement this\nstandard's interfaces, but will otherwise have no knowledge of the\nimplementation of those caching services.\n\n*    **Implementing Library** - This library is responsible for implementing\nthis standard in order to provide caching services to any Calling Library. The\nImplementing Library MUST provide a class implementing the Psr\\SimpleCache\\CacheInterface interface.\nImplementing Libraries MUST support at minimum TTL functionality as described\nbelow with whole-second granularity.\n\n*    **TTL** - The Time To Live (TTL) of an item is the amount of time between\nwhen that item is stored and it is considered stale. The TTL is normally defined\nby an integer representing time in seconds, or a DateInterval object.\n\n* **Expiration** - The actual time when an item is set to go stale. This is\n  calculated by adding the TTL to the time when an object is stored.\n\n  An item with a 300 second TTL stored at 1:30:00 will have an expiration of 1:35:00.\n\n  Implementing Libraries MAY expire an item before its requested Expiration Time,\n  but MUST treat an item as expired once its Expiration Time is reached. If a calling\n  library asks for an item to be saved but does not specify an expiration time, or\n  specifies a null expiration time or TTL, an Implementing Library MAY use a configured\n  default duration. If no default duration has been set, the Implementing Library\n  MUST interpret that as a request to cache the item forever, or for as long as the\n  underlying implementation supports.\n\n  If a negative or zero TTL is provided, the item MUST be deleted from the cache\n  if it exists, as it is expired already.\n\n*    **Key** - A string of at least one character that uniquely identifies a\ncached item. Implementing libraries MUST support keys consisting of the\ncharacters `A-Z`, `a-z`, `0-9`, `_`, and `.` in any order in UTF-8 encoding and a\nlength of up to 64 characters. Implementing libraries MAY support additional\ncharacters and encodings or longer lengths, but MUST support at least that\nminimum. Libraries are responsible for their own escaping of key strings\nas appropriate, but MUST be able to return the original unmodified key string.\nThe following characters are reserved for future extensions and MUST NOT be\nsupported by implementing libraries: `{}()/\\@:`\n\n*    **Cache** - An object that implements the `Psr\\SimpleCache\\CacheInterface` interface.\n\n*    **Cache Misses** - A cache miss will return null and therefore detecting\nif one stored `null` is not possible. This is the main deviation from PSR-6's\nassumptions.\n\n## 1.3 Cache\n\nImplementations MAY provide a mechanism for a user to specify a default TTL\nif one is not specified for a specific cache item. If no user-specified default\nis provided implementations MUST default to the maximum legal value allowed by\nthe underlying implementation. If the underlying implementation does not\nsupport TTL, the user-specified TTL MUST be silently ignored.\n\n## 1.4 Data\n\nImplementing libraries MUST support all serializable PHP data types, including:\n\n*    **Strings** - Character strings of arbitrary size in any PHP-compatible encoding.\n*    **Integers** - All integers of any size supported by PHP, up to 64-bit signed.\n*    **Floats** - All signed floating point values.\n*    **Booleans** - True and False.\n*    **Null** - The null value (although it will not be distinguishable from a\ncache miss when reading it back out).\n*    **Arrays** - Indexed, associative and multidimensional arrays of arbitrary depth.\n*    **Objects** - Any object that supports lossless serialization and\ndeserialization such that $o == unserialize(serialize($o)). Objects MAY\nleverage PHP's Serializable interface, `__sleep()` or `__wakeup()` magic methods,\nor similar language functionality if appropriate.\n\nAll data passed into the Implementing Library MUST be returned exactly as\npassed. That includes the variable type. That is, it is an error to return\n(string) 5 if (int) 5 was the value saved. Implementing Libraries MAY use PHP's\nserialize()/unserialize() functions internally but are not required to do so.\nCompatibility with them is simply used as a baseline for acceptable object values.\n\nIf it is not possible to return the exact saved value for any reason, implementing\nlibraries MUST respond with a cache miss rather than corrupted data.\n\n# 2. Interfaces\n\n## 2.1 CacheInterface\n\nThe cache interface defines the most basic operations on a collection of cache-entries, which\nentails basic reading, writing and deleting individual cache items.\n\nIn addition, it has methods for dealing with multiple sets of cache entries such as writing, reading or\ndeleting multiple cache entries at a time. This is useful when you have lots of cache reads/writes\nto perform, and lets you perform your operations in a single call to the cache server cutting down latency\ntimes dramatically.\n\nAn instance of CacheInterface corresponds to a single collection of cache items with a single key namespace,\nand is equivalent to a \"Pool\" in PSR-6. Different CacheInterface instances MAY be backed by the same\ndatastore, but MUST be logically independent.\n\n```php\n<?php\n\nnamespace Psr\\SimpleCache;\n\ninterface CacheInterface\n{\n    /**\n     * Fetches a value from the cache.\n     *\n     * @param string $key     The unique key of this item in the cache.\n     * @param mixed  $default Default value to return if the key does not exist.\n     *\n     * @return mixed The value of the item from the cache, or $default in case of cache miss.\n     *\n     * @throws \\Psr\\SimpleCache\\InvalidArgumentException\n     *   MUST be thrown if the $key string is not a legal value.\n     */\n    public function get($key, $default = null);\n\n    /**\n     * Persists data in the cache, uniquely referenced by a key with an optional expiration TTL time.\n     *\n     * @param string                 $key   The key of the item to store.\n     * @param mixed                  $value The value of the item to store. Must be serializable.\n     * @param null|int|\\DateInterval $ttl   Optional. The TTL value of this item. If no value is sent and\n     *                                      the driver supports TTL then the library may set a default value\n     *                                      for it or let the driver take care of that.\n     *\n     * @return bool True on success and false on failure.\n     *\n     * @throws \\Psr\\SimpleCache\\InvalidArgumentException\n     *   MUST be thrown if the $key string is not a legal value.\n     */\n    public function set($key, $value, $ttl = null);\n\n    /**\n     * Delete an item from the cache by its unique key.\n     *\n     * @param string $key The unique cache key of the item to delete.\n     *\n     * @return bool True if the item was successfully removed. False if there was an error.\n     *\n     * @throws \\Psr\\SimpleCache\\InvalidArgumentException\n     *   MUST be thrown if the $key string is not a legal value.\n     */\n    public function delete($key);\n\n    /**\n     * Wipes clean the entire cache's keys.\n     *\n     * @return bool True on success and false on failure.\n     */\n    public function clear();\n\n    /**\n     * Obtains multiple cache items by their unique keys.\n     *\n     * @param iterable $keys    A list of keys that can obtained in a single operation.\n     * @param mixed    $default Default value to return for keys that do not exist.\n     *\n     * @return iterable A list of key => value pairs. Cache keys that do not exist or are stale will have $default as value.\n     *\n     * @throws \\Psr\\SimpleCache\\InvalidArgumentException\n     *   MUST be thrown if $keys is neither an array nor a Traversable,\n     *   or if any of the $keys are not a legal value.\n     */\n    public function getMultiple($keys, $default = null);\n\n    /**\n     * Persists a set of key => value pairs in the cache, with an optional TTL.\n     *\n     * @param iterable               $values A list of key => value pairs for a multiple-set operation.\n     * @param null|int|\\DateInterval $ttl    Optional. The TTL value of this item. If no value is sent and\n     *                                       the driver supports TTL then the library may set a default value\n     *                                       for it or let the driver take care of that.\n     *\n     * @return bool True on success and false on failure.\n     *\n     * @throws \\Psr\\SimpleCache\\InvalidArgumentException\n     *   MUST be thrown if $values is neither an array nor a Traversable,\n     *   or if any of the $values are not a legal value.\n     */\n    public function setMultiple($values, $ttl = null);\n\n    /**\n     * Deletes multiple cache items in a single operation.\n     *\n     * @param iterable $keys A list of string-based keys to be deleted.\n     *\n     * @return bool True if the items were successfully removed. False if there was an error.\n     *\n     * @throws \\Psr\\SimpleCache\\InvalidArgumentException\n     *   MUST be thrown if $keys is neither an array nor a Traversable,\n     *   or if any of the $keys are not a legal value.\n     */\n    public function deleteMultiple($keys);\n\n    /**\n     * Determines whether an item is present in the cache.\n     *\n     * NOTE: It is recommended that has() is only to be used for cache warming type purposes\n     * and not to be used within your live applications operations for get/set, as this method\n     * is subject to a race condition where your has() will return true and immediately after,\n     * another script can remove it, making the state of your app out of date.\n     *\n     * @param string $key The cache item key.\n     *\n     * @return bool\n     *\n     * @throws \\Psr\\SimpleCache\\InvalidArgumentException\n     *   MUST be thrown if the $key string is not a legal value.\n     */\n    public function has($key);\n}\n```\n\n## 2.2 CacheException\n\n```php\n\n<?php\n\nnamespace Psr\\SimpleCache;\n\n/**\n * Interface used for all types of exceptions thrown by the implementing library.\n */\ninterface CacheException\n{\n}\n```\n\n## 2.3 InvalidArgumentException\n\n```php\n<?php\n\nnamespace Psr\\SimpleCache;\n\n/**\n * Exception interface for invalid cache arguments.\n *\n * When an invalid argument is passed, it must throw an exception which implements\n * this interface.\n */\ninterface InvalidArgumentException extends CacheException\n{\n}\n```\n"
  },
  {
    "path": "accepted/PSR-17-http-factory-meta.md",
    "content": "HTTP Factories Meta\n===================\n\n## 1. Summary\n\nThe purpose of this PSR is to provide factory interfaces that define methods to\ncreate [PSR-7][psr7] objects.\n\n[psr7]: https://www.php-fig.org/psr/psr-7/\n\n## 2. Why Bother?\n\nThe current specification for PSR-7 allows for most objects to be modified by\ncreating immutable copies. However, there are two notable exceptions:\n\n- `StreamInterface` is a mutable object based on a resource that only allows\n  the resource to be written to when the resource is writable.\n- `UploadedFileInterface` is a read-only object based on a resource that offers\n  no modification capabilities.\n\nThe former is a significant pain point for PSR-7 middleware, as it can leave\nthe response in an incomplete state. If the stream attached to the response body\nis not seekable or not writable, there is no way to recover from an error\ncondition in which the body has already been written to.\n\nThis scenario can be avoided by providing a factory to create new streams. Due to\nthe lack of a formal standard for HTTP object factories, a developer must rely on\na specific vendor implementation in order to create these objects.\n\nAnother pain point is when writing re-usable middleware or request handlers. In\nsuch cases, package authors may need to create and return a response. However,\ncreating discrete instances then ties the package to a specific PSR-7\nimplementation. If these packages rely on the request factory interface instead,\nthey can remain agnostic of the PSR-7 implementation.\n\nCreating a formal standard for factories will allow developers to avoid\ndependencies on specific implementations while having the ability to create new\nobjects when necessary.\n\n## 3. Scope\n\n### 3.1 Goals\n\n- Provide a set of interfaces that define methods to create PSR-7 compatible objects.\n\n### 3.2 Non-Goals\n\n- Provide a specific implementation of PSR-7 factories.\n\n## 4. Approaches\n\n### 4.1 Chosen Approach\n\nThe factory method definition has been chosen based on whether or not the object\ncan be modified after instantiation. For interfaces that cannot be modified, all\nof the object properties must be defined at the time of instantiation.\n\nIn the case of `UriInterface` a complete URI may be passed for convenience.\n\nThe method names used will not conflict. This allows for a single class to\nimplement multiple interfaces when appropriate.\n\n### 4.2 Existing Implementations\n\nAll of the current implementations of PSR-7 have defined their own requirements.\nIn most cases, the required parameters are the same or less strict than the proposed\nfactory methods.\n\n#### 4.2.1 Diactoros\n\n[Diactoros][zend-diactoros] was one of the first HTTP Messages implementations for\nserver usage, and was developed parallel to the PSR-7 specification.\n\n- [`Request`][diactoros-request] No required parameters, method and URI default to `null`.\n- [`Response`][diactoros-response] No required parameters, status code defaults to `200`.\n- [`ServerRequest`][diactoros-server-request] No required parameters. Contains a separate\n  [`ServerRequestFactory`][diactoros-server-request-factory] for creating requests from globals.\n- [`Stream`][diactoros-stream] Requires `string|resource $stream` for the body.\n- [`UploadedFile`][diactoros-uploaded-file] Requires `string|resource $streamOrFile`, `int $size`,\n  `int $errorStatus`. Error status must be a PHP upload constant.\n- [`Uri`][diactoros-uri] No required parameters, `string $uri` is empty by default.\n\n[zend-diactoros]: https://docs.zendframework.com/zend-diactoros/\n[diactoros-request]: https://github.com/zendframework/zend-diactoros/blob/b4e7758556c97b5bb9a5260d898e9788ee800538/src/Request.php#L33\n[diactoros-response]: https://github.com/zendframework/zend-diactoros/blob/b4e7758556c97b5bb9a5260d898e9788ee800538/src/Response.php#L114\n[diactoros-server-request]: https://github.com/zendframework/zend-diactoros/blob/b4e7758556c97b5bb9a5260d898e9788ee800538/src/ServerRequest.php#L78-L89\n[diactoros-server-request-factory]: https://github.com/zendframework/zend-diactoros/blob/b4e7758556c97b5bb9a5260d898e9788ee800538/src/ServerRequestFactory.php#L52-L58\n[diactoros-stream]: https://github.com/zendframework/zend-diactoros/blob/b4e7758556c97b5bb9a5260d898e9788ee800538/src/Stream.php#L36\n[diactoros-uploaded-file]: https://github.com/zendframework/zend-diactoros/blob/b4e7758556c97b5bb9a5260d898e9788ee800538/src/UploadedFile.php#L62\n[diactoros-uri]: https://github.com/zendframework/zend-diactoros/blob/b4e7758556c97b5bb9a5260d898e9788ee800538/src/Uri.php#L94\n\nOverall this approach is quite similar to the proposed factories. In some cases,\nmore options are given by Diactoros which are not required for a valid object.\nThe proposed uploaded file factory allows for size and error status to be optional.\n\n#### 4.2.2 Guzzle\n\n[Guzzle][guzzle] is an HTTP Messages implementation that focuses on client usage.\n\n- [`Request`][guzzle-request] Requires both `string $method` and `string|UriInterface $uri`.\n- [`Response`][guzzle-response] No required parameters, status code defaults to `200`.\n- [`Stream`][guzzle-stream] Requires `resource $stream` for the body.\n- [`Uri`][guzzle-uri] No required parameters, `string $uri` is empty by default.\n\n_Being geared towards client usage, Guzzle does not contain a `ServerRequest` or\n`UploadedFile` implementation._\n\n[guzzle]: https://github.com/guzzle/psr7\n[guzzle-request]: https://github.com/guzzle/psr7/blob/58828615f7bb87013ce6365e9b1baa08580c7fc8/src/Request.php#L32-L38\n[guzzle-response]: https://github.com/guzzle/psr7/blob/58828615f7bb87013ce6365e9b1baa08580c7fc8/src/Response.php#L88-L94\n[guzzle-stream]: https://github.com/guzzle/psr7/blob/58828615f7bb87013ce6365e9b1baa08580c7fc8/src/Stream.php#L51\n[guzzle-uri]: https://github.com/guzzle/psr7/blob/58828615f7bb87013ce6365e9b1baa08580c7fc8/src/Uri.php#L48\n\nOverall this approach is also quite similar to the proposed factories. One notable\ndifference is that Guzzle requires streams to be constructed with a resource and\ndoes not allow a string. However, it does contain a helper function [`stream_for`][guzzle-stream-for]\nthat will create a stream from a string of content and a function [`try_fopen`][guzzle-try-fopen]\nthat will create a resource from a file path.\n\n[guzzle-stream-for]: https://github.com/guzzle/psr7/blob/58828615f7bb87013ce6365e9b1baa08580c7fc8/src/functions.php#L78\n[guzzle-try-fopen]: https://github.com/guzzle/psr7/blob/58828615f7bb87013ce6365e9b1baa08580c7fc8/src/functions.php#L295\n\n#### 4.2.3 Slim\n\n[Slim][slim] is a micro-framework that makes use of HTTP Messages from version\n3.0 forward.\n\n- [`Request`][slim-request] Requires `string $method`, `UriInterface $uri`,\n  `HeadersInterface $headers`, `array $cookies`, `array $serverParams`, and\n  `StreamInterface $body`. Contains a factory method `createFromEnvironment(Environment $environment)`\n  that is framework specific but analogous to the proposed `createServerRequestFromArray`.\n- [`Response`][slim-response] No required parameters, status code defaults to `200`.\n- [`Stream`][slim-stream] Requires `resource $stream` for the body.\n- [`UploadedFile`][slim-uploaded-file] Requires `string $file` for the source file.\n  Contains a factory method `parseUploadedFiles(array $uploadedFiles)` for creating\n  an array of `UploadedFile` instances from `$_FILES` or similar format. Also contains\n  a factory method `createFromEnvironment(Environment $env)` that is framework specific\n  and makes use of `parseUploadedFiles`.\n- [`Uri`][slim-uri] Requires `string $scheme` and `string $host`. Contains a factory\n  method `createFromString($uri)` that can be used to create a `Uri` from a string.\n\n_Being geared towards server usage only, Slim does not contain an implementation\nof `Request`. The implementation listed above is an implementation of `ServerRequest`._\n\n[slim]: https://www.slimframework.com/\n[slim-request]: https://github.com/slimphp/Slim/blob/30cfe3c07dac28ec1129c0577e64b90ba11a54c4/Slim/Http/Request.php#L170-L178\n[slim-response]: https://github.com/slimphp/Slim/blob/30cfe3c07dac28ec1129c0577e64b90ba11a54c4/Slim/Http/Response.php#L123\n[slim-stream]: https://github.com/slimphp/Slim/blob/30cfe3c07dac28ec1129c0577e64b90ba11a54c4/Slim/Http/Stream.php#L96\n[slim-uploaded-file]: https://github.com/slimphp/Slim/blob/30cfe3c07dac28ec1129c0577e64b90ba11a54c4/Slim/Http/UploadedFile.php#L151\n[slim-uri]: https://github.com/slimphp/Slim/blob/30cfe3c07dac28ec1129c0577e64b90ba11a54c4/Slim/Http/Uri.php#L112-L121\n\nOf the compared approaches, Slim is most different from the proposed factories.\nMost notably, the `Request` implementation contains requirements specific\nto the framework that are not defined in HTTP Messages specification. The factory\nmethods that are included are generally similar with the proposed factories.\n\n### 4.3 Potential Issues\n\nThe most difficult task in establishing this standard will be defining the\nmethod signatures for the interfaces. As there is no clear declaration in PSR-7\nas to what values are explicitly required, the properties that are read-only\nmust be inferred based on whether the interfaces have methods to copy-and-modify\nthe object.\n\n## 5. Design Decisions\n\n### 5.1 Why PHP 7?\n\nWhile PSR-7 does not target PHP 7, the authors of this specification note that,\nat the time of writing (April 2018), PHP 5.6 stopped receiving bugfixes 15\nmonths ago, and will no longer receive security patches in 8 months; PHP 7.0\nitself will stop receiving security fixes in 7 months (see the [PHP supported\nversions document][php-support] for current support details). Since\nspecifications are meant to be long-term, the authors feel the specification\nshould target versions that will be supported for the foreseeable future; PHP 5\nwill not. As such, from a security standpoint, targeting anything under PHP 7 is\na disservice to users, as doing so would be tacit approval of usage of\nunsupported PHP versions.\n\nAdditionally, and equally importantly, PHP 7 gives us the ability to provide\nreturn type hints to interfaces we define. This guarantees a strong,\npredicatable contract for end users, as they can assume that the values returned\nby implementations will be exactly what they expect.\n\n[php-support]: http://php.net/supported-versions.php\n\n### 5.2 Why multiple interfaces?\n\nEach proposed interface is (primarily) responsible for producing one PSR-7 type.\nThis allows consumers to typehint on exactly what they need: if they need a\nresponse, they typehint on `ResponseFactoryInterface`; if they need a URI, they\ntypehint on `UriFactoryInterface`. In this way, users can be granular about what\nthey need.\n\nDoing so also allows application developers to provide anonymous implementations\nbased on the PSR-7 implementation they are using, producing only the instances\nthey need for the specific context. This reduces boilerplate; developers do not\nneed to write stubs for unused methods.\n\n### 5.3 Why does the $reasonPhrase argument to the ResponseFactoryInterface exist?\n\n`ResponseFactoryInterface::createResponse()` includes an optional string\nargument, `$reasonPhrase`. In the PSR-7 specification, you can only provide a\nreason phrase at the same time you provide a status code, as the two are related\npieces of data. The authors of this specification have chosen to mimic the PSR-7\n`ResponseInterface::withStatus()` signature to ensure both sets of data may be\npresent in the response created.\n\n### 5.4 Why does the $serverParams argument to the ServerRequestFactoryInterface exist?\n\n`ServerRequestFactoryInterface::createServerRequest()` includes an optional\n`$serverParams` array argument. The reason this is provided is to ensure that an\ninstance can be created with the server params populated. Of the data accessible\nvia the `ServerRequestInterface`, the only data that does not have a mutator\nmethod is the one corresponding to the server params. As such, this data MUST be\nprovided at initial creation. For this reason, it exists as an argument to the\nfactory method.\n\n### 5.5 Why is there no factory for creating a ServerRequestInterface from superglobals?\n\nThe primary use case of `ServerRequestFactoryInterface` is for creating a new\n`ServerRequestInterface` instance from known data. Any solution around\nmarshaling data from superglobals assumes that:\n\n- superglobals are present\n- superglobals follow a specific structure\n\nThese two assumptions are not always true. When using asynchronous systems such\nas [Swoole][swoole], [ReactPHP][reactphp], and others:\n\n- will not populate standard superglobals such as `$_GET`, `$_POST`, `$_COOKIE`,\n  and `$_FILES`\n- will not populate `$_SERVER` with the same elements as a standard SAPI (such as\n  mod_php, mod-cgi, and mod-fpm)\n\nMoreover, different standard SAPIs provide different information to `$_SERVER`\nand access to request headers, requiring different approaches for initial\npopulation of the request.\n\nAs such, designing an interface for population of an instance from superglobals\nis out of scope of this specification, and should largely be\nimplementation-specfic.\n\n[swoole]: https://www.swoole.co.uk/\n[reactphp]: https://reactphp.org/\n\n### 5.6 Why does RequestFactoryInterface::createRequest allow a string URI?\n\nThe primary use case of `RequestFactoryInterface` is to create a request, and\nthe only required values for any request are the request method and a URI. While\n`RequestFactoryInterface::createRequest()` can accept a `UriInterface` instance,\nit also allows a string.\n\nThe rationale is two-fold. First, the majority use case is to create a request\ninstance; creation of the URI instance is secondary. Requiring a `UriInterface`\nmeans users would either need to also have access to a `UriFactoryInterface`, or\nthe `RequestFactoryInterface` would have a hard requirement on a\n`UriFactoryInterface`. The first complicates usage for consumers of the factory,\nthe second complicates usage for either developers of the factory, or those\ncreating the factory instance.\n\nSecond, `UriFactoryInterface` provides exactly one way to create a\n`UriInterface` instance, and that is from a string URI. If creation of the URI\nis based on a string, there's no reason for the `RequestFactoryInterface` not to\nallow the same semantics. Additionally, every PSR-7 implementation surveyed at\nthe time this proposal was developed allowed a string URI when creating a\n`RequestInterface` instance, as the value was then passed to whatever\n`UriInterface` implementation they provided. As such, accepting a string is\nexpedient and follows existing semantics.\n\n## 6. People\n\nThis PSR was produced by a FIG Working Group with the following members:\n\n- Woody Gilk (editor), <woody.gilk@gmail.com>\n- Matthew Weier O'Phinney (sponsor), <mweierophinney@gmail.com>\n- Stefano Torresi\n- Matthieu Napoli\n- Korvin Szanto\n- Glenn Eggleton\n- Oscar Otero\n- Tobias Nyholm\n\nThe working group would also like to acknowledge the contributions of:\n\n- Paul M. Jones, <pmjones88@gmail.com>\n- Rasmus Schultz, <rasmus@mindplay.dk>\n- Roman Tsjupa, <draconyster@gmail.com>\n\n## 7. Votes\n\n- [Entrance Vote](https://groups.google.com/forum/#!topic/php-fig/6rZPZ8VglIM)\n- [Working Group Formation](https://groups.google.com/d/msg/php-fig/A5mZYTn5Jm8/j0FN6eZtBAAJ)\n- [Review Period Initiation](https://groups.google.com/d/msg/php-fig/OpUnkrnFhe0/y2dT7CakAQAJ)\n- [Acceptance Vote](https://groups.google.com/d/msg/php-fig/M8PapGXXE1E/uBq2Dq-ZAwAJ)\n\n## 8. Relevant Links\n\n_**Note:** Order descending chronologically._\n\n- [PSR-7 Middleware Proposal](https://github.com/php-fig/fig-standards/pull/755)\n- [PHP-FIG mailing list discussion of middleware](https://groups.google.com/forum/#!topic/php-fig/vTtGxdIuBX8)\n- [ircmaxwell All About Middleware](http://blog.ircmaxell.com/2016/05/all-about-middleware.html)\n- [shadowhand All About PSR-7 Middleware](http://shadowhand.me/all-about-psr-7-middleware/)\n- [AndrewCarterUK PSR-7 Objects Are Not Immutable](http://andrewcarteruk.github.io/programming/2016/05/22/psr-7-is-not-immutable.html)\n- [shadowhand Dependency Inversion and PSR-7 Bodies](http://shadowhand.me/dependency-inversion-and-psr-7-bodies/)\n- [PHP-FIG mailing list thread discussing factories](https://groups.google.com/d/msg/php-fig/G5pgQfQ9fpA/UWeM1gm1CwAJ)\n- [PHP-FIG mailing list thread feedback on proposal](https://groups.google.com/d/msg/php-fig/piRtB2Z-AZs/8UIwY1RtDgAJ)\n\n## 9. Errata\n\n### 9.1 Use of explicit nullable type\n\nPrior to PHP 8.4, it was allowed to declare a type accepting `null` by omitting\nthe nullable part of the type if the default value of the property or parameter\nwas set to null. This implicit type declaration is now deprecated and all\ntypes should be declared explicitly.\n\nThis change also requires the minimum PHP version required by this PSR to\nbe updated to 7.1, as nullable types were introduced in this version. Apart\nfrom this change, no breaking change is introduced by this update and the\nbehavior of the interfaces remains the same.\n"
  },
  {
    "path": "accepted/PSR-17-http-factory.md",
    "content": "HTTP Factories\n==============\n\nThis document describes a common standard for factories that create [PSR-7][psr7]\ncompliant HTTP objects.\n\nPSR-7 did not include a recommendation on how to create HTTP objects, which leads\nto difficulties when needing to create new HTTP objects within components that are\nnot tied to a specific implementation of PSR-7.\n\nThe interfaces outlined in this document describe methods by which PSR-7 objects\ncan be instantiated.\n\nThe key words \"MUST\", \"MUST NOT\", \"REQUIRED\", \"SHALL\", \"SHALL NOT\", \"SHOULD\",\n\"SHOULD NOT\", \"RECOMMENDED\", \"MAY\", and \"OPTIONAL\" in this document are to be\ninterpreted as described in [RFC 2119][rfc2119].\n\n[psr7]: https://www.php-fig.org/psr/psr-7/\n[rfc2119]: https://tools.ietf.org/html/rfc2119\n\n## 1. Specification\n\nAn HTTP factory is a method by which a new HTTP object, as defined by PSR-7,\nis created. HTTP factories MUST implement these interfaces for each object type\nthat is provided by the package.\n\n## 2. Interfaces\n\nThe following interfaces MAY be implemented together within a single class or\nin separate classes.\n\n### 2.1 RequestFactoryInterface\n\nHas the ability to create client requests.\n\n```php\nnamespace Psr\\Http\\Message;\n\nuse Psr\\Http\\Message\\RequestInterface;\nuse Psr\\Http\\Message\\UriInterface;\n\ninterface RequestFactoryInterface\n{\n    /**\n     * Create a new request.\n     *\n     * @param string $method The HTTP method associated with the request.\n     * @param UriInterface|string $uri The URI associated with the request. \n     */\n    public function createRequest(string $method, $uri): RequestInterface;\n}\n```\n\n### 2.2 ResponseFactoryInterface\n\nHas the ability to create responses.\n\n```php\nnamespace Psr\\Http\\Message;\n\nuse Psr\\Http\\Message\\ResponseInterface;\n\ninterface ResponseFactoryInterface\n{\n    /**\n     * Create a new response.\n     *\n     * @param int $code The HTTP status code. Defaults to 200.\n     * @param string $reasonPhrase The reason phrase to associate with the status code\n     *     in the generated response. If none is provided, implementations MAY use\n     *     the defaults as suggested in the HTTP specification.\n     */\n    public function createResponse(int $code = 200, string $reasonPhrase = ''): ResponseInterface;\n}\n```\n\n### 2.3 ServerRequestFactoryInterface\n\nHas the ability to create server requests.\n\n```php\nnamespace Psr\\Http\\Message;\n\nuse Psr\\Http\\Message\\ServerRequestInterface;\nuse Psr\\Http\\Message\\UriInterface;\n\ninterface ServerRequestFactoryInterface\n{\n    /**\n     * Create a new server request.\n     *\n     * Note that server parameters are taken precisely as given - no parsing/processing\n     * of the given values is performed. In particular, no attempt is made to\n     * determine the HTTP method or URI, which must be provided explicitly.\n     *\n     * @param string $method The HTTP method associated with the request.\n     * @param UriInterface|string $uri The URI associated with the request. \n     * @param array $serverParams An array of Server API (SAPI) parameters with\n     *     which to seed the generated request instance.\n     */\n    public function createServerRequest(string $method, $uri, array $serverParams = []): ServerRequestInterface;\n}\n```\n\n### 2.4 StreamFactoryInterface\n\nHas the ability to create streams for requests and responses.\n\n```php\nnamespace Psr\\Http\\Message;\n\nuse Psr\\Http\\Message\\StreamInterface;\n\ninterface StreamFactoryInterface\n{\n    /**\n     * Create a new stream from a string.\n     *\n     * The stream SHOULD be created with a temporary resource.\n     *\n     * @param string $content String content with which to populate the stream.\n     */\n    public function createStream(string $content = ''): StreamInterface;\n\n    /**\n     * Create a stream from an existing file.\n     *\n     * The file MUST be opened using the given mode, which may be any mode\n     * supported by the `fopen` function.\n     *\n     * The `$filename` MAY be any string supported by `fopen()`.\n     *\n     * @param string $filename The filename or stream URI to use as basis of stream.\n     * @param string $mode The mode with which to open the underlying filename/stream.\n     *\n     * @throws \\RuntimeException If the file cannot be opened.\n     * @throws \\InvalidArgumentException If the mode is invalid.\n     */\n    public function createStreamFromFile(string $filename, string $mode = 'r'): StreamInterface;\n\n    /**\n     * Create a new stream from an existing resource.\n     *\n     * The stream MUST be readable and may be writable.\n     *\n     * @param resource $resource The PHP resource to use as the basis for the stream.\n     */\n    public function createStreamFromResource($resource): StreamInterface;\n}\n```\n\nImplementations of this interface SHOULD use a temporary stream when creating\nresources from strings. The RECOMMENDED method for doing so is:\n\n```php\n$resource = fopen('php://temp', 'r+');\n```\n\n### 2.5 UploadedFileFactoryInterface\n\nHas the ability to create streams for uploaded files.\n\n```php\nnamespace Psr\\Http\\Message;\n\nuse Psr\\Http\\Message\\StreamInterface;\nuse Psr\\Http\\Message\\UploadedFileInterface;\n\ninterface UploadedFileFactoryInterface\n{\n    /**\n     * Create a new uploaded file.\n     *\n     * If a size is not provided it will be determined by checking the size of\n     * the stream.\n     *\n     * @link http://php.net/manual/features.file-upload.post-method.php\n     * @link http://php.net/manual/features.file-upload.errors.php\n     *\n     * @param StreamInterface $stream The underlying stream representing the\n     *     uploaded file content.\n     * @param int $size The size of the file in bytes.\n     * @param int $error The PHP file upload error.\n     * @param string $clientFilename The filename as provided by the client, if any.\n     * @param string $clientMediaType The media type as provided by the client, if any.\n     *\n     * @throws \\InvalidArgumentException If the file resource is not readable.\n     */\n    public function createUploadedFile(\n        StreamInterface $stream,\n        ?int $size = null,\n        int $error = \\UPLOAD_ERR_OK,\n        ?string $clientFilename = null,\n        ?string $clientMediaType = null\n    ): UploadedFileInterface;\n}\n```\n\nSince [psr/http-factory version 1.1](https://packagist.org/packages/psr/http-factory#1.1.0),\nthe above interface has been updated to add explicit nullable types.\n\n### 2.6 UriFactoryInterface\n\nHas the ability to create URIs for client and server requests.\n\n```php\nnamespace Psr\\Http\\Message;\n\nuse Psr\\Http\\Message\\UriInterface;\n\ninterface UriFactoryInterface\n{\n    /**\n     * Create a new URI.\n     *\n     * @param string $uri The URI to parse.\n     *\n     * @throws \\InvalidArgumentException If the given URI cannot be parsed.\n     */\n    public function createUri(string $uri = '') : UriInterface;\n}\n```\n"
  },
  {
    "path": "accepted/PSR-18-http-client-meta.md",
    "content": "HTTP Client Meta Document\n=========================\n\n## Summary\n\nHTTP requests and responses are the two fundamental objects in web programming.\nAll clients communicating to an external API use some form of HTTP client. Many\nlibraries are coupled to one specific client or implement a client and/or\nadapter layer themselves. This leads to bad library design, version conflicts,\nor code unrelated to the library domain.\n\n## Why bother?\n\nThanks to PSR-7 we know how HTTP requests and responses ideally look, but nothing\ndefines how a request should be sent and a response received. A common interface for HTTP\nclients will allow libraries to be decoupled from specific implementations.\n\n## Scope\n\n### Goals\n\n* A common interface for sending PSR-7 messages and returning PSR-7 responses.\n\n### Non-Goals\n\n* Support for asynchronous HTTP requests is left for another future PSR.\n* This PSR does not define how to configure an HTTP client. It only specifies the\n  default behaviours.\n* This PSR is neutral about the use of middleware.\n\n#### Asynchronous HTTP client\n\nThe reason asynchronous requests are not covered by this PSR is the lack of a\ncommon standard for Promises. Promises are sufficiently complex enough that they\ndeserve their own specification, and should not be wrapped into this one.\n\nA separate interface for asynchronous requests can be defined in a separate PSR\nonce a Promise PSR is accepted. The method signature for asynchronous requests\nMUST be different from the method signature for synchronous requests because\nthe return type of asynchronous calls will be a Promise. Thus this PSR is forwards\ncompatible, and clients will be able to implement one or both interfaces based\non the features they wish to expose.\n\n## Approaches\n\n### Default behavior\n\nThe intention of this PSR is to provide library developers with HTTP clients that\nhave a well defined behaviour. A library should be able to use any compliant client\nwithout special code to handle client implementation details (Liskov substitution\nprinciple). The PSR does not try to restrict nor define how to configure HTTP clients.\n\nAn alternative approach would be to pass configuration to the client. That approach\nwould have a few drawbacks:\n\n* Configuration must be defined by the PSR.\n* All clients must support the defined configuration.\n* If no configuration is passed to the client, the behavior is unpredictable.\n\n#### Naming rationale\n\nThe main interface behaviour is defined by the method `sendRequest(RequestInterface $request): ResponseInterface`.  \nWhile the shorter method name `send()` has been proposed, this was already used by existing and very common HTTP clients like Guzzle. As such, if they are to adopt this standard, they may need to break backwards compatibility in order to implement the specification. By defining `sendRequest()` instead, we ensure they can adopt without any immediate BC breaks.\n\n### Exception Model\n\nThe domain exceptions `NetworkExceptionInterface` and `RequestExceptionInterface` define\na contract very similar to each other. The chosen approach is to not let them extend each other\nbecause inheritance does not make sense in the domain model. A `RequestExceptionInterface` is simply not a\n`NetworkExceptionInterface`.\n\nAllowing exceptions to extend a `RequestAwareException` and/or `ResponseAwareException` interface\nhas been discussed but that is a convenience shortcut that one should not take. One should rather\ncatch the specific exceptions and handle them accordingly.\n\nOne could be more granular when defining exceptions. For example, `TimeOutException` and `HostNotFoundException`\ncould be subtypes of `NetworkExceptionInterface`. The chosen approach is not to define such subtypes because\nthe exception handling in a consuming library would in most cases not be different between those exceptions.\n\n#### Throwing exceptions for 4xx and 5xx responses\n\nThe initial idea was to allow the client to be configured to throw exceptions for responses\nwith HTTP status 4xx and 5xx. That approach is not desired because consuming libraries would\nhave to check for 4xx and 5xx responses twice: first, by verifying the status code on the response,\nand second by catching potential exceptions.\n\nTo make the specification more predictable, it was decided that HTTP clients never will throw\nexceptions for 4xx and 5xx responses.\n\n## Middleware and wrapping a client\n\nThe specification does not put any limitations on middleware or classes that want \nto wrap/decorate an HTTP client. If the decorating class also implements `ClientInterface`\nthen it must also follow the specification. \n\nIt is temping to allow configuration or add middleware to an HTTP client so it could i.e.\nfollow redirects or throw exceptions. If that is a decision from an application developer, \nthey have specifically said they want to break the specification. That is an issue (or feature)\nthe application developer should handle. Third party libraries MUST NOT assume that\na HTTP client breaks the specification.\n\n## Background\n\nThe HTTP client PSR has been inspired and created by the [php-http team](https://github.com/orgs/php-http/people).\nBack in 2015, they created HTTPlug as a common interface for HTTP clients. They wanted an\nabstraction that third party libraries could use so as not to rely on a specific HTTP client\nimplementation. A stable version was tagged in January 2016, and the project has been \nwidely adopted since then. With over 3 million downloads in the two years\nfollowing the initial stable version, it was time to convert this \"de-facto\"\nstandard into a formal specification.\n\n## People\n\n### 5.1 Editor\n\n* Tobias Nyholm\n\n### 5.2 Sponsors\n\n* Sara Golemon\n\n### 5.3 Workgroup\n\n* Simon Asika (Windwalker)\n* David Buchmann (HTTPlug)\n* David De Boer (HTTPlug)\n* Sara Golemon (Sponsor)\n* Jeremy Lindblom (Guzzle)\n* Christian Lück (Buzz react)\n* Tobias Nyholm (Editor)\n* Matthew Weier O'Phinney (Zend)\n* Mark Sagi-Kazar (Guzzle)\n* Joel Wurtz (HTTPlug)\n\n## Votes\n\n* [Entrance vote](https://groups.google.com/d/topic/php-fig/MJGYRXfUJGk/discussion)\n* [Review Period Initiation](https://groups.google.com/d/topic/php-fig/dV9zIaOooZ4/discussion)\n* [Acceptance](https://groups.google.com/d/topic/php-fig/rScdiW38nLM/discussion)\n\n## Proposed implementations\n\nBelow are the two implementations provided by the working group to pass the review period:\n\n * HTTPlug has prepared a 2.0 to make sure it is supporting the new PSR. \n   They are just waiting for the PSR to be released: https://github.com/php-http/httplug/tree/2.x\n * Buzz has been adapting to every version of the PSR and has their 0.17.3 release with the latest \n   version of psr/http-client: https://github.com/kriswallsmith/Buzz\n"
  },
  {
    "path": "accepted/PSR-18-http-client.md",
    "content": "HTTP Client\n===========\n\nThis document describes a common interface for sending HTTP requests and receiving HTTP responses.\n\nThe key words \"MUST\", \"MUST NOT\", \"REQUIRED\", \"SHALL\", \"SHALL NOT\", \"SHOULD\",\n\"SHOULD NOT\", \"RECOMMENDED\", \"MAY\", and \"OPTIONAL\" in this document are to be\ninterpreted as described in [RFC 2119](http://tools.ietf.org/html/rfc2119).\n\n## Goal\n\nThe goal of this PSR is to allow developers to create libraries decoupled from HTTP client\nimplementations. This will make libraries more reusable as it reduces the number of\ndependencies and lowers the likelihood of version conflicts.\n\nA second goal is that HTTP clients can be replaced as per the\n[Liskov substitution principle][Liskov]. This means that all clients MUST behave in the\nsame way when sending a request.\n\n## Definitions\n\n* **Client** - A Client is a library that implements this specification for the purposes of\nsending PSR-7-compatible HTTP Request messages and returning a PSR-7-compatible HTTP Response message to a Calling library.\n* **Calling Library** - A Calling Library is any code that makes use of a Client.  It does not implement\nthis specification's interfaces but consumes an object that implements them (a Client).\n\n## Client\n\nA Client is an object implementing `ClientInterface`.\n\nA Client MAY:\n\n* Choose to send an altered HTTP request from the one it was provided. For example, it could\ncompress an outgoing message body.\n* Choose to alter a received HTTP response before returning it to the calling library. For example, it could\ndecompress an incoming message body.\n\nIf a Client chooses to alter either the HTTP request or HTTP response, it MUST ensure that the\nobject remains internally consistent.  For example, if a Client chooses to decompress the message\nbody then it MUST also remove the `Content-Encoding` header and adjust the `Content-Length` header.\n\nNote that as a result, since [PSR-7 objects are immutable](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-7-http-message-meta.md#why-value-objects),\nthe Calling Library MUST NOT assume that the object passed to `ClientInterface::sendRequest()` will be the same PHP object\nthat is actually sent. For example, the Request object that is returned by an exception MAY be a different object than\nthe one passed to `sendRequest()`, so comparison by reference (===) is not possible.\n\nA Client MUST:\n\n* Reassemble a multi-step HTTP 1xx response itself so that what is returned to the Calling Library is a valid HTTP response\nof status code 200 or higher.\n\n## Error handling\n\nA Client MUST NOT treat a well-formed HTTP request or HTTP response as an error condition. For example, response\nstatus codes in the 400 and 500 range MUST NOT cause an exception and MUST be returned to the Calling Library as normal.\n\nA Client MUST throw an instance of `Psr\\Http\\Client\\ClientExceptionInterface` if and only if it is unable to send\nthe HTTP request at all or if the HTTP response could not be parsed into a PSR-7 response object.\n\nIf a request cannot be sent because the request message is not a well-formed HTTP request or is missing some critical\npiece of information (such as a Host or Method), the Client MUST throw an instance of `Psr\\Http\\Client\\RequestExceptionInterface`.\n\nIf the request cannot be sent due to a network failure of any kind, including a timeout, the Client MUST throw an\ninstance of `Psr\\Http\\Client\\NetworkExceptionInterface`.\n\nClients MAY throw more specific exceptions than those defined here (a `TimeOutException` or `HostNotFoundException` for\nexample), provided they implement the appropriate interface defined above.\n\n## Interfaces\n\n### ClientInterface\n\n```php\nnamespace Psr\\Http\\Client;\n\nuse Psr\\Http\\Message\\RequestInterface;\nuse Psr\\Http\\Message\\ResponseInterface;\n\ninterface ClientInterface\n{\n    /**\n     * Sends a PSR-7 request and returns a PSR-7 response.\n     *\n     * @param RequestInterface $request\n     *\n     * @return ResponseInterface\n     *\n     * @throws \\Psr\\Http\\Client\\ClientExceptionInterface If an error happens while processing the request.\n     */\n    public function sendRequest(RequestInterface $request): ResponseInterface;\n}\n```\n\n### ClientExceptionInterface\n\n```php\nnamespace Psr\\Http\\Client;\n\n/**\n * Every HTTP client related exception MUST implement this interface.\n */\ninterface ClientExceptionInterface extends \\Throwable\n{\n}\n```\n\n### RequestExceptionInterface\n\n```php\nnamespace Psr\\Http\\Client;\n\nuse Psr\\Http\\Message\\RequestInterface;\n\n/**\n * Exception for when a request failed.\n *\n * Examples:\n *      - Request is invalid (e.g. method is missing)\n *      - Runtime request errors (e.g. the body stream is not seekable)\n */\ninterface RequestExceptionInterface extends ClientExceptionInterface\n{\n    /**\n     * Returns the request.\n     *\n     * The request object MAY be a different object from the one passed to ClientInterface::sendRequest()\n     *\n     * @return RequestInterface\n     */\n    public function getRequest(): RequestInterface;\n}\n```\n\n### NetworkExceptionInterface\n\n```php\nnamespace Psr\\Http\\Client;\n\nuse Psr\\Http\\Message\\RequestInterface;\n\n/**\n * Thrown when the request cannot be completed because of network issues.\n *\n * There is no response object as this exception is thrown when no response has been received.\n *\n * Example: the target host name can not be resolved or the connection failed.\n */\ninterface NetworkExceptionInterface extends ClientExceptionInterface\n{\n    /**\n     * Returns the request.\n     *\n     * The request object MAY be a different object from the one passed to ClientInterface::sendRequest()\n     *\n     * @return RequestInterface\n     */\n    public function getRequest(): RequestInterface;\n}\n```\n\n[Liskov]: https://en.wikipedia.org/wiki/Liskov_substitution_principle\n"
  },
  {
    "path": "accepted/PSR-2-coding-style-guide-meta.md",
    "content": "# PSR-2 Meta Document\n\n## 1. Summary\n\nThe intent of this guide is to reduce cognitive friction when scanning code from different authors. It does so\nby enumerating a shared set of rules and expectations about how to format PHP code.\n\nThe style rules herein are derived from commonalities among the various member projects. When various authors\ncollaborate across multiple projects, it helps to have one set of guidelines to be used among all those\nprojects. Thus, the benefit of this guide is not in the rules themselves, but in the sharing of those rules.\n\n## 2. Votes\n\n- **Acceptance Vote:** [ML](https://groups.google.com/d/msg/php-fig/c-QVvnZdMQ0/TdDMdzKFpdIJ)\n\n## 3. Errata\n\n### 3.1 - Multi-line Arguments (09/08/2013)\n\nUsing one or more multi-line arguments (i.e: arrays or anonymous functions) does not constitute\nsplitting the argument list itself, therefore Section 4.6 is not automatically enforced. Arrays and anonymous\nfunctions are able to span multiple lines.\n\nThe following examples are perfectly valid in PSR-2:\n\n```php\n<?php\nsomefunction($foo, $bar, [\n  // ...\n], $baz);\n\n$app->get('/hello/{name}', function ($name) use ($app) {\n    return 'Hello '.$app->escape($name);\n});\n```\n\n### 3.2 - Extending Multiple Interfaces (10/17/2013)\n\nWhen extending multiple interfaces, the list of `extends` should be treated the same as a list\nof `implements`, as declared in Section 4.1.\n\n## 4. People\n\n### 4.1 Editor\n\n* Paul M. Jones\n\n"
  },
  {
    "path": "accepted/PSR-2-coding-style-guide.md",
    "content": "# Coding Style Guide\n\n> **Deprecated** - As of 2019-08-10 PSR-2 has been marked as deprecated. [PSR-12] is now recommended\nas an alternative.\n\n[PSR-12]: https://www.php-fig.org/psr/psr-12/\n\nThis guide extends and expands on [PSR-1], the basic coding standard.\n\nThe intent of this guide is to reduce cognitive friction when scanning code\nfrom different authors. It does so by enumerating a shared set of rules and\nexpectations about how to format PHP code.\n\nThe style rules herein are derived from commonalities among the various member\nprojects. When various authors collaborate across multiple projects, it helps\nto have one set of guidelines to be used among all those projects. Thus, the\nbenefit of this guide is not in the rules themselves, but in the sharing of\nthose rules.\n\nThe key words \"MUST\", \"MUST NOT\", \"REQUIRED\", \"SHALL\", \"SHALL NOT\", \"SHOULD\",\n\"SHOULD NOT\", \"RECOMMENDED\", \"MAY\", and \"OPTIONAL\" in this document are to be\ninterpreted as described in [RFC 2119].\n\n[RFC 2119]: http://www.ietf.org/rfc/rfc2119.txt\n[PSR-0]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md\n[PSR-1]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-1-basic-coding-standard.md\n\n## 1. Overview\n\n- Code MUST follow a \"coding style guide\" PSR [[PSR-1]].\n\n- Code MUST use 4 spaces for indenting, not tabs.\n\n- There MUST NOT be a hard limit on line length; the soft limit MUST be 120\n  characters; lines SHOULD be 80 characters or less.\n\n- There MUST be one blank line after the `namespace` declaration, and there\n  MUST be one blank line after the block of `use` declarations.\n\n- Opening braces for classes MUST go on the next line, and closing braces MUST\n  go on the next line after the body.\n\n- Opening braces for methods MUST go on the next line, and closing braces MUST\n  go on the next line after the body.\n\n- Visibility MUST be declared on all properties and methods; `abstract` and\n  `final` MUST be declared before the visibility; `static` MUST be declared\n  after the visibility.\n\n- Control structure keywords MUST have one space after them; method and\n  function calls MUST NOT.\n\n- Opening braces for control structures MUST go on the same line, and closing\n  braces MUST go on the next line after the body.\n\n- Opening parentheses for control structures MUST NOT have a space after them,\n  and closing parentheses for control structures MUST NOT have a space before.\n\n### 1.1. Example\n\nThis example encompasses some of the rules below as a quick overview:\n\n```php\n<?php\nnamespace Vendor\\Package;\n\nuse FooInterface;\nuse BarClass as Bar;\nuse OtherVendor\\OtherPackage\\BazClass;\n\nclass Foo extends Bar implements FooInterface\n{\n    public function sampleMethod($a, $b = null)\n    {\n        if ($a === $b) {\n            bar();\n        } elseif ($a > $b) {\n            $foo->bar($arg1);\n        } else {\n            BazClass::bar($arg2, $arg3);\n        }\n    }\n\n    final public static function bar()\n    {\n        // method body\n    }\n}\n```\n\n## 2. General\n\n### 2.1. Basic Coding Standard\n\nCode MUST follow all rules outlined in [PSR-1].\n\n### 2.2. Files\n\nAll PHP files MUST use the Unix LF (linefeed) line ending.\n\nAll PHP files MUST end with a single blank line.\n\nThe closing `?>` tag MUST be omitted from files containing only PHP.\n\n### 2.3. Lines\n\nThere MUST NOT be a hard limit on line length.\n\nThe soft limit on line length MUST be 120 characters; automated style checkers\nMUST warn but MUST NOT error at the soft limit.\n\nLines SHOULD NOT be longer than 80 characters; lines longer than that SHOULD\nbe split into multiple subsequent lines of no more than 80 characters each.\n\nThere MUST NOT be trailing whitespace at the end of non-blank lines.\n\nBlank lines MAY be added to improve readability and to indicate related\nblocks of code.\n\nThere MUST NOT be more than one statement per line.\n\n### 2.4. Indenting\n\nCode MUST use an indent of 4 spaces, and MUST NOT use tabs for indenting.\n\n> N.b.: Using only spaces, and not mixing spaces with tabs, helps to avoid\n> problems with diffs, patches, history, and annotations. The use of spaces\n> also makes it easy to insert fine-grained sub-indentation for inter-line\n> alignment.\n\n### 2.5. Keywords and True/False/Null\n\nPHP [keywords] MUST be in lower case.\n\nThe PHP constants `true`, `false`, and `null` MUST be in lower case.\n\n[keywords]: http://php.net/manual/en/reserved.keywords.php\n\n## 3. Namespace and Use Declarations\n\nWhen present, there MUST be one blank line after the `namespace` declaration.\n\nWhen present, all `use` declarations MUST go after the `namespace`\ndeclaration.\n\nThere MUST be one `use` keyword per declaration.\n\nThere MUST be one blank line after the `use` block.\n\nFor example:\n\n```php\n<?php\nnamespace Vendor\\Package;\n\nuse FooClass;\nuse BarClass as Bar;\nuse OtherVendor\\OtherPackage\\BazClass;\n\n// ... additional PHP code ...\n\n```\n\n## 4. Classes, Properties, and Methods\n\nThe term \"class\" refers to all classes, interfaces, and traits.\n\n### 4.1. Extends and Implements\n\nThe `extends` and `implements` keywords MUST be declared on the same line as\nthe class name.\n\nThe opening brace for the class MUST go on its own line; the closing brace\nfor the class MUST go on the next line after the body.\n\n```php\n<?php\nnamespace Vendor\\Package;\n\nuse FooClass;\nuse BarClass as Bar;\nuse OtherVendor\\OtherPackage\\BazClass;\n\nclass ClassName extends ParentClass implements \\ArrayAccess, \\Countable\n{\n    // constants, properties, methods\n}\n```\n\nLists of `implements` MAY be split across multiple lines, where each\nsubsequent line is indented once. When doing so, the first item in the list\nMUST be on the next line, and there MUST be only one interface per line.\n\n```php\n<?php\nnamespace Vendor\\Package;\n\nuse FooClass;\nuse BarClass as Bar;\nuse OtherVendor\\OtherPackage\\BazClass;\n\nclass ClassName extends ParentClass implements\n    \\ArrayAccess,\n    \\Countable,\n    \\Serializable\n{\n    // constants, properties, methods\n}\n```\n\n### 4.2. Properties\n\nVisibility MUST be declared on all properties.\n\nThe `var` keyword MUST NOT be used to declare a property.\n\nThere MUST NOT be more than one property declared per statement.\n\nProperty names SHOULD NOT be prefixed with a single underscore to indicate\nprotected or private visibility.\n\nA property declaration looks like the following.\n\n```php\n<?php\nnamespace Vendor\\Package;\n\nclass ClassName\n{\n    public $foo = null;\n}\n```\n\n### 4.3. Methods\n\nVisibility MUST be declared on all methods.\n\nMethod names SHOULD NOT be prefixed with a single underscore to indicate\nprotected or private visibility.\n\nMethod names MUST NOT be declared with a space after the method name. The\nopening brace MUST go on its own line, and the closing brace MUST go on the\nnext line following the body. There MUST NOT be a space after the opening\nparenthesis, and there MUST NOT be a space before the closing parenthesis.\n\nA method declaration looks like the following. Note the placement of\nparentheses, commas, spaces, and braces:\n\n```php\n<?php\nnamespace Vendor\\Package;\n\nclass ClassName\n{\n    public function fooBarBaz($arg1, &$arg2, $arg3 = [])\n    {\n        // method body\n    }\n}\n```\n\n### 4.4. Method Arguments\n\nIn the argument list, there MUST NOT be a space before each comma, and there\nMUST be one space after each comma.\n\nMethod arguments with default values MUST go at the end of the argument\nlist.\n\n```php\n<?php\nnamespace Vendor\\Package;\n\nclass ClassName\n{\n    public function foo($arg1, &$arg2, $arg3 = [])\n    {\n        // method body\n    }\n}\n```\n\nArgument lists MAY be split across multiple lines, where each subsequent line\nis indented once. When doing so, the first item in the list MUST be on the\nnext line, and there MUST be only one argument per line.\n\nWhen the argument list is split across multiple lines, the closing parenthesis\nand opening brace MUST be placed together on their own line with one space\nbetween them.\n\n```php\n<?php\nnamespace Vendor\\Package;\n\nclass ClassName\n{\n    public function aVeryLongMethodName(\n        ClassTypeHint $arg1,\n        &$arg2,\n        array $arg3 = []\n    ) {\n        // method body\n    }\n}\n```\n\n### 4.5. `abstract`, `final`, and `static`\n\nWhen present, the `abstract` and `final` declarations MUST precede the\nvisibility declaration.\n\nWhen present, the `static` declaration MUST come after the visibility\ndeclaration.\n\n```php\n<?php\nnamespace Vendor\\Package;\n\nabstract class ClassName\n{\n    protected static $foo;\n\n    abstract protected function zim();\n\n    final public static function bar()\n    {\n        // method body\n    }\n}\n```\n\n### 4.6. Method and Function Calls\n\nWhen making a method or function call, there MUST NOT be a space between the\nmethod or function name and the opening parenthesis, there MUST NOT be a space\nafter the opening parenthesis, and there MUST NOT be a space before the\nclosing parenthesis. In the argument list, there MUST NOT be a space before\neach comma, and there MUST be one space after each comma.\n\n```php\n<?php\nbar();\n$foo->bar($arg1);\nFoo::bar($arg2, $arg3);\n```\n\nArgument lists MAY be split across multiple lines, where each subsequent line\nis indented once. When doing so, the first item in the list MUST be on the\nnext line, and there MUST be only one argument per line.\n\n```php\n<?php\n$foo->bar(\n    $longArgument,\n    $longerArgument,\n    $muchLongerArgument\n);\n```\n\n## 5. Control Structures\n\nThe general style rules for control structures are as follows:\n\n- There MUST be one space after the control structure keyword\n- There MUST NOT be a space after the opening parenthesis\n- There MUST NOT be a space before the closing parenthesis\n- There MUST be one space between the closing parenthesis and the opening\n  brace\n- The structure body MUST be indented once\n- The closing brace MUST be on the next line after the body\n\nThe body of each structure MUST be enclosed by braces. This standardizes how\nthe structures look, and reduces the likelihood of introducing errors as new\nlines get added to the body.\n\n### 5.1. `if`, `elseif`, `else`\n\nAn `if` structure looks like the following. Note the placement of parentheses,\nspaces, and braces; and that `else` and `elseif` are on the same line as the\nclosing brace from the earlier body.\n\n```php\n<?php\nif ($expr1) {\n    // if body\n} elseif ($expr2) {\n    // elseif body\n} else {\n    // else body;\n}\n```\n\nThe keyword `elseif` SHOULD be used instead of `else if` so that all control\nkeywords look like single words.\n\n### 5.2. `switch`, `case`\n\nA `switch` structure looks like the following. Note the placement of\nparentheses, spaces, and braces. The `case` statement MUST be indented once\nfrom `switch`, and the `break` keyword (or other terminating keyword) MUST be\nindented at the same level as the `case` body. There MUST be a comment such as\n`// no break` when fall-through is intentional in a non-empty `case` body.\n\n```php\n<?php\nswitch ($expr) {\n    case 0:\n        echo 'First case, with a break';\n        break;\n    case 1:\n        echo 'Second case, which falls through';\n        // no break\n    case 2:\n    case 3:\n    case 4:\n        echo 'Third case, return instead of break';\n        return;\n    default:\n        echo 'Default case';\n        break;\n}\n```\n\n### 5.3. `while`, `do while`\n\nA `while` statement looks like the following. Note the placement of\nparentheses, spaces, and braces.\n\n```php\n<?php\nwhile ($expr) {\n    // structure body\n}\n```\n\nSimilarly, a `do while` statement looks like the following. Note the placement\nof parentheses, spaces, and braces.\n\n```php\n<?php\ndo {\n    // structure body;\n} while ($expr);\n```\n\n### 5.4. `for`\n\nA `for` statement looks like the following. Note the placement of parentheses,\nspaces, and braces.\n\n```php\n<?php\nfor ($i = 0; $i < 10; $i++) {\n    // for body\n}\n```\n\n### 5.5. `foreach`\n\nA `foreach` statement looks like the following. Note the placement of\nparentheses, spaces, and braces.\n\n```php\n<?php\nforeach ($iterable as $key => $value) {\n    // foreach body\n}\n```\n\n### 5.6. `try`, `catch`\n\nA `try catch` block looks like the following. Note the placement of\nparentheses, spaces, and braces.\n\n```php\n<?php\ntry {\n    // try body\n} catch (FirstExceptionType $e) {\n    // catch body\n} catch (OtherExceptionType $e) {\n    // catch body\n}\n```\n\n## 6. Closures\n\nClosures MUST be declared with a space after the `function` keyword, and a\nspace before and after the `use` keyword.\n\nThe opening brace MUST go on the same line, and the closing brace MUST go on\nthe next line following the body.\n\nThere MUST NOT be a space after the opening parenthesis of the argument list\nor variable list, and there MUST NOT be a space before the closing parenthesis\nof the argument list or variable list.\n\nIn the argument list and variable list, there MUST NOT be a space before each\ncomma, and there MUST be one space after each comma.\n\nClosure arguments with default values MUST go at the end of the argument\nlist.\n\nA closure declaration looks like the following. Note the placement of\nparentheses, commas, spaces, and braces:\n\n```php\n<?php\n$closureWithArgs = function ($arg1, $arg2) {\n    // body\n};\n\n$closureWithArgsAndVars = function ($arg1, $arg2) use ($var1, $var2) {\n    // body\n};\n```\n\nArgument lists and variable lists MAY be split across multiple lines, where\neach subsequent line is indented once. When doing so, the first item in the\nlist MUST be on the next line, and there MUST be only one argument or variable\nper line.\n\nWhen the ending list (whether of arguments or variables) is split across\nmultiple lines, the closing parenthesis and opening brace MUST be placed\ntogether on their own line with one space between them.\n\nThe following are examples of closures with and without argument lists and\nvariable lists split across multiple lines.\n\n```php\n<?php\n$longArgs_noVars = function (\n    $longArgument,\n    $longerArgument,\n    $muchLongerArgument\n) {\n    // body\n};\n\n$noArgs_longVars = function () use (\n    $longVar1,\n    $longerVar2,\n    $muchLongerVar3\n) {\n    // body\n};\n\n$longArgs_longVars = function (\n    $longArgument,\n    $longerArgument,\n    $muchLongerArgument\n) use (\n    $longVar1,\n    $longerVar2,\n    $muchLongerVar3\n) {\n    // body\n};\n\n$longArgs_shortVars = function (\n    $longArgument,\n    $longerArgument,\n    $muchLongerArgument\n) use ($var1) {\n    // body\n};\n\n$shortArgs_longVars = function ($arg) use (\n    $longVar1,\n    $longerVar2,\n    $muchLongerVar3\n) {\n    // body\n};\n```\n\nNote that the formatting rules also apply when the closure is used directly\nin a function or method call as an argument.\n\n```php\n<?php\n$foo->bar(\n    $arg1,\n    function ($arg2) use ($var1) {\n        // body\n    },\n    $arg3\n);\n```\n\n## 7. Conclusion\n\nThere are many elements of style and practice intentionally omitted by this\nguide. These include but are not limited to:\n\n- Declaration of global variables and global constants\n\n- Declaration of functions\n\n- Operators and assignment\n\n- Inter-line alignment\n\n- Comments and documentation blocks\n\n- Class name prefixes and suffixes\n\n- Best practices\n\nFuture recommendations MAY revise and extend this guide to address those or\nother elements of style and practice.\n\n## Appendix A. Survey\n\nIn writing this style guide, the group took a survey of member projects to\ndetermine common practices.  The survey is retained herein for posterity.\n\n### A.1. Survey Data\n\n    url,http://www.horde.org/apps/horde/docs/CODING_STANDARDS,http://pear.php.net/manual/en/standards.php,http://solarphp.com/manual/appendix-standards.style,http://framework.zend.com/manual/en/coding-standard.html,https://symfony.com/doc/2.0/contributing/code/standards.html,http://www.ppi.io/docs/coding-standards.html,https://github.com/ezsystems/ezp-next/wiki/codingstandards,http://book.cakephp.org/2.0/en/contributing/cakephp-coding-conventions.html,https://github.com/UnionOfRAD/lithium/wiki/Spec%3A-Coding,http://drupal.org/coding-standards,http://code.google.com/p/sabredav/,http://area51.phpbb.com/docs/31x/coding-guidelines.html,https://docs.google.com/a/zikula.org/document/edit?authkey=CPCU0Us&hgd=1&id=1fcqb93Sn-hR9c0mkN6m_tyWnmEvoswKBtSc0tKkZmJA,http://www.chisimba.com,n/a,https://github.com/Respect/project-info/blob/master/coding-standards-sample.php,n/a,Object Calisthenics for PHP,http://doc.nette.org/en/coding-standard,http://flow3.typo3.org,https://github.com/propelorm/Propel2/wiki/Coding-Standards,http://developer.joomla.org/coding-standards.html\n    voting,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,no,no,no,?,yes,no,yes\n    indent_type,4,4,4,4,4,tab,4,tab,tab,2,4,tab,4,4,4,4,4,4,tab,tab,4,tab\n    line_length_limit_soft,75,75,75,75,no,85,120,120,80,80,80,no,100,80,80,?,?,120,80,120,no,150\n    line_length_limit_hard,85,85,85,85,no,no,no,no,100,?,no,no,no,100,100,?,120,120,no,no,no,no\n    class_names,studly,studly,studly,studly,studly,studly,studly,studly,studly,studly,studly,lower_under,studly,lower,studly,studly,studly,studly,?,studly,studly,studly\n    class_brace_line,next,next,next,next,next,same,next,same,same,same,same,next,next,next,next,next,next,next,next,same,next,next\n    constant_names,upper,upper,upper,upper,upper,upper,upper,upper,upper,upper,upper,upper,upper,upper,upper,upper,upper,upper,upper,upper,upper,upper\n    true_false_null,lower,lower,lower,lower,lower,lower,lower,lower,lower,upper,lower,lower,lower,upper,lower,lower,lower,lower,lower,upper,lower,lower\n    method_names,camel,camel,camel,camel,camel,camel,camel,camel,camel,camel,camel,lower_under,camel,camel,camel,camel,camel,camel,camel,camel,camel,camel\n    method_brace_line,next,next,next,next,next,same,next,same,same,same,same,next,next,same,next,next,next,next,next,same,next,next\n    control_brace_line,same,same,same,same,same,same,next,same,same,same,same,next,same,same,next,same,same,same,same,same,same,next\n    control_space_after,yes,yes,yes,yes,yes,no,yes,yes,yes,yes,no,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes\n    always_use_control_braces,yes,yes,yes,yes,yes,yes,no,yes,yes,yes,no,yes,yes,yes,yes,no,yes,yes,yes,yes,yes,yes\n    else_elseif_line,same,same,same,same,same,same,next,same,same,next,same,next,same,next,next,same,same,same,same,same,same,next\n    case_break_indent_from_switch,0/1,0/1,0/1,1/2,1/2,1/2,1/2,1/1,1/1,1/2,1/2,1/1,1/2,1/2,1/2,1/2,1/2,1/2,0/1,1/1,1/2,1/2\n    function_space_after,no,no,no,no,no,no,no,no,no,no,no,no,no,no,no,no,no,no,no,no,no,no\n    closing_php_tag_required,no,no,no,no,no,no,no,no,yes,no,no,no,no,yes,no,no,no,no,no,yes,no,no\n    line_endings,LF,LF,LF,LF,LF,LF,LF,LF,?,LF,?,LF,LF,LF,LF,?,,LF,?,LF,LF,LF\n    static_or_visibility_first,static,?,static,either,either,either,visibility,visibility,visibility,either,static,either,?,visibility,?,?,either,either,visibility,visibility,static,?\n    control_space_parens,no,no,no,no,no,no,yes,no,no,no,no,no,no,yes,?,no,no,no,no,no,no,no\n    blank_line_after_php,no,no,no,no,yes,no,no,no,no,yes,yes,no,no,yes,?,yes,yes,no,yes,no,yes,no\n    class_method_control_brace,next/next/same,next/next/same,next/next/same,next/next/same,next/next/same,same/same/same,next/next/next,same/same/same,same/same/same,same/same/same,same/same/same,next/next/next,next/next/same,next/same/same,next/next/next,next/next/same,next/next/same,next/next/same,next/next/same,same/same/same,next/next/same,next/next/next\n\n### A.2. Survey Legend\n\n`indent_type`:\nThe type of indenting. `tab` = \"Use a tab\", `2` or `4` = \"number of spaces\"\n\n`line_length_limit_soft`:\nThe \"soft\" line length limit, in characters. `?` = not discernible or no response, `no` means no limit.\n\n`line_length_limit_hard`:\nThe \"hard\" line length limit, in characters. `?` = not discernible or no response, `no` means no limit.\n\n`class_names`:\nHow classes are named. `lower` = lowercase only, `lower_under` = lowercase with underscore separators, `studly` = StudlyCase.\n\n`class_brace_line`:\nDoes the opening brace for a class go on the `same` line as the class keyword, or on the `next` line after it?\n\n`constant_names`:\nHow are class constants named? `upper` = Uppercase with underscore separators.\n\n`true_false_null`:\nAre the `true`, `false`, and `null` keywords spelled as all `lower` case, or all `upper` case?\n\n`method_names`:\nHow are methods named? `camel` = `camelCase`, `lower_under` = lowercase with underscore separators.\n\n`method_brace_line`:\nDoes the opening brace for a method go on the `same` line as the method name, or on the `next` line?\n\n`control_brace_line`:\nDoes the opening brace for a control structure go on the `same` line, or on the `next` line?\n\n`control_space_after`:\nIs there a space after the control structure keyword?\n\n`always_use_control_braces`:\nDo control structures always use braces?\n\n`else_elseif_line`:\nWhen using `else` or `elseif`, does it go on the `same` line as the previous closing brace, or does it go on the `next` line?\n\n`case_break_indent_from_switch`:\nHow many times are `case` and `break` indented from an opening `switch` statement?\n\n`function_space_after`:\nDo function calls have a space after the function name and before the opening parenthesis?\n\n`closing_php_tag_required`:\nIn files containing only PHP, is the closing `?>` tag required?\n\n`line_endings`:\nWhat type of line ending is used?\n\n`static_or_visibility_first`:\nWhen declaring a method, does `static` come first, or does the visibility come first?\n\n`control_space_parens`:\nIn a control structure expression, is there a space after the opening parenthesis and a space before the closing parenthesis? `yes` = `if ( $expr )`, `no` = `if ($expr)`.\n\n`blank_line_after_php`:\nIs there a blank line after the opening PHP tag?\n\n`class_method_control_brace`:\nA summary of what line the opening braces go on for classes, methods, and control structures.\n\n### A.3. Survey Results\n\n    indent_type:\n        tab: 7\n        2: 1\n        4: 14\n    line_length_limit_soft:\n        ?: 2\n        no: 3\n        75: 4\n        80: 6\n        85: 1\n        100: 1\n        120: 4\n        150: 1\n    line_length_limit_hard:\n        ?: 2\n        no: 11\n        85: 4\n        100: 3\n        120: 2\n    class_names:\n        ?: 1\n        lower: 1\n        lower_under: 1\n        studly: 19\n    class_brace_line:\n        next: 16\n        same: 6\n    constant_names:\n        upper: 22\n    true_false_null:\n        lower: 19\n        upper: 3\n    method_names:\n        camel: 21\n        lower_under: 1\n    method_brace_line:\n        next: 15\n        same: 7\n    control_brace_line:\n        next: 4\n        same: 18\n    control_space_after:\n        no: 2\n        yes: 20\n    always_use_control_braces:\n        no: 3\n        yes: 19\n    else_elseif_line:\n        next: 6\n        same: 16\n    case_break_indent_from_switch:\n        0/1: 4\n        1/1: 4\n        1/2: 14\n    function_space_after:\n        no: 22\n    closing_php_tag_required:\n        no: 19\n        yes: 3\n    line_endings:\n        ?: 5\n        LF: 17\n    static_or_visibility_first:\n        ?: 5\n        either: 7\n        static: 4\n        visibility: 6\n    control_space_parens:\n        ?: 1\n        no: 19\n        yes: 2\n    blank_line_after_php:\n        ?: 1\n        no: 13\n        yes: 8\n    class_method_control_brace:\n        next/next/next: 4\n        next/next/same: 11\n        next/same/same: 1\n        same/same/same: 6\n"
  },
  {
    "path": "accepted/PSR-20-clock-meta.md",
    "content": "# Clock Meta Document\n\n## 1. Summary\n\nGetting the current time in applications is typically achieved using the `\\time()` or `\\microtime` functions, or by using a `new \\DateTimeImmutable()` class.\n\nDue to the nature of time progression, these methods cannot be used when predictable results are needed, such as during testing.\n\nThis `ClockInterface` aims to provide a standard way to consume time that allows interoperability, not only when consuming the \"real\" time, but also when predictable results need to be available. This avoids the need to use PHP extensions for testing or redeclaring the `\\time()` function in a local namespace.\n\n## 2. Why Bother?\n\nThere are currently a few libraries that provide this functionality. However, there is no interoperability between these different libraries, as they ship with their own clock interfaces.\n\nSymfony provides a package called `symfony/phpunit-bridge` that has a `\\Symfony\\Bridge\\PhpUnit\\ClockMock` class, which allows mocking PHP's built-in time and date functions. However, this does not solve mocking calls to `new \\DateTimeImmutable()`. It also does not fully mock time when called from other libraries that rely on the system time.\n\n`\\Carbon\\Carbon`, and its fork `\\Cake\\Chronos\\Chronos`, do provide mocking via a static `setTestNow()` method, but this provides no isolation and must be called again to stop mocking.\n\nPros:\n\n* Consistent interface to get the current time;\n* Easy to mock the wall clock time for repeatability.\n\nCons:\n\n* Extra overhead and developer effort to get the current time;\n* Not as simple as calling `\\time()` or `\\date()`.\n\n## 3. Scope\n\n### 3.1 Goals\n\n* Provide a simple and mockable way to read the current time;\n* Allow interoperability between libraries when reading the clock.\n\n### 3.2 Non-Goals\n\n* This PSR does not provide a recommendation on how and when to use the concepts described in this document, so it is not a coding standard;\n* This PSR does not provide a recommendation on how to handle timezones when retrieving the current time. This is left up to the implementation.\n* This PSR does not handle any scheduling methods like `sleep()` or `wait()` because such methods are not related to retrieving the current time.\n\n## 4. Approaches\n\n### 4.1 Chosen Approach\n\nWe have decided to formalize the existing practices used by several other packages. Some popular packages providing this functionality are:\n\n* [`lcobucci/clock`](https://packagist.org/packages/lcobucci/clock)\n* [`kreait/clock`](https://packagist.org/packages/kreait/clock)\n* [`ergebnis/clock`](https://packagist.org/packages/ergebnis/clock)\n* [`mangoweb/clock`](https://packagist.org/packages/mangoweb/clock)\n\n(This list is not exhaustive!)\n\nSome of these provide interfaces and some rely on extending a clock class to mock the current time.\n\nThese implementations all provide a `now()` method which returns a `\\DateTimeImmutable` object. As the `\\DateTimeImmutable` object allows retrieving the Unix timestamp, by calling `getTimestamp()` or `format('u.U')`, this interface does not define any special methods to retrieve a Unix timestamp or any other time information that is not available from a `\\DateTimeImmutable` object.\n\n### 4.2 Timezones\n\nTime by now is defined by interaction of electromagnetic radiation with the excited states of certain atoms, where the SI defines one second as the duration of 9192631770 cycles of radiation corresponding to the transition between two energy levels of the ground state of the caesium-133 atom at 0K. This means that retrieving the current time will always return the same time, no matter where it is observed. While the timezone defines *where* the time was observed, it does not modify the actual \"slice\" of time.\n\nThis means that, for the sake of this PSR, the timezone is considered an implementation detail of the interface.\n\nIt is up to the implementation to make sure that the timezone is handled according to the business logic of the application. That is either by making sure that a call to `now()` will only return a `\\DateTimeImmutable` object with a known timezone (implicit contract) or by explicitly changing the timezone to be correct for the application. This can be done by calling `setTimezone()` to create a new `\\DateTimeImmutable` object with the given timezone.\n\nThese actions are not defined in this interface.\n\n\n### 4.2 Example Implementations\n\n```php\nfinal class SystemClock implements \\Psr\\Clock\\ClockInterface\n{\n    public function now(): \\DateTimeImmutable\n    {\n        return new \\DateTimeImmutable();\n    }\n}\n\nfinal class FrozenClock implements \\Psr\\Clock\\ClockInterface\n{\n    private \\DateTimeImmutable $now;\n\n    public function __construct(\\DateTimeImmutable $now)\n    {\n        $this->now = $now;\n    }\n\n    public function now(): \\DateTimeImmutable\n    {\n        return clone $this->now;\n    }\n}\n\n```\n\n## 5. People\n\n### 5.1 Editor\n\n * Chris Seufert\n\n### 5.2 Sponsor\n\n * Chuck Burgess\n\n### 5.3 Working group members\n\n * Luís Cobucci\n * Pol Dellaiera\n * Ben Edmunds\n * Jérôme Gamez\n * Andreas Heigl\n * Andreas Möller\n\n## 6. Votes\n\n* [Entrance Vote](https://groups.google.com/g/php-fig/c/hIKqd0an-GI)\n* [Acceptance Vote](https://groups.google.com/g/php-fig/c/4esd62o0QoU)\n\n## 7. Relevant Links\n\n* https://github.com/ergebnis/clock/blob/main/src/Clock.php\n* https://github.com/icecave/chrono/blob/master/src/Clock/ClockInterface.php\n* https://github.com/Kdyby/DateTimeProvider/blob/master/src/DateTimeProviderInterface.php\n* https://github.com/kreait/clock-php/blob/main/src/Clock.php\n* https://github.com/lcobucci/clock/blob/2.1.x/src/Clock.php\n* https://github.com/mangoweb-backend/clock/blob/master/src/Clock.php\n* https://martinfowler.com/bliki/ClockWrapper.html\n\n## 8. Past contributors\n\nThis document stems from the work of many people in previous years, we recognize their effort:\n\n *\n_**Note:** Order descending chronologically._\n\n## 9. FAQ\n\n### Why not simply use UTC?\n\nThere are different reasons why this interface does not enforce a specific timezone.\n\nA purely _technical_ reason is that the interface itself provides an explicit contract. Part of this contract\nis the value returned by the `now()` method. At the _language_ level, the only thing we can enforce is that\nthe returned value is of type `\\DateTimeImmutable`. There is no way to enforce a certain timezone at the\nlanguage level.\n\nA _logical_ reason is that the explicit contract should be usable in all situations where one needs a way to\nretrieve the current time. We should not make an assumption at the _contract_ level about what the caller\nneeds. If the contract did define that only `UTC` is returned, then use cases that require something else\nwould have to explicitly work around the returned `UTC` timezone. This is different from an issue like\nimmutability, which also cannot be enforced on the language level, but which is still necessary to adhere\nto other calls on the contract.  For this `ClockInterface`, there will be no other calls.\n\nMost importantly, the explicit contract provided by this interface does not _prevent_ a user from using\nan implicit contract alongside logic to return a `\\DateTimeImmutable` with a specific timezone. Whether\nthat is `UTC` or `Antarctica/Troll`, it is the _user_ who is in control of this.\n\nThe explicit contract defined by the interface does not limit a user in what they are doing. It tries to\nsolve the problem of getting the current time in a reliable way. Whatever view on the current time that is,\nit is not part of the explicit contract.\n\nThus, this interface tries to be as _open as possible_, while at the same time, being as _strict as necessary_.\n"
  },
  {
    "path": "accepted/PSR-20-clock.md",
    "content": "Common Interface for Accessing the Clock\n========================================\n\nThis document describes a simple interface for reading the system clock.\n\nThe key words \"MUST\", \"MUST NOT\", \"REQUIRED\", \"SHALL\", \"SHALL NOT\", \"SHOULD\",\n\"SHOULD NOT\", \"RECOMMENDED\", \"MAY\", and \"OPTIONAL\" in this document are to be\ninterpreted as described in [RFC 2119][].\n\nThe final implementations MAY decorate the objects with more\nfunctionality than the one proposed, but they MUST implement the indicated\ninterfaces/functionality first.\n\n[RFC 2119]: http://tools.ietf.org/html/rfc2119\n\n# 1. Specification\n\n## 1.1 Introduction\n\nCreating a standard way of accessing the clock would allow interoperability\nduring testing, when testing behavior that has timing-based side effects.\nCommon ways to get the current time include calling `\\time()` or \n`new \\DateTimeImmutable('now')`. However, this makes mocking the current time\nimpossible in some situations.\n\n## 1.2 Definitions\n\n* **Clock** - The clock is able to read the current time and date.\n\n* **Timestamp** - The current time as an integer number of seconds since\nJan 1, 1970 00:00:00 UTC.\n\n## 1.3 Usage\n\n**Get the current timestamp**\n\nThis should be done by using the `getTimestamp()` method on the returned `\\DateTimeImmutable`:\n```php\n$timestamp = $clock->now()->getTimestamp();\n```\n\n# 2. Interfaces\n\n## 2.1 ClockInterface\n\nThe clock interface defines the most basic operations to read the current time and date from the clock. \nIt MUST return the time as a `\\DateTimeImmutable`.\n\n```php\n<?php\n\nnamespace Psr\\Clock;\n\ninterface ClockInterface\n{\n    /**\n     * Returns the current time as a DateTimeImmutable Object\n     */\n    public function now(): \\DateTimeImmutable;\n\n}\n```\n"
  },
  {
    "path": "accepted/PSR-3-logger-interface-meta.md",
    "content": "# Logger Meta Document\n\n## 1. Summary\n\nThe logger interface defines a common interface for logging system messages from an application or library.\n\nThis metadocument was written post-hoc, as PSR-3 was originally passed before meta-documents were standard practice.\n\n## 2. Design Decisions\n\n### Static log messages\n\nIt is the intent of this specification that the message passed to a logging method always be a static value.  Any context-specific variability (such as a username, timestamp, or other information) should be provided via the `$context` array only, and the string should use a placeholder to reference it.\n\nThe intent of this design is twofold.  One, the message is then readily available to translation systems to create localized versions of log messages.  Two, context-specific data may contain user input, and thus requires escaping.  That escaping will be necessarily different if the log message is stored in a database for later rendering in HTML, serialized to JSON, serialized to a syslog message string, etc.  It is the responsibility of the logging implementation to ensure that `$context` data that is shown to the user is appropriately escaped. \n\n## 3. People\n\n### 3.1 Editor(s)\n\n* Jordi Boggiano\n\n## 4. Votes\n\n[Approval vote](https://groups.google.com/g/php-fig/c/d0yPC7jWPAE/m/rhexAfz2T_8J)\n\n## 5. Errata\n\n### 5.1 Type additions\n\nThe 2.0 release of the `psr/log` package includes scalar parameter types.  The 3.0 release of the package includes return types.  This structure leverages PHP 7.2 covariance support to allow for a gradual upgrade process, but requires PHP 8.0 for type compatibility.\n\nImplementers MAY add return types to their own packages at their discretion, provided that:\n\n* the return types match those in the 3.0 package.\n* the implementation specifies a minimum PHP version of 8.0.0 or later.\n\nImplementers MAY add parameter types to their own packages in a new major release, either at the same time as adding return types or in a subsequent release, provided that:\n\n* the parameter types match those in the 2.0 package.\n* the implementation specifies a minimum PHP version of 8.0.0 or later.\n* the implementation depends on `\"psr/log\": \"^2.0 || ^3.0\"` so as to exclude the untyped 1.0 version.\n\nImplementers are encouraged but not required to transition their packages toward the 3.0 version of the package at their earliest convenience.\n\n### 5.2 Throwable vs. Exception\n\nAt the time PSR-3 was written, PHP only had the `Exception` type and the more general `Throwable` interface did not yet exist.\n\nIn modern PHP versions, `Throwable` is the common base interface for both `Exception` and `Error`.\n\nWherever this specification refers to an `Exception` being passed in the `exception` context key, it SHOULD be interpreted as allowing any `Throwable` instance.\n\nImplementations MUST still verify that the value in the `exception` context key is actually a `Throwable` before using it as such."
  },
  {
    "path": "accepted/PSR-3-logger-interface.md",
    "content": "Logger Interface\n================\n\nThis document describes a common interface for logging libraries.\n\nThe main goal is to allow libraries to receive a `Psr\\Log\\LoggerInterface`\nobject and write logs to it in a simple and universal way. Frameworks\nand CMSs that have custom needs MAY extend the interface for their own\npurpose, but SHOULD remain compatible with this document. This ensures\nthat the third-party libraries an application uses can write to the\ncentralized application logs.\n\nThe key words \"MUST\", \"MUST NOT\", \"REQUIRED\", \"SHALL\", \"SHALL NOT\", \"SHOULD\",\n\"SHOULD NOT\", \"RECOMMENDED\", \"MAY\", and \"OPTIONAL\" in this document are to be\ninterpreted as described in [RFC 2119][].\n\nThe word `implementor` in this document is to be interpreted as someone\nimplementing the `LoggerInterface` in a log-related library or framework.\nUsers of loggers are referred to as `user`.\n\n[RFC 2119]: http://tools.ietf.org/html/rfc2119\n\n## 1. Specification\n\n### 1.1 Basics\n\n- The `LoggerInterface` exposes eight methods to write logs to the eight\n  [RFC 5424][] levels (debug, info, notice, warning, error, critical, alert,\n  emergency).\n\n- A ninth method, `log`, accepts a log level as the first argument. Calling this\n  method with one of the log level constants MUST have the same result as\n  calling the level-specific method. Calling this method with a level not\n  defined by this specification MUST throw a `Psr\\Log\\InvalidArgumentException`\n  if the implementation does not know about the level. Users SHOULD NOT use a\n  custom level without knowing for sure the current implementation supports it.\n\n[RFC 5424]: http://tools.ietf.org/html/rfc5424\n\n### 1.2 Message\n\n- Every method accepts a string as the message, or an object with a\n  `__toString()` method. Implementors MAY have special handling for the passed\n  objects. If that is not the case, implementors MUST cast it to a string.\n\n- The message MAY contain placeholders which implementors MAY replace with\n  values from the context array.\n\n  Placeholder names MUST correspond to keys in the context array.\n\n  Placeholder names MUST be delimited with a single opening brace `{` and\n  a single closing brace `}`. There MUST NOT be any whitespace between the\n  delimiters and the placeholder name.\n\n  Placeholder names SHOULD be composed only of the characters `A-Z`, `a-z`,\n  `0-9`, underscore `_`, and period `.`. The use of other characters is\n  reserved for future modifications of the placeholders specification.\n\n  Implementors MAY use placeholders to implement various escaping strategies\n  and translate logs for display. Users SHOULD NOT pre-escape placeholder\n  values since they can not know in which context the data will be displayed.\n\n  The following is an example implementation of placeholder interpolation\n  provided for reference purposes only:\n\n  ```php\n  <?php\n\n  /**\n   * Interpolates context values into the message placeholders.\n   */\n  function interpolate($message, array $context = array())\n  {\n      // build a replacement array with braces around the context keys\n      $replace = array();\n      foreach ($context as $key => $val) {\n          // check that the value can be cast to string\n          if (!is_array($val) && (!is_object($val) || method_exists($val, '__toString'))) {\n              $replace['{' . $key . '}'] = $val;\n          }\n      }\n\n      // interpolate replacement values into the message and return\n      return strtr($message, $replace);\n  }\n\n  // a message with brace-delimited placeholder names\n  $message = \"User {username} created\";\n\n  // a context array of placeholder names => replacement values\n  $context = array('username' => 'bolivar');\n\n  // echoes \"User bolivar created\"\n  echo interpolate($message, $context);\n  ```\n\n### 1.3 Context\n\n- Every method accepts an array as context data. This is meant to hold any\n  extraneous information that does not fit well in a string. The array can\n  contain anything. Implementors MUST ensure they treat context data with\n  as much lenience as possible. A given value in the context MUST NOT throw\n  an exception nor raise any php error, warning or notice.\n\n- If an `Exception` object is passed in the context data, it MUST be in the\n  `'exception'` key. Logging exceptions is a common pattern and this allows\n  implementors to extract a stack trace from the exception when the log\n  backend supports it. Implementors MUST still verify that the `'exception'`\n  key is actually an `Exception` before using it as such, as it MAY contain\n  anything.\n\n### 1.4 Helper classes and interfaces\n\n- The `Psr\\Log\\AbstractLogger` class lets you implement the `LoggerInterface`\n  very easily by extending it and implementing the generic `log` method.\n  The other eight methods are forwarding the message and context to it.\n\n- Similarly, using the `Psr\\Log\\LoggerTrait` only requires you to\n  implement the generic `log` method. Note that since traits can not implement\n  interfaces, in this case you still have to implement `LoggerInterface`.\n\n- The `Psr\\Log\\NullLogger` is provided together with the interface. It MAY be\n  used by users of the interface to provide a fall-back \"black hole\"\n  implementation if no logger is given to them. However, conditional logging\n  may be a better approach if context data creation is expensive.\n\n- The `Psr\\Log\\LoggerAwareInterface` only contains a\n  `setLogger(LoggerInterface $logger)` method and can be used by frameworks to\n  auto-wire arbitrary instances with a logger.\n\n- The `Psr\\Log\\LoggerAwareTrait` trait can be used to implement the equivalent\n  interface easily in any class. It gives you access to `$this->logger`.\n\n- The `Psr\\Log\\LogLevel` class holds constants for the eight log levels.\n\n## 2. Package\n\nThe interfaces and classes described as well as relevant exception classes\nand a test suite to verify your implementation are provided as part of the\n[psr/log](https://packagist.org/packages/psr/log) package.\n\n## 3. `Psr\\Log\\LoggerInterface`\n\n```php\n<?php\n\nnamespace Psr\\Log;\n\n/**\n * Describes a logger instance.\n *\n * The message MUST be a string or object implementing __toString().\n *\n * The message MAY contain placeholders in the form: {foo} where foo\n * will be replaced by the context data in key \"foo\".\n *\n * The context array can contain arbitrary data, the only assumption that\n * can be made by implementors is that if an Exception instance is given\n * to produce a stack trace, it MUST be in a key named \"exception\".\n *\n * See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md\n * for the full interface specification.\n */\ninterface LoggerInterface\n{\n    /**\n     * System is unusable.\n     *\n     * @param string $message\n     * @param array $context\n     * @return void\n     */\n    public function emergency($message, array $context = array());\n\n    /**\n     * Action must be taken immediately.\n     *\n     * Example: Entire website down, database unavailable, etc. This should\n     * trigger the SMS alerts and wake you up.\n     *\n     * @param string $message\n     * @param array $context\n     * @return void\n     */\n    public function alert($message, array $context = array());\n\n    /**\n     * Critical conditions.\n     *\n     * Example: Application component unavailable, unexpected exception.\n     *\n     * @param string $message\n     * @param array $context\n     * @return void\n     */\n    public function critical($message, array $context = array());\n\n    /**\n     * Runtime errors that do not require immediate action but should typically\n     * be logged and monitored.\n     *\n     * @param string $message\n     * @param array $context\n     * @return void\n     */\n    public function error($message, array $context = array());\n\n    /**\n     * Exceptional occurrences that are not errors.\n     *\n     * Example: Use of deprecated APIs, poor use of an API, undesirable things\n     * that are not necessarily wrong.\n     *\n     * @param string $message\n     * @param array $context\n     * @return void\n     */\n    public function warning($message, array $context = array());\n\n    /**\n     * Normal but significant events.\n     *\n     * @param string $message\n     * @param array $context\n     * @return void\n     */\n    public function notice($message, array $context = array());\n\n    /**\n     * Interesting events.\n     *\n     * Example: User logs in, SQL logs.\n     *\n     * @param string $message\n     * @param array $context\n     * @return void\n     */\n    public function info($message, array $context = array());\n\n    /**\n     * Detailed debug information.\n     *\n     * @param string $message\n     * @param array $context\n     * @return void\n     */\n    public function debug($message, array $context = array());\n\n    /**\n     * Logs with an arbitrary level.\n     *\n     * @param mixed $level\n     * @param string $message\n     * @param array $context\n     * @return void\n     */\n    public function log($level, $message, array $context = array());\n}\n```\n\n## 4. `Psr\\Log\\LoggerAwareInterface`\n\n```php\n<?php\n\nnamespace Psr\\Log;\n\n/**\n * Describes a logger-aware instance.\n */\ninterface LoggerAwareInterface\n{\n    /**\n     * Sets a logger instance on the object.\n     *\n     * @param LoggerInterface $logger\n     * @return void\n     */\n    public function setLogger(LoggerInterface $logger);\n}\n```\n\n## 5. `Psr\\Log\\LogLevel`\n\n```php\n<?php\n\nnamespace Psr\\Log;\n\n/**\n * Describes log levels.\n */\nclass LogLevel\n{\n    const EMERGENCY = 'emergency';\n    const ALERT     = 'alert';\n    const CRITICAL  = 'critical';\n    const ERROR     = 'error';\n    const WARNING   = 'warning';\n    const NOTICE    = 'notice';\n    const INFO      = 'info';\n    const DEBUG     = 'debug';\n}\n```\n"
  },
  {
    "path": "accepted/PSR-4-autoloader-examples.md",
    "content": "Example Implementations of PSR-4\n================================\n\nThe following examples illustrate PSR-4 compliant code:\n\nClosure Example\n---------------\n\n```php\n<?php\n/**\n * An example of a project-specific implementation.\n *\n * After registering this autoload function with SPL, the following line\n * would cause the function to attempt to load the \\Foo\\Bar\\Baz\\Qux class\n * from /path/to/project/src/Baz/Qux.php:\n *\n *      new \\Foo\\Bar\\Baz\\Qux;\n *\n * @param string $class The fully-qualified class name.\n * @return void\n */\nspl_autoload_register(function ($class) {\n\n    // project-specific namespace prefix\n    $prefix = 'Foo\\\\Bar\\\\';\n\n    // base directory for the namespace prefix\n    $base_dir = __DIR__ . '/src/';\n\n    // does the class use the namespace prefix?\n    $len = strlen($prefix);\n    if (strncmp($prefix, $class, $len) !== 0) {\n        // no, move to the next registered autoloader\n        return;\n    }\n\n    // get the relative class name\n    $relative_class = substr($class, $len);\n\n    // replace the namespace prefix with the base directory, replace namespace\n    // separators with directory separators in the relative class name, append\n    // with .php\n    $file = $base_dir . str_replace('\\\\', '/', $relative_class) . '.php';\n\n    // if the file exists, require it\n    if (file_exists($file)) {\n        require $file;\n    }\n});\n```\n\nClass Example\n-------------\n\nThe following is an example class implementation to handle multiple\nnamespaces:\n\n```php\n<?php\nnamespace Example;\n\n/**\n * An example of a general-purpose implementation that includes the optional\n * functionality of allowing multiple base directories for a single namespace\n * prefix.\n *\n * Given a foo-bar package of classes in the file system at the following\n * paths ...\n *\n *     /path/to/packages/foo-bar/\n *         src/\n *             Baz.php             # Foo\\Bar\\Baz\n *             Qux/\n *                 Quux.php        # Foo\\Bar\\Qux\\Quux\n *         tests/\n *             BazTest.php         # Foo\\Bar\\BazTest\n *             Qux/\n *                 QuuxTest.php    # Foo\\Bar\\Qux\\QuuxTest\n *\n * ... add the path to the class files for the \\Foo\\Bar\\ namespace prefix\n * as follows:\n *\n *      <?php\n *      // instantiate the loader\n *      $loader = new \\Example\\Psr4AutoloaderClass;\n *\n *      // register the autoloader\n *      $loader->register();\n *\n *      // register the base directories for the namespace prefix\n *      $loader->addNamespace('Foo\\Bar', '/path/to/packages/foo-bar/src');\n *      $loader->addNamespace('Foo\\Bar', '/path/to/packages/foo-bar/tests');\n *\n * The following line would cause the autoloader to attempt to load the\n * \\Foo\\Bar\\Qux\\Quux class from /path/to/packages/foo-bar/src/Qux/Quux.php:\n *\n *      <?php\n *      new \\Foo\\Bar\\Qux\\Quux;\n *\n * The following line would cause the autoloader to attempt to load the\n * \\Foo\\Bar\\Qux\\QuuxTest class from /path/to/packages/foo-bar/tests/Qux/QuuxTest.php:\n *\n *      <?php\n *      new \\Foo\\Bar\\Qux\\QuuxTest;\n */\nclass Psr4AutoloaderClass\n{\n    /**\n     * An associative array where the key is a namespace prefix and the value\n     * is an array of base directories for classes in that namespace.\n     *\n     * @var array\n     */\n    protected $prefixes = array();\n\n    /**\n     * Register loader with SPL autoloader stack.\n     *\n     * @return void\n     */\n    public function register()\n    {\n        spl_autoload_register(array($this, 'loadClass'));\n    }\n\n    /**\n     * Adds a base directory for a namespace prefix.\n     *\n     * @param string $prefix The namespace prefix.\n     * @param string $base_dir A base directory for class files in the\n     * namespace.\n     * @param bool $prepend If true, prepend the base directory to the stack\n     * instead of appending it; this causes it to be searched first rather\n     * than last.\n     * @return void\n     */\n    public function addNamespace($prefix, $base_dir, $prepend = false)\n    {\n        // normalize namespace prefix\n        $prefix = trim($prefix, '\\\\') . '\\\\';\n\n        // normalize the base directory with a trailing separator\n        $base_dir = rtrim($base_dir, DIRECTORY_SEPARATOR) . '/';\n\n        // initialize the namespace prefix array\n        if (isset($this->prefixes[$prefix]) === false) {\n            $this->prefixes[$prefix] = array();\n        }\n\n        // retain the base directory for the namespace prefix\n        if ($prepend) {\n            array_unshift($this->prefixes[$prefix], $base_dir);\n        } else {\n            array_push($this->prefixes[$prefix], $base_dir);\n        }\n    }\n\n    /**\n     * Loads the class file for a given class name.\n     *\n     * @param string $class The fully-qualified class name.\n     * @return mixed The mapped file name on success, or boolean false on\n     * failure.\n     */\n    public function loadClass($class)\n    {\n        // the current namespace prefix\n        $prefix = $class;\n\n        // work backwards through the namespace names of the fully-qualified\n        // class name to find a mapped file name\n        while (false !== $pos = strrpos($prefix, '\\\\')) {\n\n            // retain the trailing namespace separator in the prefix\n            $prefix = substr($class, 0, $pos + 1);\n\n            // the rest is the relative class name\n            $relative_class = substr($class, $pos + 1);\n\n            // try to load a mapped file for the prefix and relative class\n            $mapped_file = $this->loadMappedFile($prefix, $relative_class);\n            if ($mapped_file) {\n                return $mapped_file;\n            }\n\n            // remove the trailing namespace separator for the next iteration\n            // of strrpos()\n            $prefix = rtrim($prefix, '\\\\');\n        }\n\n        // never found a mapped file\n        return false;\n    }\n\n    /**\n     * Load the mapped file for a namespace prefix and relative class.\n     *\n     * @param string $prefix The namespace prefix.\n     * @param string $relative_class The relative class name.\n     * @return mixed Boolean false if no mapped file can be loaded, or the\n     * name of the mapped file that was loaded.\n     */\n    protected function loadMappedFile($prefix, $relative_class)\n    {\n        // are there any base directories for this namespace prefix?\n        if (isset($this->prefixes[$prefix]) === false) {\n            return false;\n        }\n\n        // look through base directories for this namespace prefix\n        foreach ($this->prefixes[$prefix] as $base_dir) {\n\n            // replace the namespace prefix with the base directory,\n            // replace namespace separators with directory separators\n            // in the relative class name, append with .php\n            $file = $base_dir\n                  . str_replace('\\\\', '/', $relative_class)\n                  . '.php';\n\n            // if the mapped file exists, require it\n            if ($this->requireFile($file)) {\n                // yes, we're done\n                return $file;\n            }\n        }\n\n        // never found it\n        return false;\n    }\n\n    /**\n     * If a file exists, require it from the file system.\n     *\n     * @param string $file The file to require.\n     * @return bool True if the file exists, false if not.\n     */\n    protected function requireFile($file)\n    {\n        if (file_exists($file)) {\n            require $file;\n            return true;\n        }\n        return false;\n    }\n}\n```\n\n### Unit Tests\n\nThe following example is one way of unit testing the above class loader:\n\n```php\n<?php\nnamespace Example\\Tests;\n\nclass MockPsr4AutoloaderClass extends Psr4AutoloaderClass\n{\n    protected $files = array();\n\n    public function setFiles(array $files)\n    {\n        $this->files = $files;\n    }\n\n    protected function requireFile($file)\n    {\n        return in_array($file, $this->files);\n    }\n}\n\nclass Psr4AutoloaderClassTest extends \\PHPUnit_Framework_TestCase\n{\n    protected $loader;\n\n    protected function setUp()\n    {\n        $this->loader = new MockPsr4AutoloaderClass;\n\n        $this->loader->setFiles(array(\n            '/vendor/foo.bar/src/ClassName.php',\n            '/vendor/foo.bar/src/DoomClassName.php',\n            '/vendor/foo.bar/tests/ClassNameTest.php',\n            '/vendor/foo.bardoom/src/ClassName.php',\n            '/vendor/foo.bar.baz.dib/src/ClassName.php',\n            '/vendor/foo.bar.baz.dib.zim.gir/src/ClassName.php',\n        ));\n\n        $this->loader->addNamespace(\n            'Foo\\Bar',\n            '/vendor/foo.bar/src'\n        );\n\n        $this->loader->addNamespace(\n            'Foo\\Bar',\n            '/vendor/foo.bar/tests'\n        );\n\n        $this->loader->addNamespace(\n            'Foo\\BarDoom',\n            '/vendor/foo.bardoom/src'\n        );\n\n        $this->loader->addNamespace(\n            'Foo\\Bar\\Baz\\Dib',\n            '/vendor/foo.bar.baz.dib/src'\n        );\n\n        $this->loader->addNamespace(\n            'Foo\\Bar\\Baz\\Dib\\Zim\\Gir',\n            '/vendor/foo.bar.baz.dib.zim.gir/src'\n        );\n    }\n\n    public function testExistingFile()\n    {\n        $actual = $this->loader->loadClass('Foo\\Bar\\ClassName');\n        $expect = '/vendor/foo.bar/src/ClassName.php';\n        $this->assertSame($expect, $actual);\n\n        $actual = $this->loader->loadClass('Foo\\Bar\\ClassNameTest');\n        $expect = '/vendor/foo.bar/tests/ClassNameTest.php';\n        $this->assertSame($expect, $actual);\n    }\n\n    public function testMissingFile()\n    {\n        $actual = $this->loader->loadClass('No_Vendor\\No_Package\\NoClass');\n        $this->assertFalse($actual);\n    }\n\n    public function testDeepFile()\n    {\n        $actual = $this->loader->loadClass('Foo\\Bar\\Baz\\Dib\\Zim\\Gir\\ClassName');\n        $expect = '/vendor/foo.bar.baz.dib.zim.gir/src/ClassName.php';\n        $this->assertSame($expect, $actual);\n    }\n\n    public function testConfusion()\n    {\n        $actual = $this->loader->loadClass('Foo\\Bar\\DoomClassName');\n        $expect = '/vendor/foo.bar/src/DoomClassName.php';\n        $this->assertSame($expect, $actual);\n\n        $actual = $this->loader->loadClass('Foo\\BarDoom\\ClassName');\n        $expect = '/vendor/foo.bardoom/src/ClassName.php';\n        $this->assertSame($expect, $actual);\n    }\n}\n```\n"
  },
  {
    "path": "accepted/PSR-4-autoloader-meta.md",
    "content": "# PSR-4 Meta Document\n\n## 1. Summary\n\nThe purpose is to specify the rules for an interoperable PHP autoloader that\nmaps namespaces to file system paths, and that can co-exist with any other SPL\nregistered autoloader.  This would be an addition to, not a replacement for,\nPSR-0.\n\n## 2. Why Bother?\n\n### History of PSR-0\n\nThe PSR-0 class naming and autoloading standard rose out of the broad\nacceptance of the Horde/PEAR convention under the constraints of PHP 5.2 and\nprevious. With that convention, the tendency was to put all PHP source classes\nin a single main directory, using underscores in the class name to indicate\npseudo-namespaces, like so:\n\n    /path/to/src/\n        VendorFoo/\n            Bar/\n                Baz.php     # VendorFoo_Bar_Baz\n        VendorDib/\n            Zim/\n                Gir.php     # Vendor_Dib_Zim_Gir\n\nWith the release of PHP 5.3 and the availability of namespaces proper, PSR-0\nwas introduced to allow both the old Horde/PEAR underscore mode *and* the use\nof the new namespace notation. Underscores were still allowed in the class\nname to ease the transition from the older namespace naming to the newer naming,\nand thereby to encourage wider adoption.\n\n    /path/to/src/\n        VendorFoo/\n            Bar/\n                Baz.php     # VendorFoo_Bar_Baz\n        VendorDib/\n            Zim/\n                Gir.php     # VendorDib_Zim_Gir\n        Irk_Operation/\n            Impending_Doom/\n                V1.php\n                V2.php      # Irk_Operation\\Impending_Doom\\V2\n\nThis structure is informed very much by the fact that the PEAR installer moved\nsource files from PEAR packages into a single central directory.\n\n### Along Comes Composer\n\nWith Composer, package sources are no longer copied to a single global\nlocation. They are used from their installed location and are not moved\naround. This means that with Composer there is no \"single main directory\" for\nPHP sources as with PEAR. Instead, there are multiple directories; each\npackage is in a separate directory for each project.\n\nTo meet the requirements of PSR-0, this leads to Composer packages looking\nlike this:\n\n    vendor/\n        vendor_name/\n            package_name/\n                src/\n                    Vendor_Name/\n                        Package_Name/\n                            ClassName.php       # Vendor_Name\\Package_Name\\ClassName\n                tests/\n                    Vendor_Name/\n                        Package_Name/\n                            ClassNameTest.php   # Vendor_Name\\Package_Name\\ClassNameTest\n\nThe \"src\" and \"tests\" directories have to include vendor and package directory\nnames. This is an artifact of PSR-0 compliance.\n\nMany find this structure to be deeper and more repetitive than necessary. This\nproposal suggests that an additional or superseding PSR would be useful so\nthat we can have packages that look more like the following:\n\n    vendor/\n        vendor_name/\n            package_name/\n                src/\n                    ClassName.php       # Vendor_Name\\Package_Name\\ClassName\n                tests/\n                    ClassNameTest.php   # Vendor_Name\\Package_Name\\ClassNameTest\n\nThis would require an implementation of what was initially called\n\"package-oriented autoloading\" (as vs the traditional \"direct class-to-file\nautoloading\").\n\n### Package-Oriented Autoloading\n\nIt's difficult to implement package-oriented autoloading via an extension or\namendment to PSR-0, because PSR-0 does not allow for an intercessory path\nbetween any portions of the class name. This means the implementation of a\npackage-oriented autoloader would be more complicated than PSR-0. However, it\nwould allow for cleaner packages.\n\nInitially, the following rules were suggested:\n\n1. Implementors MUST use at least two namespace levels: a vendor name, and\npackage name within that vendor. (This top-level two-name combination is\nhereinafter referred to as the vendor-package name or the vendor-package\nnamespace.)\n\n2. Implementors MUST allow a path infix between the vendor-package namespace\nand the remainder of the fully qualified class name.\n\n3. The vendor-package namespace MAY map to any directory. The remaining\nportion of the fully-qualified class name MUST map the namespace names to\nidentically-named directories, and MUST map the class name to an\nidentically-named file ending in .php.\n\nNote that this means the end of underscore-as-directory-separator in the class\nname. One might think underscores should be honored as they are under\nPSR-0, but seeing as their presence in that document is in reference to\ntransitioning away from PHP 5.2 and previous pseudo-namespacing, it is\nacceptable to remove them here as well.\n\n## 3. Scope\n\n### 3.1 Goals\n\n- Retain the PSR-0 rule that implementors MUST use at least two namespace\n  levels: a vendor name, and package name within that vendor.\n\n- Allow a path infix between the vendor-package namespace and the remainder of\n  the fully qualified class name.\n\n- Allow the vendor-package namespace MAY map to any directory, perhaps\n  multiple directories.\n\n- End the honoring of underscores in class names as directory separators\n\n### 3.2 Non-Goals\n\n- Provide a general transformation algorithm for non-class resources\n\n## 4. Approaches\n\n### 4.1 Chosen Approach\n\nThis approach retains key characteristics of PSR-0 while eliminating the\ndeeper directory structures it requires. In addition, it specifies certain\nadditional rules that make implementations explicitly more interoperable.\n\nAlthough not related to directory mapping, the final draft also specifies how\nautoloaders should handle errors.  Specifically, it forbids throwing exceptions\nor raising errors.  The reason is two-fold.\n\n1. Autoloaders in PHP are explicitly designed to be stackable so that if one\nautoloader cannot load a class another has a chance to do so. Having an autoloader\ntrigger a breaking error condition violates that compatibility.\n\n2. `class_exists()` and `interface_exists()` allow \"not found, even after trying to\nautoload\" as a legitimate, normal use case. An autoloader that throws exceptions\nrenders `class_exists()` unusable, which is entirely unacceptable from an interoperability\nstandpoint.  Autoloaders that wish to provide additional debugging information\nin a class-not-found case should do so via logging instead, either to a PSR-3\ncompatible logger or otherwise.\n\nPros:\n\n- Shallower directory structures\n\n- More flexible file locations\n\n- Stops underscore in class name from being honored as directory separator\n\n- Makes implementations more explicitly interoperable\n\nCons:\n\n- It is no longer possible, as under PSR-0, to merely examine a class name to\n  determine where it is in the file system (the \"class-to-file\" convention\n  inherited from Horde/PEAR).\n\n### 4.2 Alternative: Stay With PSR-0 Only\n\nStaying with PSR-0 only, although reasonable, does leave us with relatively\ndeeper directory structures.\n\nPros:\n\n- No need to change anyone's habits or implementations\n\nCons:\n\n- Leaves us with deeper directory structures\n\n- Leaves us with underscores in the class name being honored as directory\n  separators\n\n### 4.3 Alternative: Split Up Autoloading And Transformation\n\nBeau Simensen and others suggested that the transformation algorithm might be\nsplit out from the autoloading proposal so that the transformation rules\ncould be referenced by other proposals. After doing the work to separate them,\nfollowed by a poll and some discussion, the combined version (i.e.,\ntransformation rules embedded in the autoloader proposal) was revealed as the\npreference.\n\nPros:\n\n- Transformation rules could be referenced separately by other proposals\n\nCons:\n\n- Not in line with the wishes of poll respondents and some collaborators\n\n### 4.4 Alternative: Use More Imperative And Narrative Language\n\nAfter the second vote was pulled by a Sponsor after hearing from multiple +1\nvoters that they supported the idea but did not agree with (or understand) the\nwording of the proposal, there was a period during which the voted-on proposal\nwas expanded with greater narrative and somewhat more imperative language. This\napproach was decried by a vocal minority of participants. After some time, Beau\nSimensen started an experimental revision with an eye to PSR-0; the Editor and\nSponsors favored this more terse approach and shepherded the version now under\nconsideration, written by Paul M. Jones and contributed to by many.\n\n### Compatibility Note with PHP 5.3.2 and below\n\nPHP versions before 5.3.3 do not strip the leading namespace separator, so\nthe responsibility to look out for this falls on the implementation. Failing\nto strip the leading namespace separator could lead to unexpected behavior.\n\n## 5. People\n\n### 5.1 Editor\n\n- Paul M. Jones, Solar/Aura\n\n### 5.2 Sponsors\n\n- Phil Sturgeon, PyroCMS (Coordinator)\n- Larry Garfield, Drupal\n\n### 5.3 Contributors\n\n- Andreas Hennings\n- Bernhard Schussek\n- Beau Simensen\n- Donald Gilbert\n- Mike van Riel\n- Paul Dragoonis\n- Too many others to name and count\n\n## 6. Votes\n\n- **Entrance Vote:** <https://groups.google.com/d/msg/php-fig/_LYBgfcEoFE/ZwFTvVTIl4AJ>\n\n- **Acceptance Vote:**\n\n    - 1st attempt: <https://groups.google.com/forum/#!topic/php-fig/Ua46E344_Ls>,\n      presented prior to new workflow; aborted due to accidental proposal modification\n\n    - 2nd attempt: <https://groups.google.com/forum/#!topic/php-fig/NWfyAeF7Psk>,\n      cancelled at the discretion of the sponsor <https://groups.google.com/forum/#!topic/php-fig/t4mW2TQF7iE>\n\n    - 3rd attempt: TBD\n\n## 7. Relevant Links\n\n- [Autoloader, round 4](https://groups.google.com/forum/#!topicsearchin/php-fig/autoload/php-fig/lpmJcmkNYjM)\n- [POLL: Autoloader: Split or Combined?](https://groups.google.com/forum/#!topicsearchin/php-fig/autoload/php-fig/fGwA6XHlYhI)\n- [PSR-X autoloader spec: Loopholes, ambiguities](https://groups.google.com/forum/#!topicsearchin/php-fig/autoload/php-fig/kUbzJAbHxmg)\n- [Autoloader: Combine Proposals?](https://groups.google.com/forum/#!topicsearchin/php-fig/autoload/php-fig/422dFBGs1Yc)\n- [Package-Oriented Autoloader, Round 2](https://groups.google.com/forum/#!topicsearchin/php-fig/autoload/php-fig/Y4xc71Q3YEQ)\n- [Autoloader: looking again at namespace](https://groups.google.com/forum/#!topicsearchin/php-fig/autoload/php-fig/bnoiTxE8L28)\n- [DISCUSSION: Package-Oriented Autoloader - vote against](https://groups.google.com/forum/#!topicsearchin/php-fig/autoload/php-fig/SJTL1ec46II)\n- [VOTE: Package-Oriented Autoloader](https://groups.google.com/forum/#!topicsearchin/php-fig/autoload/php-fig/Ua46E344_Ls)\n- [Proposal: Package-Oriented Autoloader](https://groups.google.com/forum/#!topicsearchin/php-fig/autoload/php-fig/qT7mEy0RIuI)\n- [Towards a Package Oriented Autoloader](https://groups.google.com/forum/#!searchin/php-fig/package$20oriented$20autoloader/php-fig/JdR-g8ZxKa8/jJr80ard-ekJ)\n- [List of Alternative PSR-4 Proposals](https://groups.google.com/forum/#!topic/php-fig/oXr-2TU1lQY)\n- [Summary of [post-Acceptance Vote pull] PSR-4 discussions](https://groups.google.com/forum/#!searchin/php-fig/psr-4$20summary/php-fig/bSTwUX58NhE/YPcFgBjwvpEJ)\n"
  },
  {
    "path": "accepted/PSR-4-autoloader.md",
    "content": "# Autoloader\n\nThe key words \"MUST\", \"MUST NOT\", \"REQUIRED\", \"SHALL\", \"SHALL NOT\", \"SHOULD\",\n\"SHOULD NOT\", \"RECOMMENDED\", \"MAY\", and \"OPTIONAL\" in this document are to be\ninterpreted as described in [RFC 2119](http://tools.ietf.org/html/rfc2119).\n\n## 1. Overview\n\nThis PSR describes a specification for [autoloading][] classes from file\npaths. It is fully interoperable, and can be used in addition to any other\nautoloading specification, including [PSR-0][]. This PSR also describes where\nto place files that will be autoloaded according to the specification.\n\n## 2. Specification\n\n1. The term \"class\" refers to classes, interfaces, traits, and other similar\n   structures.\n\n2. A fully qualified class name has the following form:\n\n        \\<NamespaceName>(\\<SubNamespaceNames>)*\\<ClassName>\n\n    1. The fully qualified class name MUST have a top-level namespace name,\n       also known as a \"vendor namespace\".\n\n    2. The fully qualified class name MAY have one or more sub-namespace\n       names.\n\n    3. The fully qualified class name MUST have a terminating class name.\n\n    4. Underscores have no special meaning in any portion of the fully\n       qualified class name.\n\n    5. Alphabetic characters in the fully qualified class name MAY be any\n       combination of lower case and upper case.\n\n    6. All class names MUST be referenced in a case-sensitive fashion.\n\n3. When loading a file that corresponds to a fully qualified class name ...\n\n    1. A contiguous series of one or more leading namespace and sub-namespace\n       names, not including the leading namespace separator, in the fully\n       qualified class name (a \"namespace prefix\") corresponds to at least one\n       \"base directory\".\n\n    2. The contiguous sub-namespace names after the \"namespace prefix\"\n       correspond to a subdirectory within a \"base directory\", in which the\n       namespace separators represent directory separators. The subdirectory\n       name MUST match the case of the sub-namespace names.\n\n    3. The terminating class name corresponds to a file name ending in `.php`.\n       The file name MUST match the case of the terminating class name.\n\n4. Autoloader implementations MUST NOT throw exceptions, MUST NOT raise errors\n   of any level, and SHOULD NOT return a value.\n\n## 3. Examples\n\nThe table below shows the corresponding file path for a given fully qualified\nclass name, namespace prefix, and base directory.\n\n| Fully Qualified Class Name    | Namespace Prefix   | Base Directory           | Resulting File Path\n| ----------------------------- |--------------------|--------------------------|-------------------------------------------\n| \\Acme\\Log\\Writer\\File_Writer  | Acme\\Log\\Writer    | ./acme-log-writer/lib/   | ./acme-log-writer/lib/File_Writer.php\n| \\Aura\\Web\\Response\\Status     | Aura\\Web           | /path/to/aura-web/src/   | /path/to/aura-web/src/Response/Status.php\n| \\Symfony\\Core\\Request         | Symfony\\Core       | ./vendor/Symfony/Core/   | ./vendor/Symfony/Core/Request.php\n| \\Zend\\Acl                     | Zend               | /usr/includes/Zend/      | /usr/includes/Zend/Acl.php\n\nFor example implementations of autoloaders conforming to the specification,\nplease see the [examples file][]. Example implementations MUST NOT be regarded\nas part of the specification and MAY change at any time.\n\n[autoloading]: https://php.net/manual/en/language.oop5.autoload.php\n[PSR-0]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md\n[examples file]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader-examples.md\n"
  },
  {
    "path": "accepted/PSR-6-cache-meta.md",
    "content": "# PSR-Cache Meta Document\n\n## 1. Summary\n\nCaching is a common way to improve the performance of any project, making\ncaching libraries one of the most common features of many frameworks and\nlibraries. This has lead to a situation where many libraries roll their own\ncaching libraries, with various levels of functionality. These differences are\ncausing developers to have to learn multiple systems which may or may not\nprovide the functionality they need. In addition, the developers of caching\nlibraries themselves face a choice between only supporting a limited number\nof frameworks or creating a large number of adapter classes.\n\n## 2. Why Bother?\n\nA common interface for caching systems will solve these problems. Library and\nframework developers can count on the caching systems working the way they're\nexpecting, while the developers of caching systems will only have to implement\na single set of interfaces rather than a whole assortment of adapters.\n\nMoreover, the implementation presented here is designed for future extensibility.\nIt allows a variety of internally-different but API-compatible implementations\nand offers a clear path for future extension by later PSRs or by specific\nimplementers.\n\nPros:\n* A standard interface for caching allows free-standing libraries to support\ncaching of intermediary data without effort; they may simply (optionally) depend\non this standard interface and leverage it without being concerned about\nimplementation details.\n* Commonly developed caching libraries shared by multiple projects, even if\nthey extend this interface, are likely to be more robust than a dozen separately\ndeveloped implementations.\n\nCons:\n* Any interface standardization runs the risk of stifling future innovation as\nbeing \"not the Way It's Done(tm)\".  However, we believe caching is a sufficiently\ncommoditized problem space that the extension capability offered here mitigates\nany potential risk of stagnation.\n\n## 3. Scope\n\n### 3.1 Goals\n\n* A common interface for basic and intermediate-level caching needs.\n* A clear mechanism for extending the specification to support advanced features,\nboth by future PSRs or by individual implementations. This mechanism must allow\nfor multiple independent extensions without collision.\n\n### 3.2 Non-Goals\n\n* Architectural compatibility with all existing cache implementations.\n* Advanced caching features such as namespacing or tagging that are used by a\nminority of users.\n\n## 4. Approaches\n\n### 4.1 Chosen Approach\n\nThis specification adopts a \"repository model\" or \"data mapper\" model for caching\nrather than the more traditional \"expire-able key-value\" model.  The primary\nreason is flexibility.  A simple key/value model is much more difficult to extend.\n\nThe model here mandates the use of a CacheItem object, which represents a cache\nentry, and a Pool object, which is a given store of cached data.  Items are\nretrieved from the pool, interacted with, and returned to it.  While a bit more\nverbose at times it offers a good, robust, flexible approach to caching,\nespecially in cases where caching is more involved than simply saving and\nretrieving a string.\n\nMost method names were chosen based on common practice and method names in a\nsurvey of member projects and other popular non-member systems.\n\nPros:\n\n* Flexible and extensible\n* Allows a great deal of variation in implementation without violating the interface\n* Does not implicitly expose object constructors as a pseudo-interface.\n\nCons:\n\n* A bit more verbose than the naive approach\n\nExamples:\n\nSome common usage patterns are shown below.  These are non-normative but should\ndemonstrate the application of some design decisions.\n\n```php\n/**\n * Gets a list of available widgets.\n *\n * In this case, we assume the widget list changes so rarely that we want\n * the list cached forever until an explicit clear.\n */\nfunction get_widget_list()\n{\n    $pool = get_cache_pool('widgets');\n    $item = $pool->getItem('widget_list');\n    if (!$item->isHit()) {\n        $value = compute_expensive_widget_list();\n        $item->set($value);\n        $pool->save($item);\n    }\n    return $item->get();\n}\n```\n\n```php\n/**\n * Caches a list of available widgets.\n *\n * In this case, we assume a list of widgets has been computed and we want\n * to cache it, regardless of what may already be cached.\n */\nfunction save_widget_list($list)\n{\n    $pool = get_cache_pool('widgets');\n    $item = $pool->getItem('widget_list');\n    $item->set($list);\n    $pool->save($item);\n}\n```\n\n```php\n/**\n * Clears the list of available widgets.\n *\n * In this case, we simply want to remove the widget list from the cache. We\n * don't care if it was set or not; the post condition is simply \"no longer set\".\n */\nfunction clear_widget_list()\n{\n    $pool = get_cache_pool('widgets');\n    $pool->deleteItems(['widget_list']);\n}\n```\n\n```php\n/**\n * Clears all widget information.\n *\n * In this case, we want to empty the entire widget pool. There may be other\n * pools in the application that will be unaffected.\n */\nfunction clear_widget_cache()\n{\n    $pool = get_cache_pool('widgets');\n    $pool->clear();\n}\n```\n\n```php\n/**\n * Load widgets.\n *\n * We want to get back a list of widgets, of which some are cached and some\n * are not. This of course assumes that loading from the cache is faster than\n * whatever the non-cached loading mechanism is.\n *\n * In this case, we assume widgets may change frequently so we only allow them\n * to be cached for an hour (3600 seconds). We also cache newly-loaded objects\n * back to the pool en masse.\n *\n * Note that a real implementation would probably also want a multi-load\n * operation for widgets, but that's irrelevant for this demonstration.\n */\nfunction load_widgets(array $ids)\n{\n    $pool = get_cache_pool('widgets');\n    $keys = array_map(function($id) { return 'widget.' . $id; }, $ids);\n    $items = $pool->getItems($keys);\n\n    $widgets = array();\n    foreach ($items as $key => $item) {\n        if ($item->isHit()) {\n            $value = $item->get();\n        } else {\n            $value = expensive_widget_load($id);\n            $item->set($value);\n            $item->expiresAfter(3600);\n            $pool->saveDeferred($item, true);\n        }\n        $widget[$value->id()] = $value;\n    }\n    $pool->commit(); // If no items were deferred this is a no-op.\n\n    return $widgets;\n}\n```\n\n```php\n/**\n * This examples reflects functionality that is NOT included in this\n * specification, but is shown as an example of how such functionality MIGHT\n * be added by extending implementations.\n */\n\ninterface TaggablePoolInterface extends Psr\\Cache\\CachePoolInterface\n{\n    /**\n     * Clears only those items from the pool that have the specified tag.\n     */\n    clearByTag($tag);\n}\n\ninterface TaggableItemInterface extends Psr\\Cache\\CacheItemInterface\n{\n    public function setTags(array $tags);\n}\n\n/**\n * Caches a widget with tags.\n */\nfunction set_widget(TaggablePoolInterface $pool, Widget $widget)\n{\n    $key = 'widget.' . $widget->id();\n    $item = $pool->getItem($key);\n\n    $item->setTags($widget->tags());\n    $item->set($widget);\n    $pool->save($item);\n}\n```\n\n### 4.2 Alternative: \"Weak item\" approach\n\nA variety of earlier drafts took a simpler \"key value with expiration\" approach,\nalso known as a \"weak item\" approach.  In this model, the \"Cache Item\" object\nwas really just a dumb array-with-methods object.  Users would instantiate it\ndirectly, then pass it to a cache pool.  While more familiar, that approach\neffectively prevented any meaningful extension of the Cache Item.  It effectively\nmade the Cache Item's constructor part of the implicit interface, and thus\nseverely curtailed extensibility or the ability to have the cache item be where\nthe intelligence lives.\n\nIn a poll conducted in June 2013, most participants showed a clear preference for\nthe more robust if less conventional \"Strong item\" / repository approach, which\nwas adopted as the way forward.\n\nPros:\n* More traditional approach.\n\nCons:\n* Less extensible or flexible.\n\n### 4.3 Alternative: \"Naked value\" approach\n\nSome of the earliest discussions of the Cache spec suggested skipping the Cache\nItem concept all together and just reading/writing raw values to be cached.\nWhile simpler, it was pointed out that made it impossible to tell the difference\nbetween a cache miss and whatever raw value was selected to represent a cache\nmiss.  That is, if a cache lookup returned NULL it's impossible to tell if there\nwas no cached value or if NULL was the value that had been cached.  (NULL is a\nlegitimate value to cache in many cases.)\n\nMost more robust caching implementations we reviewed -- in particular the Stash\ncaching library and the home-grown cache system used by Drupal -- use some sort\nof structured object on `get` at least to avoid confusion between a miss and a\nsentinel value.  Based on that prior experience FIG decided that a naked value\non `get` was impossible.\n\n### 4.4 Alternative: ArrayAccess Pool\n\nThere was a suggestion to make a Pool implement ArrayAccess, which would allow\nfor cache get/set operations to use array syntax.  That was rejected due to\nlimited interest, limited flexibility of that approach (trivial get and set with\ndefault control information is all that's possible), and because it's trivial\nfor a particular implementation to include as an add-on should it desire to\ndo so.\n\n## 5. People\n\n### 5.1 Editor\n\n* Larry Garfield\n\n### 5.2 Sponsors\n\n* Paul Dragoonis, PPI Framework (Coordinator)\n* Robert Hafner, Stash\n\n## 6. Votes\n\n[Acceptance vote on the mailing list](https://groups.google.com/forum/#!msg/php-fig/dSw5IhpKJ1g/O9wpqizWAwAJ)\n\n## 7. Relevant Links\n\n_**Note:** Order descending chronologically._\n\n* [Survey of existing cache implementations][1], by @dragoonis\n* [Strong vs. Weak informal poll][2], by @Crell\n* [Implementation details informal poll][3], by @Crell\n\n[1]: https://docs.google.com/spreadsheet/ccc?key=0Ak2JdGialLildEM2UjlOdnA4ekg3R1Bfeng5eGlZc1E#gid=0\n[2]: https://docs.google.com/spreadsheet/ccc?key=0AsMrMKNHL1uGdDdVd2llN1kxczZQejZaa3JHcXA3b0E#gid=0\n[3]: https://docs.google.com/spreadsheet/ccc?key=0AsMrMKNHL1uGdEE3SU8zclNtdTNobWxpZnFyR0llSXc#gid=1\n\n## 8. Errata\n\n### 8.1 Handling of incorrect DateTime values in expiresAt()\n\nThe `CacheItemInterface::expiresAt()` method's `$expiration` parameter is untyped\nin the interface, but in the docblock is specified as `\\DateTimeInterface`.  The\nintent is that either a `\\DateTime` or `\\DateTimeImmutable` object is allowed.\nHowever, `\\DateTimeInterface` and `\\DateTimeImmutable` were added in PHP 5.5, and\nthe authors chose not to impose a hard syntactic requirement for PHP 5.5 on the\nspecification.\n\nDespite that, implementers MUST accept only `\\DateTimeInterface` or compatible types\n(such as `\\DateTime` and `\\DateTimeImmutable`) as if the method was explicitly typed.\n(Note that the variance rules for a typed parameter may vary between language versions.)\n\nSimulating a failed type check unfortunately varies between PHP versions and thus is not\nrecommended.  Instead, implementors SHOULD throw an instance of `\\Psr\\Cache\\InvalidArgumentException`.  \nThe following sample code is recommended in order to enforce the type check on the expiresAt()\nmethod:\n\n```php\n\nclass ExpiresAtInvalidParameterException implements Psr\\Cache\\InvalidArgumentException {}\n\n// ...\n\nif (! (\n        null === $expiration\n        || $expiration instanceof \\DateTime\n        || $expiration instanceof \\DateTimeInterface\n)) {\n    throw new ExpiresAtInvalidParameterException(sprintf(\n        'Argument 1 passed to %s::expiresAt() must be an instance of DateTime or DateTimeImmutable; %s given',\n        get_class($this),\n        is_object($expiration) ? get_class($expiration) : gettype($expiration)\n    ));\n}\n```\n\n### 8.2 Type additions\n\nThe 2.0 release of the `psr/cache` package includes scalar parameter types.  The 3.0 release of the package includes return types.  This structure leverages PHP 7.2 covariance support to allow for a gradual upgrade process, but requires PHP 8.0 for type compatibility.\n\nThe 2.0 version also corrects the Errata 8.1 above by providing a correct type hint for the `CacheItemInterface::expiresAt()` method's `$expiration` parameter.  That results in a slight change in the error thrown on invalid input; as it is still a fatal disallowed case, FIG has deemed it an acceptably small BC break in order to leverage correct native typing.\n\nImplementers MAY add return types to their own packages at their discretion, provided that:\n\n* the return types match those in the 3.0 package.\n* the implementation specifies a minimum PHP version of 8.0.0 or later.\n\nImplementers MAY add parameter types to their own packages in a new major release, either at the same time as adding return types or in a subsequent release, provided that:\n\n* the parameter types match those in the 2.0 package.\n* the implementation specifies a minimum PHP version of 8.0.0 or later.\n* the implementation depends on `\"psr/cache\": \"^2.0 || ^3.0\"` so as to exclude the untyped 1.0 version.\n\nImplementers are encouraged but not required to transition their packages toward the 3.0 version of the package at their earliest convenience.\n"
  },
  {
    "path": "accepted/PSR-6-cache.md",
    "content": "# Caching Interface\n\nCaching is a common way to improve the performance of any project, making\ncaching libraries one of the most common features of many frameworks and\nlibraries. This has lead to a situation where many libraries build their own\ncaching libraries, with various levels of functionality. These differences are\ncausing developers to have to learn multiple systems which may or may not\nprovide the functionality they need. In addition, the developers of caching\nlibraries themselves face a choice between only supporting a limited number\nof frameworks or creating a large number of adapter classes.\n\nA common interface for caching systems will solve these problems. Library and\nframework developers can count on the caching systems working the way they're\nexpecting, while the developers of caching systems will only have to implement\na single set of interfaces rather than a whole assortment of adapters.\n\nThe key words \"MUST\", \"MUST NOT\", \"REQUIRED\", \"SHALL\", \"SHALL NOT\", \"SHOULD\",\n\"SHOULD NOT\", \"RECOMMENDED\", \"MAY\", and \"OPTIONAL\" in this document are to be\ninterpreted as described in [RFC 2119][].\n\n[RFC 2119]: http://tools.ietf.org/html/rfc2119\n\n## Goal\n\nThe goal of this PSR is to allow developers to create cache-aware libraries that\ncan be integrated into existing frameworks and systems without the need for\ncustom development.\n\n## Definitions\n\n*    **Calling Library** - The library or code that actually needs the cache\nservices. This library will utilize caching services that implement this\nstandard's interfaces, but will otherwise have no knowledge of the\nimplementation of those caching services.\n\n*    **Implementing Library** - This library is responsible for implementing\nthis standard in order to provide caching services to any Calling Library. The\nImplementing Library MUST provide classes which implement the\nCache\\CacheItemPoolInterface and Cache\\CacheItemInterface interfaces.\nImplementing Libraries MUST support at minimum TTL functionality as described\nbelow with whole-second granularity.\n\n*    **TTL** - The Time To Live (TTL) of an item is the amount of time between\nwhen that item is stored and it is considered stale. The TTL is normally defined\nby an integer representing time in seconds, or a DateInterval object.\n\n*    **Expiration** - The actual time when an item is set to go stale. This is\ntypically calculated by adding the TTL to the time when an object is stored, but\nmay also be explicitly set with DateTime object. An item with a 300 second TTL\nstored at 1:30:00 will have an expiration of 1:35:00. Implementing Libraries MAY\nexpire an item before its requested Expiration Time, but MUST treat an item as\nexpired once its Expiration Time is reached. If a calling library asks for an\nitem to be saved but does not specify an expiration time, or specifies a null\nexpiration time or TTL, an Implementing Library MAY use a configured default\nduration. If no default duration has been set, the Implementing Library MUST\ninterpret that as a request to cache the item forever, or for as long as the\nunderlying implementation supports.\n\n*    **Key** - A string of at least one character that uniquely identifies a\ncached item. Implementing libraries MUST support keys consisting of the\ncharacters `A-Z`, `a-z`, `0-9`, `_`, and `.` in any order in UTF-8 encoding and a\nlength of up to 64 characters. Implementing libraries MAY support additional\ncharacters and encodings or longer lengths, but must support at least that\nminimum.  Libraries are responsible for their own escaping of key strings\nas appropriate, but MUST be able to return the original unmodified key string.\nThe following characters are reserved for future extensions and MUST NOT be\nsupported by implementing libraries: `{}()/\\@:`\n\n*    **Hit** - A cache hit occurs when a Calling Library requests an Item by key\nand a matching value is found for that key, and that value has not expired, and\nthe value is not invalid for some other reason. Calling Libraries SHOULD make\nsure to verify isHit() on all get() calls.\n\n*    **Miss** - A cache miss is the opposite of a cache hit. A cache miss occurs\nwhen a Calling Library requests an item by key and that value not found for that\nkey, or the value was found but has expired, or the value is invalid for some\nother reason. An expired value MUST always be considered a cache miss.\n\n*    **Deferred** - A deferred cache save indicates that a cache item may not be\npersisted immediately by the pool. A Pool object MAY delay persisting a deferred\ncache item in order to take advantage of bulk-set operations supported by some\nstorage engines. A Pool MUST ensure that any deferred cache items are eventually\npersisted and data is not lost, and MAY persist them before a Calling Library\nrequests that they be persisted. When a Calling Library invokes the commit()\nmethod all outstanding deferred items MUST be persisted. An Implementing Library\nMAY use whatever logic is appropriate to determine when to persist deferred\nitems, such as an object destructor, persisting all on save(), a timeout or\nmax-items check or any other appropriate logic. Requests for a cache item that\nhas been deferred MUST return the deferred but not-yet-persisted item.\n\n## Data\n\nImplementing libraries MUST support all serializable PHP data types, including:\n\n*    **Strings** - Character strings of arbitrary size in any PHP-compatible encoding.\n*    **Integers** - All integers of any size supported by PHP, up to 64-bit signed.\n*    **Floats** - All signed floating point values.\n*    **Boolean** - True and False.\n*    **Null** - The actual null value.\n*    **Arrays** - Indexed, associative and multidimensional arrays of arbitrary depth.\n*    **Object** - Any object that supports lossless serialization and\ndeserialization such that `$o == unserialize(serialize($o))`. Objects MAY\nleverage PHP's Serializable interface, `__sleep()` or `__wakeup()` magic methods,\nor similar language functionality if appropriate.\n\nAll data passed into the Implementing Library MUST be returned exactly as\npassed. That includes the variable type. That is, it is an error to return\n(string) 5 if (int) 5 was the value saved.  Implementing Libraries MAY use PHP's\n`serialize()`/`unserialize()` functions internally but are not required to do so.\nCompatibility with them is simply used as a baseline for acceptable object values.\n\nIf it is not possible to return the exact saved value for any reason, implementing\nlibraries MUST respond with a cache miss rather than corrupted data.\n\n## Key Concepts\n\n### Pool\n\nThe Pool represents a collection of items in a caching system. The pool is\na logical Repository of all items it contains.  All cacheable items are retrieved\nfrom the Pool as an Item object, and all interaction with the whole universe of\ncached objects happens through the Pool.\n\n### Items\n\nAn Item represents a single key/value pair within a Pool. The key is the primary\nunique identifier for an Item and MUST be immutable. The Value MAY be changed\nat any time.\n\n## Error handling\n\nWhile caching is often an important part of application performance, it should never\nbe a critical part of application functionality. Thus, an error in a cache system SHOULD NOT\nresult in application failure.  For that reason, Implementing Libraries MUST NOT\nthrow exceptions other than those defined by the interface, and SHOULD trap any errors\nor exceptions triggered by an underlying data store and not allow them to bubble.\n\nAn Implementing Library SHOULD log such errors or otherwise report them to an\nadministrator as appropriate.\n\nIf a Calling Library requests that one or more Items be deleted, or that a pool be cleared,\nit MUST NOT be considered an error condition if the specified key does not exist. The\npost-condition is the same (the key does not exist, or the pool is empty), thus there is\nno error condition.\n\n## Interfaces\n\n### CacheItemInterface\n\nCacheItemInterface defines an item inside a cache system.  Each Item object\nMUST be associated with a specific key, which can be set according to the\nimplementing system and is typically passed by the `Cache\\CacheItemPoolInterface`\nobject.\n\nThe `Cache\\CacheItemInterface` object encapsulates the storage and retrieval of\ncache items. Each `Cache\\CacheItemInterface` is generated by a\n`Cache\\CacheItemPoolInterface` object, which is responsible for any required\nsetup as well as associating the object with a unique Key.\n`Cache\\CacheItemInterface` objects MUST be able to store and retrieve any type of\nPHP value defined in the Data section of this document.\n\nCalling Libraries MUST NOT instantiate Item objects themselves. They may only\nbe requested from a Pool object via the `getItem()` method.  Calling Libraries\nSHOULD NOT assume that an Item created by one Implementing Library is\ncompatible with a Pool from another Implementing Library.\n\n```php\n<?php\n\nnamespace Psr\\Cache;\n\n/**\n * CacheItemInterface defines an interface for interacting with objects inside a cache.\n */\ninterface CacheItemInterface\n{\n    /**\n     * Returns the key for the current cache item.\n     *\n     * The key is loaded by the Implementing Library, but should be available to\n     * the higher level callers when needed.\n     *\n     * @return string\n     *   The key string for this cache item.\n     */\n    public function getKey();\n\n    /**\n     * Retrieves the value of the item from the cache associated with this object's key.\n     *\n     * The value returned must be identical to the value originally stored by set().\n     *\n     * If isHit() returns false, this method MUST return null. Note that null\n     * is a legitimate cached value, so the isHit() method SHOULD be used to\n     * differentiate between \"null value was found\" and \"no value was found.\"\n     *\n     * @return mixed\n     *   The value corresponding to this cache item's key, or null if not found.\n     */\n    public function get();\n\n    /**\n     * Confirms if the cache item lookup resulted in a cache hit.\n     *\n     * Note: This method MUST NOT have a race condition between calling isHit()\n     * and calling get().\n     *\n     * @return bool\n     *   True if the request resulted in a cache hit. False otherwise.\n     */\n    public function isHit();\n\n    /**\n     * Sets the value represented by this cache item.\n     *\n     * The $value argument may be any item that can be serialized by PHP,\n     * although the method of serialization is left up to the Implementing\n     * Library.\n     *\n     * @param mixed $value\n     *   The serializable value to be stored.\n     *\n     * @return static\n     *   The invoked object.\n     */\n    public function set($value);\n\n    /**\n     * Sets the expiration time for this cache item.\n     *\n     * @param \\DateTimeInterface|null $expiration\n     *   The point in time after which the item MUST be considered expired.\n     *   If null is passed explicitly, a default value MAY be used. If none is set,\n     *   the value should be stored permanently or for as long as the\n     *   implementation allows.\n     *\n     * @return static\n     *   The called object.\n     */\n    public function expiresAt($expiration);\n\n    /**\n     * Sets the expiration time for this cache item.\n     *\n     * @param int|\\DateInterval|null $time\n     *   The period of time from the present after which the item MUST be considered\n     *   expired. An integer parameter is understood to be the time in seconds until\n     *   expiration. If null is passed explicitly, a default value MAY be used.\n     *   If none is set, the value should be stored permanently or for as long as the\n     *   implementation allows.\n     *\n     * @return static\n     *   The called object.\n     */\n    public function expiresAfter($time);\n\n}\n```\n\n### CacheItemPoolInterface\n\nThe primary purpose of Cache\\CacheItemPoolInterface is to accept a key from the\nCalling Library and return the associated Cache\\CacheItemInterface object.\nIt is also the primary point of interaction with the entire cache collection.\nAll configuration and initialization of the Pool is left up to an Implementing\nLibrary.\n\n```php\n<?php\n\nnamespace Psr\\Cache;\n\n/**\n * CacheItemPoolInterface generates CacheItemInterface objects.\n */\ninterface CacheItemPoolInterface\n{\n    /**\n     * Returns a Cache Item representing the specified key.\n     *\n     * This method must always return a CacheItemInterface object, even in case of\n     * a cache miss. It MUST NOT return null.\n     *\n     * @param string $key\n     *   The key for which to return the corresponding Cache Item.\n     *\n     * @throws InvalidArgumentException\n     *   If the $key string is not a legal value a \\Psr\\Cache\\InvalidArgumentException\n     *   MUST be thrown.\n     *\n     * @return CacheItemInterface\n     *   The corresponding Cache Item.\n     */\n    public function getItem($key);\n\n    /**\n     * Returns a traversable set of cache items.\n     *\n     * @param string[] $keys\n     *   An indexed array of keys of items to retrieve.\n     *\n     * @throws InvalidArgumentException\n     *   If any of the keys in $keys are not a legal value a \\Psr\\Cache\\InvalidArgumentException\n     *   MUST be thrown.\n     *\n     * @return array|\\Traversable\n     *   A traversable collection of Cache Items keyed by the cache keys of\n     *   each item. A Cache item will be returned for each key, even if that\n     *   key is not found. However, if no keys are specified then an empty\n     *   traversable MUST be returned instead.\n     */\n    public function getItems(array $keys = array());\n\n    /**\n     * Confirms if the cache contains specified cache item.\n     *\n     * Note: This method MAY avoid retrieving the cached value for performance reasons.\n     * This could result in a race condition with CacheItemInterface::get(). To avoid\n     * such situation use CacheItemInterface::isHit() instead.\n     *\n     * @param string $key\n     *   The key for which to check existence.\n     *\n     * @throws InvalidArgumentException\n     *   If the $key string is not a legal value a \\Psr\\Cache\\InvalidArgumentException\n     *   MUST be thrown.\n     *\n     * @return bool\n     *   True if item exists in the cache, false otherwise.\n     */\n    public function hasItem($key);\n\n    /**\n     * Deletes all items in the pool.\n     *\n     * @return bool\n     *   True if the pool was successfully cleared. False if there was an error.\n     */\n    public function clear();\n\n    /**\n     * Removes the item from the pool.\n     *\n     * @param string $key\n     *   The key to delete.\n     *\n     * @throws InvalidArgumentException\n     *   If the $key string is not a legal value a \\Psr\\Cache\\InvalidArgumentException\n     *   MUST be thrown.\n     *\n     * @return bool\n     *   True if the item was successfully removed. False if there was an error.\n     */\n    public function deleteItem($key);\n\n    /**\n     * Removes multiple items from the pool.\n     *\n     * @param string[] $keys\n     *   An array of keys that should be removed from the pool.\n     *\n     * @throws InvalidArgumentException\n     *   If any of the keys in $keys are not a legal value a \\Psr\\Cache\\InvalidArgumentException\n     *   MUST be thrown.\n     *\n     * @return bool\n     *   True if the items were successfully removed. False if there was an error.\n     */\n    public function deleteItems(array $keys);\n\n    /**\n     * Persists a cache item immediately.\n     *\n     * @param CacheItemInterface $item\n     *   The cache item to save.\n     *\n     * @return bool\n     *   True if the item was successfully persisted. False if there was an error.\n     */\n    public function save(CacheItemInterface $item);\n\n    /**\n     * Sets a cache item to be persisted later.\n     *\n     * @param CacheItemInterface $item\n     *   The cache item to save.\n     *\n     * @return bool\n     *   False if the item could not be queued or if a commit was attempted and failed. True otherwise.\n     */\n    public function saveDeferred(CacheItemInterface $item);\n\n    /**\n     * Persists any deferred cache items.\n     *\n     * @return bool\n     *   True if all not-yet-saved items were successfully saved or there were none. False otherwise.\n     */\n    public function commit();\n}\n```\n\n### CacheException\n\nThis exception interface is intended for use when critical errors occur,\nincluding but not limited to *cache setup* such as connecting to a cache server\nor invalid credentials supplied.\n\nAny exception thrown by an Implementing Library MUST implement this interface.\n\n```php\n<?php\n\nnamespace Psr\\Cache;\n\n/**\n * Exception interface for all exceptions thrown by an Implementing Library.\n */\ninterface CacheException\n{\n}\n```\n\n### InvalidArgumentException\n\n```php\n<?php\n\nnamespace Psr\\Cache;\n\n/**\n * Exception interface for invalid cache arguments.\n *\n * Any time an invalid argument is passed into a method it must throw an\n * exception class which implements Psr\\Cache\\InvalidArgumentException.\n */\ninterface InvalidArgumentException extends CacheException\n{\n}\n```\n\nSince [psr/cache version 2.0](https://packagist.org/packages/psr/cache#2.0.0), the above interfaces have been updated to add argument type hints.\nSince [psr/cache version 3.0](https://packagist.org/packages/psr/cache#3.0.0), the above interfaces have been updated to add return type hints.  References to `array|\\Traversable` have been replaced with `iterable`.\n"
  },
  {
    "path": "accepted/PSR-7-http-message-meta.md",
    "content": "# HTTP Message Meta Document\n\n## 1. Summary\n\nThe purpose of this proposal is to provide a set of common interfaces for HTTP\nmessages as described in [RFC 7230](http://tools.ietf.org/html/rfc7230) and\n[RFC 7231](http://tools.ietf.org/html/rfc7231), and URIs as described in\n[RFC 3986](http://tools.ietf.org/html/rfc3986) (in the context of HTTP messages).\n\n- RFC 7230: http://www.ietf.org/rfc/rfc7230.txt\n- RFC 7231: http://www.ietf.org/rfc/rfc7231.txt\n- RFC 3986: http://www.ietf.org/rfc/rfc3986.txt\n\nAll HTTP messages consist of the HTTP protocol version being used, headers, and\na message body. A _Request_ builds on the message to include the HTTP method\nused to make the request, and the URI to which the request is made. A\n_Response_ includes the HTTP status code and reason phrase.\n\nIn PHP, HTTP messages are used in two contexts:\n\n- To send an HTTP request, via the `ext/curl` extension, PHP's native stream\n  layer, etc., and process the received HTTP response. In other words, HTTP\n  messages are used when using PHP as an _HTTP client_.\n- To process an incoming HTTP request to the server, and return an HTTP response\n  to the client making the request. PHP can use HTTP messages when used as a\n  _server-side application_ to fulfill HTTP requests.\n\nThis proposal presents an API for fully describing all parts of the various\nHTTP messages within PHP.\n\n## 2. HTTP Messages in PHP\n\nPHP does not have built-in support for HTTP messages.\n\n### Client-side HTTP support\n\nPHP supports sending HTTP requests via several mechanisms:\n\n- [PHP streams](http://php.net/streams)\n- The [cURL extension](http://php.net/curl)\n- [ext/http](http://php.net/http) (v2 also attempts to address server-side support)\n\nPHP streams are the most convenient and ubiquitous way to send HTTP requests,\nbut pose a number of limitations with regards to properly configuring SSL\nsupport, and provide a cumbersome interface around setting things such as\nheaders. cURL provides a complete and expanded feature-set, but, as it is not a\ndefault extension, is often not present. The http extension suffers from the\nsame problem as cURL, as well as the fact that it has traditionally had far\nfewer examples of usage.\n\nMost modern HTTP client libraries tend to abstract the implementation, to\nensure they can work on whatever environment they are executed on, and across\nany of the above layers.\n\n### Server-side HTTP Support\n\nPHP uses Server APIs (SAPI) to interpret incoming HTTP requests, marshal input,\nand pass off handling to scripts. The original SAPI design mirrored [Common\nGateway Interface](http://www.w3.org/CGI/), which would marshal request data\nand push it into environment variables before passing delegation to a script;\nthe script would then pull from the environment variables in order to process\nthe request and return a response.\n\nPHP's SAPI design abstracts common input sources such as cookies, query string\narguments, and url-encoded POST content via superglobals (`$_COOKIE`, `$_GET`,\nand `$_POST`, respectively), providing a layer of convenience for web developers.\n\nOn the response side of the equation, PHP was originally developed as a\ntemplating language, and allows intermixing HTML and PHP; any HTML portions of\na file are immediately flushed to the output buffer. Modern applications and\nframeworks eschew this practice, as it can lead to issues with\nregards to emitting a status line and/or response headers; they tend to\naggregate all headers and content, and emit them at once when all other\napplication processing is complete. Special care needs to be paid to ensure\nthat error reporting and other actions that send content to the output buffer\ndo not flush the output buffer.\n\n## 3. Why Bother?\n\nHTTP messages are used in a wide number of PHP projects -- both clients and\nservers. In each case, we observe one or more of the following patterns or\nsituations:\n\n1. Projects use PHP's superglobals directly.\n2. Projects will create implementations from scratch.\n3. Projects may require a specific HTTP client/server library that provides\n   HTTP message implementations.\n4. Projects may create adapters for common HTTP message implementations.\n\nAs examples:\n\n1. Just about any application that began development before the rise of\n   frameworks, which includes a number of very popular CMS, forum, and shopping\n   cart systems, have historically used superglobals.\n2. Frameworks such as Symfony and Zend Framework each define HTTP components\n   that form the basis of their MVC layers; even small, single-purpose\n   libraries such as oauth2-server-php provide and require their own HTTP\n   request/response implementations. Guzzle, Buzz, and other HTTP client\n   implementations each create their own HTTP message implementations as well.\n3. Projects such as Silex, Stack, and Drupal 8 have hard dependencies on\n   Symfony's HTTP kernel. Any SDK built on Guzzle has a hard requirement on\n   Guzzle's HTTP message implementations.\n4. Projects such as Geocoder create redundant [adapters for common\n   libraries](https://github.com/geocoder-php/Geocoder/tree/6a729c6869f55ad55ae641c74ac9ce7731635e6e/src/Geocoder/HttpAdapter).\n\nDirect usage of superglobals has a number of concerns. First, these are\nmutable, which makes it possible for libraries and code to alter the values,\nand thus alter state for the application. Additionally, superglobals make unit\nand integration testing difficult and brittle, leading to code quality\ndegradation.\n\nIn the current ecosystem of frameworks that implement HTTP message abstractions,\nthe net result is that projects are not capable of interoperability or\ncross-pollination. In order to consume code targeting one framework from\nanother, the first order of business is building a bridge layer between the\nHTTP message implementations. On the client-side, if a particular library does\nnot have an adapter you can utilize, you need to bridge the request/response\npairs if you wish to use an adapter from another library.\n\nFinally, when it comes to server-side responses, PHP gets in its own way: any\ncontent emitted before a call to `header()` will result in that call becoming a\nno-op; depending on error reporting settings, this can often mean headers\nand/or response status are not correctly sent. One way to work around this is\nto use PHP's output buffering features, but nesting of output buffers can\nbecome problematic and difficult to debug. Frameworks and applications thus\ntend to create response abstractions for aggregating headers and content that\ncan be emitted at once - and these abstractions are often incompatible.\n\nThus, the goal of this proposal is to abstract both client- and server-side\nrequest and response interfaces in order to promote interoperability between\nprojects. If projects implement these interfaces, a reasonable level of\ncompatibility may be assumed when adopting code from different libraries.\n\nIt should be noted that the goal of this proposal is not to obsolete the\ncurrent interfaces utilized by existing PHP libraries. This proposal is aimed\nat interoperability between PHP packages for the purpose of describing HTTP\nmessages.\n\n## 4. Scope\n\n### 4.1 Goals\n\n* Provide the interfaces needed for describing HTTP messages.\n* Focus on practical applications and usability.\n* Define the interfaces to model all elements of the HTTP message and URI\n  specifications.\n* Ensure that the API does not impose arbitrary limits on HTTP messages. For\n  example, some HTTP message bodies can be too large to store in memory, so we\n  must account for this.\n* Provide useful abstractions both for handling incoming requests for\n  server-side applications and for sending outgoing requests in HTTP clients.\n\n### 4.2 Non-Goals\n\n* This proposal does not expect all HTTP client libraries or server-side\n  frameworks to change their interfaces to conform. It is strictly meant for\n  interoperability.\n* While everyone's perception of what is and is not an implementation detail\n  varies, this proposal should not impose implementation details. As\n  RFCs 7230, 7231, and 3986 do not force any particular implementation,\n  there will be a certain amount of invention needed to describe HTTP message\n  interfaces in PHP.\n\n## 5. Design Decisions\n\n### Message design\n\nThe `MessageInterface` provides accessors for the elements common to all HTTP\nmessages, whether they are for requests or responses. These elements include:\n\n- HTTP protocol version (e.g., \"1.0\", \"1.1\")\n- HTTP headers\n- HTTP message body\n\nMore specific interfaces are used to describe requests and responses, and more\nspecifically the context of each (client- vs. server-side). These divisions are\npartly inspired by existing PHP usage, but also by other languages such as\nRuby's [Rack](https://rack.github.io),\nPython's [WSGI](https://www.python.org/dev/peps/pep-0333/),\nGo's [http package](http://golang.org/pkg/net/http/),\nNode's [http module](http://nodejs.org/api/http.html), etc.\n\n### Why are there header methods on messages rather than in a header bag?\n\nThe message itself is a container for the headers (as well as the other message\nproperties). How these are represented internally is an implementation detail,\nbut uniform access to headers is a responsibility of the message.\n\n### Why are URIs represented as objects?\n\nURIs are values, with identity defined by the value, and thus should be modeled\nas value objects.\n\nAdditionally, URIs contain a variety of segments which may be accessed many\ntimes in a given request -- and which would require parsing the URI in order to\ndetermine (e.g., via `parse_url()`). Modeling URIs as value objects allows\nparsing once only, and simplifies access to individual segments. It also\nprovides convenience in client applications by allowing users to create new\ninstances of a base URI instance with only the segments that change (e.g.,\nupdating the path only).\n\n### Why does the request interface have methods for dealing with the request-target AND compose a URI?\n\nRFC 7230 details the request line as containing a \"request-target\". Of the four\nforms of request-target, only one is a URI compliant with RFC 3986; the most\ncommon form used is origin-form, which represents the URI without the\nscheme or authority information. Moreover, since all forms are valid for\npurposes of requests, the proposal must accommodate each.\n\n`RequestInterface` thus has methods relating to the request-target. By default,\nit will use the composed URI to present an origin-form request-target, and, in\nthe absence of a URI instance, return the string \"/\".  Another method,\n`withRequestTarget()`, allows specifying an instance with a specific\nrequest-target, allowing users to create requests that use one of the other\nvalid request-target forms.\n\nThe URI is kept as a discrete member of the request for a variety of reasons.\nFor both clients and servers, knowledge of the absolute URI is typically\nrequired. In the case of clients, the URI, and specifically the scheme and\nauthority details, is needed in order to make the actual TCP connection. For\nserver-side applications, the full URI is often required in order to validate\nthe request or to route to an appropriate handler.\n\n### Why value objects?\n\nThe proposal models messages and URIs as [value objects](http://en.wikipedia.org/wiki/Value_object).\n\nMessages are values where the identity is the aggregate of all parts of the\nmessage; a change to any aspect of the message is essentially a new message.\nThis is the very definition of a value object. The practice by which changes\nresult in a new instance is termed [immutability](http://en.wikipedia.org/wiki/Immutable_object),\nand is a feature designed to ensure the integrity of a given value.\n\nThe proposal also recognizes that most clients and server-side\napplications will need to be able to easily update message aspects, and, as\nsuch, provides interface methods that will create new message instances with\nthe updates. These are generally prefixed with the verbiage `with` or\n`without`.\n\nValue objects provides several benefits when modeling HTTP messages:\n\n- Changes in URI state cannot alter the request composing the URI instance.\n- Changes in headers cannot alter the message composing them.\n\nIn essence, modeling HTTP messages as value objects ensures the integrity of\nthe message state, and prevents the need for bi-directional dependencies, which\ncan often go out-of-sync or lead to debugging or performance issues.\n\nFor HTTP clients, they allow consumers to build a base request with data such\nas the base URI and required headers, without needing to build a brand new\nrequest or reset request state for each message the client sends:\n\n```php\n$uri = new Uri('http://api.example.com');\n$baseRequest = new Request($uri, null, [\n    'Authorization' => 'Bearer ' . $token,\n    'Accept'        => 'application/json',\n]);\n\n$request = $baseRequest->withUri($uri->withPath('/user'))->withMethod('GET');\n$response = $client->sendRequest($request);\n\n// get user id from $response\n\n$body = new StringStream(json_encode(['tasks' => [\n    'Code',\n    'Coffee',\n]]));\n$request = $baseRequest\n    ->withUri($uri->withPath('/tasks/user/' . $userId))\n    ->withMethod('POST')\n    ->withHeader('Content-Type', 'application/json')\n    ->withBody($body);\n$response = $client->sendRequest($request)\n\n// No need to overwrite headers or body!\n$request = $baseRequest->withUri($uri->withPath('/tasks'))->withMethod('GET');\n$response = $client->sendRequest($request);\n```\n\nOn the server-side, developers will need to:\n\n- Deserialize the request message body.\n- Decrypt HTTP cookies.\n- Write to the response.\n\nThese operations can be accomplished with value objects as well, with a number\nof benefits:\n\n- The original request state can be stored for retrieval by any consumer.\n- A default response state can be created with default headers and/or message body.\n\nMost popular PHP frameworks have fully mutable HTTP messages today. The main\nchanges necessary in consuming true value objects are:\n\n- Instead of calling setter methods or setting public properties, mutator\n  methods will be called, and the result assigned.\n- Developers must notify the application on a change in state.\n\nAs an example, in Zend Framework 2, instead of the following:\n\n```php\nfunction (MvcEvent $e)\n{\n    $response = $e->getResponse();\n    $response->setHeaderLine('x-foo', 'bar');\n}\n```\n\none would now write:\n\n```php\nfunction (MvcEvent $e)\n{\n    $response = $e->getResponse();\n    $e->setResponse(\n        $response->withHeader('x-foo', 'bar')\n    );\n}\n```\n\nThe above combines assignment and notification in a single call.\n\nThis practice has a side benefit of making explicit any changes to application\nstate being made.\n\n### New instances vs returning $this\n\nOne observation made on the various `with*()` methods is that they can likely\nsafely `return $this;` if the argument presented will not result in a change in\nthe value. One rationale for doing so is performance (as this will not result in\na cloning operation).\n\nThe various interfaces have been written with verbiage indicating that\nimmutability MUST be preserved, but only indicate that \"an instance\" must be\nreturned containing the new state. Since instances that represent the same value\nare considered equal, returning `$this` is functionally equivalent, and thus\nallowed.\n\n### Using streams instead of X\n\n`MessageInterface` uses a body value that must implement `StreamInterface`. This\ndesign decision was made so that developers can send and receive (and/or receive\nand send) HTTP messages that contain more data than can practically be stored in\nmemory while still allowing the convenience of interacting with message bodies\nas a string. While PHP provides a stream abstraction by way of stream wrappers,\nstream resources can be cumbersome to work with: stream resources can only be\ncast to a string using `stream_get_contents()` or manually reading the remainder\nof a string. Adding custom behavior to a stream as it is consumed or populated\nrequires registering a stream filter; however, stream filters can only be added\nto a stream after the filter is registered with PHP (i.e., there is no stream\nfilter autoloading mechanism).\n\nThe use of a well- defined stream interface allows for the potential of\nflexible stream decorators that can be added to a request or response\npre-flight to enable things like encryption, compression, ensuring that the\nnumber of bytes downloaded reflects the number of bytes reported in the\n`Content-Length` of a response, etc. Decorating streams is a well-established\n[pattern in the Java](http://docs.oracle.com/javase/7/docs/api/java/io/package-tree.html)\nand [Node](http://nodejs.org/api/stream.html#stream_class_stream_transform_1)\ncommunities that allows for very flexible streams.\n\nThe majority of the `StreamInterface` API is based on\n[Python's io module](http://docs.python.org/3.1/library/io.html), which provides\na practical and consumable API. Instead of implementing stream\ncapabilities using something like a `WritableStreamInterface` and\n`ReadableStreamInterface`, the capabilities of a stream are provided by methods\nlike `isReadable()`, `isWritable()`, etc. This approach is used by Python,\n[C#, C++](http://msdn.microsoft.com/en-us/library/system.io.stream.aspx),\n[Ruby](http://www.ruby-doc.org/core-2.0.0/IO.html),\n[Node](http://nodejs.org/api/stream.html), and likely others.\n\n#### What if I just want to return a file?\n\nIn some cases, you may want to return a file from the filesystem. The typical\nway to do this in PHP is one of the following:\n\n```php\nreadfile($filename);\n\nstream_copy_to_stream(fopen($filename, 'r'), fopen('php://output', 'w'));\n```\n\nNote that the above omits sending appropriate `Content-Type` and\n`Content-Length` headers; the developer would need to emit these prior to\ncalling the above code.\n\nThe equivalent using HTTP messages would be to use a `StreamInterface`\nimplementation that accepts a filename and/or stream resource, and to provide\nthis to the response instance. A complete example, including setting appropriate\nheaders:\n\n```php\n// where Stream is a concrete StreamInterface:\n$stream   = new Stream($filename);\n$finfo    = new finfo(FILEINFO_MIME);\n$response = $response\n    ->withHeader('Content-Type', $finfo->file($filename))\n    ->withHeader('Content-Length', (string) filesize($filename))\n    ->withBody($stream);\n```\n\nEmitting this response will send the file to the client.\n\n#### What if I want to directly emit output?\n\nDirectly emitting output (e.g. via `echo`, `printf`, or writing to the\n`php://output` stream) is generally only advisable as a performance optimization\nor when emitting large data sets. If it needs to be done and you still wish\nto work in an HTTP message paradigm, one approach would be to use a\ncallback-based `StreamInterface` implementation, per [this\nexample](https://github.com/phly/psr7examples#direct-output). Wrap any code\nemitting output directly in a callback, pass that to an appropriate\n`StreamInterface` implementation, and provide it to the message body:\n\n```php\n$output = new CallbackStream(function () use ($request) {\n    printf(\"The requested URI was: %s<br>\\n\", $request->getUri());\n    return '';\n});\nreturn (new Response())\n    ->withHeader('Content-Type', 'text/html')\n    ->withBody($output);\n```\n\n#### What if I want to use an iterator for content?\n\nRuby's Rack implementation uses an iterator-based approach for server-side\nresponse message bodies. This can be emulated using an HTTP message paradigm via\nan iterator-backed `StreamInterface` approach, as [detailed in the\npsr7examples repository](https://github.com/phly/psr7examples#iterators-and-generators).\n\n### Why are streams mutable?\n\nThe `StreamInterface` API includes methods such as `write()` which can\nchange the message content -- which directly contradicts having immutable\nmessages.\n\nThe problem that arises is due to the fact that the interface is intended to\nwrap a PHP stream or similar. A write operation therefore will proxy to writing\nto the stream. Even if we made `StreamInterface` immutable, once the stream\nhas been updated, any instance that wraps that stream will also be updated --\nmaking immutability impossible to enforce.\n\nOur recommendation is that implementations use read-only streams for\nserver-side requests and client-side responses.\n\n### Rationale for ServerRequestInterface\n\nThe `RequestInterface` and `ResponseInterface` have essentially 1:1\ncorrelations with the request and response messages described in\n[RFC 7230](http://www.ietf.org/rfc/rfc7230.txt). They provide interfaces for\nimplementing value objects that correspond to the specific HTTP message types\nthey model.\n\nFor server-side applications there are other considerations for\nincoming requests:\n\n- Access to server parameters (potentially derived from the request, but also\n  potentially the result of server configuration, and generally represented\n  via the `$_SERVER` superglobal; these are part of the PHP Server API (SAPI)).\n- Access to the query string arguments (usually encapsulated in PHP via the\n  `$_GET` superglobal).\n- Access to the parsed body (i.e., data deserialized from the incoming request\n  body; in PHP, this is typically the result of POST requests using\n  `application/x-www-form-urlencoded` content types, and encapsulated in the\n  `$_POST` superglobal, but for non-POST, non-form-encoded data, could be\n  an array or an object).\n- Access to uploaded files (encapsulated in PHP via the `$_FILES` superglobal).\n- Access to cookie values (encapsulated in PHP via the `$_COOKIE` superglobal).\n- Access to attributes derived from the request (usually, but not limited to,\n  those matched against the URL path).\n\nUniform access to these parameters increases the viability of interoperability\nbetween frameworks and libraries, as they can now assume that if a request\nimplements `ServerRequestInterface`, they can get at these values. It also\nsolves problems within the PHP language itself:\n\n- Until 5.6.0, `php://input` was read-once; as such, instantiating multiple\n  request instances from multiple frameworks/libraries could lead to\n  inconsistent state, as the first to access `php://input` would be the only\n  one to receive the data.\n- Unit testing against superglobals (e.g., `$_GET`, `$_FILES`, etc.) is\n  difficult and typically brittle. Encapsulating them inside the\n  `ServerRequestInterface` implementation eases testing considerations.\n\n### Why \"parsed body\" in the ServerRequestInterface?\n\nArguments were made to use the terminology \"BodyParams\", and require the value\nto be an array, with the following rationale:\n\n- Consistency with other server-side parameter access.\n- `$_POST` is an array, and the 80% use case would target that superglobal.\n- A single type makes for a strong contract, simplifying usage.\n\nThe main argument is that if the body parameters are an array, developers have\npredictable access to values:\n\n```php\n$foo = isset($request->getBodyParams()['foo'])\n    ? $request->getBodyParams()['foo']\n    : null;\n```\n\nThe argument for using \"parsed body\" was made by examining the domain. A message\nbody can contain literally anything. While traditional web applications use\nforms and submit data using POST, this is a use case that is quickly being\nchallenged in current web development trends, which are often API-centric, and\nthus use alternate request methods (notably PUT and PATCH), as well as\nnon-form-encoded content (generally JSON or XML) that _can_ be coerced to arrays\nin many cases, but in many cases also _cannot_ or _should not_.\n\nIf forcing the property representing the parsed body to be only an array,\ndevelopers then need a shared convention about where to put the results of\nparsing the body. These might include:\n\n- A special key under the body parameters, such as `__parsed__`.\n- A specially named attribute, such as `__body__`.\n\nThe end result is that a developer now has to look in multiple locations:\n\n```php\n$data = $request->getBodyParams();\nif (isset($data['__parsed__']) && is_object($data['__parsed__'])) {\n    $data = $data['__parsed__'];\n}\n\n// or:\n$data = $request->getBodyParams();\nif ($request->hasAttribute('__body__')) {\n    $data = $request->getAttribute('__body__');\n}\n```\n\nThe solution presented is to use the terminology \"ParsedBody\", which implies\nthat the values are the results of parsing the message body. This also means\nthat the return value _will_ be ambiguous; however, because this is an attribute\nof the domain, this is also expected. As such, usage will become:\n\n```php\n$data = $request->getParsedBody();\nif (! $data instanceof \\stdClass) {\n    // raise an exception!\n}\n// otherwise, we have what we expected\n```\n\nThis approach removes the limitations of forcing an array, at the expense of\nambiguity of return value. Considering that the other suggested solutions —\npushing the parsed data into a special body parameter key or into an attribute —\nalso suffer from ambiguity, the proposed solution is simpler as it does not\nrequire additions to the interface specification. Ultimately, the ambiguity\nenables the flexibility required when representing the results of parsing the\nbody.\n\n### Why is no functionality included for retrieving the \"base path\"?\n\nMany frameworks provide the ability to get the \"base path,\" usually considered\nthe path up to and including the front controller. As an example, if the\napplication is served at `http://example.com/b2b/index.php`, and the current URI\nused to request it is `http://example.com/b2b/index.php/customer/register`, the\nfunctionality to retrieve the base path would return `/b2b/index.php`. This value\ncan then be used by routers to strip that path segment prior to attempting a\nmatch.\n\nThis value is often also then used for URI generation within applications;\nparameters will be passed to the router, which will generate the path, and\nprefix it with the base path in order to return a fully-qualified URI. Other\ntools — typically view helpers, template filters, or template functions — are\nused to resolve a path relative to the base path in order to generate a URI for\nlinking to resources such as static assets.\n\nOn examination of several different implementations, we noticed the following:\n\n- The logic for determining the base path varies widely between implementations.\n  As an example, compare the [logic in ZF2](https://github.com/zendframework/zf2/blob/release-2.3.7/library/Zend/Http/PhpEnvironment/Request.php#L477-L575)\n  to the [logic in Symfony 2](https://github.com/symfony/symfony/blob/2.7/src/Symfony/Component/HttpFoundation/Request.php#L1858-L1877).\n- Most implementations appear to allow manual injection of a base path to the\n  router and/or any facilities used for URI generation.\n- The primary use cases — routing and URI generation — typically are the only\n  consumers of the functionality; developers usually do not need to be aware\n  of the base path concept as other objects take care of that detail for them.\n  As examples:\n  - A router will strip off the base path for you during routing; you do not\n    need to pass the modified path to the router.\n  - View helpers, template filters, etc. typically are injected with a base path\n    prior to invocation. Sometimes this is manually done, though more often it\n    is the result of framework wiring.\n- All sources necessary for calculating the base path *are already in the\n  `RequestInterface` instance*, via server parameters and the URI instance.\n\nOur stance is that base path detection is framework and/or application\nspecific, and the results of detection can be easily injected into objects that\nneed it, and/or calculated as needed using utility functions and/or classes from\nthe `RequestInterface` instance itself.\n\n### Why does getUploadedFiles() return objects instead of arrays?\n\n`getUploadedFiles()` returns a tree of `Psr\\Http\\Message\\UploadedFileInterface`\ninstances. This is done primarily to simplify specification: instead of\nrequiring paragraphs of implementation specification for an array, we specify an\ninterface.\n\nAdditionally, the data in an `UploadedFileInterface` is normalized to work in\nboth SAPI and non-SAPI environments. This allows the creation of processes to parse\nthe message body manually and assign contents to streams without first writing\nto the filesystem, while still allowing proper handling of file uploads in SAPI\nenvironments.\n\n### What about \"special\" header values?\n\nA number of header values contain unique representation requirements which can\npose problems both for consumption as well as generation; in particular, cookies\nand the `Accept` header.\n\nThis proposal does not provide any special treatment of any header types. The\nbase `MessageInterface` provides methods for header retrieval and setting, and\nall header values are, in the end, string values.\n\nDevelopers are encouraged to write commodity libraries for interacting with\nthese header values, either for the purposes of parsing or generation. Users may\nthen consume these libraries when needing to interact with those values.\nExamples of this practice already exist in libraries such as\n[willdurand/Negotiation](https://github.com/willdurand/Negotiation) and\n[Aura.Accept](https://github.com/auraphp/Aura.Accept). So long as the object\nhas functionality for casting the value to a string, these objects can be\nused to populate the headers of an HTTP message.\n\n## 6. People\n\n### 6.1 Editor(s)\n\n* Matthew Weier O'Phinney\n\n### 6.2 Sponsors\n\n* Paul M. Jones\n* Beau Simensen (coordinator)\n\n### 6.3 Contributors\n\n* Michael Dowling\n* Larry Garfield\n* Evert Pot\n* Tobias Schultze\n* Bernhard Schussek\n* Anton Serdyuk\n* Phil Sturgeon\n* Chris Wilkinson\n\n## 7. Errata\n\n### 7.1 Validation of Header Names and Values\n\nSome special characters within the name or value of an HTTP header might affect\nthe parsing of the serialized message in a way that the contents of unrelated\nheaders are changed. This misparsing can open up an application to security\nvulnerabilities. A common type of vulnerability is CRLF injection, allowing\nan attacker to inject additional headers or to end the list of headers early.\n\nFor this reason classes implementing the `MessageInterface` SHOULD strictly\nvalidate the header names and contents according to the most recent HTTP\nspecification ([RFC 7230#3.2][1] at the time of writing). The implementation\nSHOULD reject invalid values and SHOULD NOT make any attempt to automatically\ncorrect the provided values.\n\nA minimally viable validator is expected to reject header names containing the\nfollowing characters:\n\n- NUL (0x00)\n- `\\r` (0x0D)\n- `\\n` (0x0A)\n- Any character less than or equal to 0x20.\n\nFurther characters or sequences in header names should be rejected according\nto the HTTP specification.\n\nA minimally viable validator is expected to reject header values containing the\nfollowing characters:\n\n- NUL (0x00)\n- `\\r` (0x0D)\n- `\\n` (0x0A)\n\nIf compatibility with older systems is desired then the sequence `\\r\\n` (0x0D0A)\nwithin a header value MAY be accepted if and only if it is immediately followed\nby either SPACE (0x20) or `\\t` (0x09). The full sequence SHOULD then internally\nbe normalized to a single SPACE (0x20).\n\nFurther characters or sequences in header values should be rejected according\nto the HTTP specification.\n\n### 7.2 Type Additions\n\nThe 1.1 release of the `psr/http-message` package includes scalar parameter types.\nThe 2.0 release of the package includes return types.\nThis structure leverages PHP 7.2 covariance support to allow for a gradual upgrade process, but requires PHP 8.0 for type compatibility.\n\nImplementers MAY add return types to their own packages at their discretion, provided that:\n\n* the return types match those in the 2.0 package.\n* the implementation specifies a minimum PHP version of 7.2.0 or later.\n\nImplementers MAY add parameter types to their own packages in a new major release, either at the same time as adding return types or in a subsequent release, provided that:\n\n* the parameter types match those in the 1.1 package.\n* the implementation specifies a minimum PHP version of 7.2.0 or later.\n* the implementation depends on `\"psr/http-message\": \"^1.1 || ^2.0\"` so as to exclude the untyped 1.0 version.\n\nImplementers are encouraged but not required to transition their packages toward the 2.0 version of the package at their earliest convenience.\n\n[1]: https://datatracker.ietf.org/doc/html/rfc7230#section-3.2\n\n### 7.3 Escaping User Info\n\nSome characters are reserved in the user info part of the authority section.\nAccording to (RFC3986 2.2 and 3.2.1)[https://www.rfc-editor.org/rfc/rfc3986], the reserved characters are `\"/\" / \"?\" / \"#\" / \"[\" / \"]\" / \"@\"`.\nAdditionally, `:` must be encoded when in the username because it is used to separate username and password.\n\n`UriInterface::withUserInfo()` MUST NOT double encode reserved characters.\n\n`UriInterface::getUserInfo()` MUST encode the reserved characters according to RFC3986 when returning the authority.\nIf there is a password, the `:` between username and password MUST NOT be encoded.\n\n"
  },
  {
    "path": "accepted/PSR-7-http-message.md",
    "content": "# HTTP message interfaces\n\nThis document describes common interfaces for representing HTTP messages as\ndescribed in [RFC 7230](http://tools.ietf.org/html/rfc7230) and\n[RFC 7231](http://tools.ietf.org/html/rfc7231), and URIs for use with HTTP\nmessages as described in [RFC 3986](http://tools.ietf.org/html/rfc3986).\n\nHTTP messages are the foundation of web development. Web browsers and HTTP\nclients such as cURL create HTTP request messages that are sent to a web server,\nwhich provides an HTTP response message. Server-side code receives an HTTP\nrequest message, and returns an HTTP response message.\n\nHTTP messages are typically abstracted from the end-user consumer, but as\ndevelopers, we typically need to know how they are structured and how to\naccess or manipulate them in order to perform our tasks, whether that might be\nmaking a request to an HTTP API, or handling an incoming request.\n\nEvery HTTP request message has a specific form:\n\n```http\nPOST /path HTTP/1.1\nHost: example.com\n\nfoo=bar&baz=bat\n```\n\nThe first line of a request is the \"request line\", and contains, in order, the\nHTTP request method, the request target (usually either an absolute URI or a\npath on the web server), and the HTTP protocol version. This is followed by one\nor more HTTP headers, an empty line, and the message body.\n\nHTTP response messages have a similar structure:\n\n```http\nHTTP/1.1 200 OK\nContent-Type: text/plain\n\nThis is the response body\n```\n\nThe first line is the \"status line\", and contains, in order, the HTTP protocol\nversion, the HTTP status code, and a \"reason phrase,\" a human-readable\ndescription of the status code. Like the request message, this is then\nfollowed by one or more HTTP headers, an empty line, and the message body.\n\nThe interfaces described in this document are abstractions around HTTP messages\nand the elements composing them.\n\nThe key words \"MUST\", \"MUST NOT\", \"REQUIRED\", \"SHALL\", \"SHALL NOT\", \"SHOULD\",\n\"SHOULD NOT\", \"RECOMMENDED\", \"MAY\", and \"OPTIONAL\" in this document are to be\ninterpreted as described in [RFC 2119](http://tools.ietf.org/html/rfc2119).\n\n### References\n\n- [RFC 2119](http://tools.ietf.org/html/rfc2119)\n- [RFC 3986](http://tools.ietf.org/html/rfc3986)\n- [RFC 7230](http://tools.ietf.org/html/rfc7230)\n- [RFC 7231](http://tools.ietf.org/html/rfc7231)\n\n## 1. Specification\n\n### 1.1 Messages\n\nAn HTTP message is either a request from a client to a server or a response from\na server to a client. This specification defines interfaces for the HTTP messages\n`Psr\\Http\\Message\\RequestInterface` and `Psr\\Http\\Message\\ResponseInterface` respectively.\n\nBoth `Psr\\Http\\Message\\RequestInterface` and `Psr\\Http\\Message\\ResponseInterface` extend\n`Psr\\Http\\Message\\MessageInterface`. While `Psr\\Http\\Message\\MessageInterface` MAY be\nimplemented directly, implementors SHOULD implement\n`Psr\\Http\\Message\\RequestInterface` and `Psr\\Http\\Message\\ResponseInterface`.\n\nFrom here forward, the namespace `Psr\\Http\\Message` will be omitted when\nreferring to these interfaces.\n\n### 1.2 HTTP Headers\n\n[cf. [errata](https://www.php-fig.org/psr/psr-7/meta/#71-validation-of-header-names-and-values)]\n\n#### Case-insensitive header field names\n\nHTTP messages include case-insensitive header field names. Headers are retrieved\nby name from classes implementing the `MessageInterface` in a case-insensitive\nmanner. For example, retrieving the `foo` header will return the same result as\nretrieving the `FoO` header. Similarly, setting the `Foo` header will overwrite\nany previously set `foo` header value.\n\n```php\n$message = $message->withHeader('foo', 'bar');\n\necho $message->getHeaderLine('foo');\n// Outputs: bar\n\necho $message->getHeaderLine('FOO');\n// Outputs: bar\n\n$message = $message->withHeader('fOO', 'baz');\necho $message->getHeaderLine('foo');\n// Outputs: baz\n```\n\nDespite that headers may be retrieved case-insensitively, the original case\nMUST be preserved by the implementation, in particular when retrieved with\n`getHeaders()`.\n\nNon-conforming HTTP applications may depend on a certain case, so it is useful\nfor a user to be able to dictate the case of the HTTP headers when creating a\nrequest or response.\n\n#### Headers with multiple values\n\nIn order to accommodate headers with multiple values yet still provide the\nconvenience of working with headers as strings, headers can be retrieved from\nan instance of a `MessageInterface` as an array or a string. Use the\n`getHeaderLine()` method to retrieve a header value as a string containing all\nheader values of a case-insensitive header by name concatenated with a comma.\nUse `getHeader()` to retrieve an array of all the header values for a\nparticular case-insensitive header by name.\n\n```php\n$message = $message\n    ->withHeader('foo', 'bar')\n    ->withAddedHeader('foo', 'baz');\n\n$header = $message->getHeaderLine('foo');\n// $header contains: 'bar,baz'\n\n$header = $message->getHeader('foo');\n// ['bar', 'baz']\n```\n\nNote: Not all header values can be concatenated using a comma (e.g.,\n`Set-Cookie`). When working with such headers, consumers of\n`MessageInterface`-based classes SHOULD rely on the `getHeader()` method\nfor retrieving such multi-valued headers.\n\n#### Host header\n\nIn requests, the `Host` header typically mirrors the host component of the URI, as\nwell as the host used when establishing the TCP connection. However, the HTTP\nspecification allows the `Host` header to differ from each of the two.\n\nDuring construction, implementations MUST attempt to set the `Host` header from\na provided URI if no `Host` header is provided.\n\n`RequestInterface::withUri()` will, by default, replace the returned request's\n`Host` header with a `Host` header matching the host component of the passed\n`UriInterface`.\n\nYou can opt-in to preserving the original state of the `Host` header by passing\n`true` for the second (`$preserveHost`) argument. When this argument is set to\n`true`, the returned request will not update the `Host` header of the returned\nmessage -- unless the message contains no `Host` header.\n\nThis table illustrates what `getHeaderLine('Host')` will return for a request\nreturned by `withUri()` with the `$preserveHost` argument set to `true` for\nvarious initial requests and URIs.\n\nRequest Host header<sup>[1](#rhh)</sup> | Request host component<sup>[2](#rhc)</sup> | URI host component<sup>[3](#uhc)</sup> | Result\n----------------------------------------|--------------------------------------------|----------------------------------------|--------\n''                                      | ''                                         | ''                                     | ''\n''                                      | foo.com                                    | ''                                     | foo.com\n''                                      | foo.com                                    | bar.com                                | foo.com\nfoo.com                                 | ''                                         | bar.com                                | foo.com\nfoo.com                                 | bar.com                                    | baz.com                                | foo.com\n\n- <sup id=\"rhh\">1</sup> `Host` header value prior to operation.\n- <sup id=\"rhc\">2</sup> Host component of the URI composed in the request prior\n  to the operation.\n- <sup id=\"uhc\">3</sup> Host component of the URI being injected via\n  `withUri()`.\n\n### 1.3 Streams\n\nHTTP messages consist of a start-line, headers, and a body. The body of an HTTP\nmessage can be very small or extremely large. Attempting to represent the body\nof a message as a string can easily consume more memory than intended because\nthe body must be stored completely in memory. Attempting to store the body of a\nrequest or response in memory would preclude the use of that implementation from\nbeing able to work with large message bodies. `StreamInterface` is used in\norder to hide the implementation details when a stream of data is read from\nor written to. For situations where a string would be an appropriate message\nimplementation, built-in streams such as `php://memory` and `php://temp` may be\nused.\n\n`StreamInterface` exposes several methods that enable streams to be read\nfrom, written to, and traversed effectively.\n\nStreams expose their capabilities using three methods: `isReadable()`,\n`isWritable()`, and `isSeekable()`. These methods can be used by stream\ncollaborators to determine if a stream is capable of their requirements.\n\nEach stream instance will have various capabilities: it can be read-only,\nwrite-only, or read-write. It can also allow arbitrary random access (seeking\nforwards or backwards to any location), or only sequential access (for\nexample in the case of a socket, pipe, or callback-based stream).\n\nFinally, `StreamInterface` defines a `__toString()` method to simplify\nretrieving or emitting the entire body contents at once.\n\nUnlike the request and response interfaces, `StreamInterface` does not model\nimmutability. In situations where an actual PHP stream is wrapped, immutability\nis impossible to enforce, as any code that interacts with the resource can\npotentially change its state (including cursor position, contents, and more).\nOur recommendation is that implementations use read-only streams for\nserver-side requests and client-side responses. Consumers should be aware of\nthe fact that the stream instance may be mutable, and, as such, could alter\nthe state of the message; when in doubt, create a new stream instance and attach\nit to a message to enforce state.\n\n### 1.4 Request Targets and URIs\n\nPer RFC 7230, request messages contain a \"request-target\" as the second segment\nof the request line. The request target can be one of the following forms:\n\n- **origin-form**, which consists of the path, and, if present, the query\n  string; this is often referred to as a relative URL. Messages as transmitted\n  over TCP typically are of origin-form; scheme and authority data are usually\n  only present via CGI variables.\n- **absolute-form**, which consists of the scheme, authority\n  (\"[user-info@]host[:port]\", where items in brackets are optional), path (if\n  present), query string (if present), and fragment (if present). This is often\n  referred to as an absolute URI, and is the only form to specify a URI as\n  detailed in RFC 3986. This form is commonly used when making requests to\n  HTTP proxies.\n- **authority-form**, which consists of the authority only. This is typically\n  used in CONNECT requests only, to establish a connection between an HTTP\n  client and a proxy server.\n- **asterisk-form**, which consists solely of the string `*`, and which is used\n  with the OPTIONS method to determine the general capabilities of a web server.\n\nAside from these request-targets, there is often an 'effective URL' which is\nseparate from the request target. The effective URL is not transmitted within\nan HTTP message, but it is used to determine the protocol (http/https), port\nand hostname for making the request.\n\nThe effective URL is represented by `UriInterface`. `UriInterface` models HTTP\nand HTTPS URIs as specified in RFC 3986 (the primary use case). The interface\nprovides methods for interacting with the various URI parts, which will obviate\nthe need for repeated parsing of the URI. It also specifies a `__toString()`\nmethod for casting the modeled URI to its string representation.\n\nWhen retrieving the request-target with `getRequestTarget()`, by default this\nmethod will use the URI object and extract all the necessary components to\nconstruct the _origin-form_. The _origin-form_ is by far the most common\nrequest-target.\n\nIf it's desired by an end-user to use one of the other three forms, or if the\nuser wants to explicitly override the request-target, it is possible to do so\nwith `withRequestTarget()`.\n\nCalling this method does not affect the URI, as it is returned from `getUri()`.\n\nFor example, a user may want to make an asterisk-form request to a server:\n\n```php\n$request = $request\n    ->withMethod('OPTIONS')\n    ->withRequestTarget('*')\n    ->withUri(new Uri('https://example.org/'));\n```\n\nThis example may ultimately result in an HTTP request that looks like this:\n\n```http\nOPTIONS * HTTP/1.1\n```\n\nBut the HTTP client will be able to use the effective URL (from `getUri()`),\nto determine the protocol, hostname and TCP port.\n\nAn HTTP client MUST ignore the values of `Uri::getPath()` and `Uri::getQuery()`,\nand instead use the value returned by `getRequestTarget()`, which defaults\nto concatenating these two values.\n\nClients that choose to not implement 1 or more of the 4 request-target forms,\nMUST still use `getRequestTarget()`. These clients MUST reject request-targets\nthey do not support, and MUST NOT fall back on the values from `getUri()`.\n\n`RequestInterface` provides methods for retrieving the request-target or\ncreating a new instance with the provided request-target. By default, if no\nrequest-target is specifically composed in the instance, `getRequestTarget()`\nwill return the origin-form of the composed URI (or \"/\" if no URI is composed).\n`withRequestTarget($requestTarget)` creates a new instance with the\nspecified request target, and thus allows developers to create request messages\nthat represent the other three request-target forms (absolute-form,\nauthority-form, and asterisk-form). When used, the composed URI instance can\nstill be of use, particularly in clients, where it may be used to create the\nconnection to the server.\n\n### 1.5 Server-side Requests\n\n`RequestInterface` provides the general representation of an HTTP request\nmessage. However, server-side requests need additional treatment, due to the\nnature of the server-side environment. Server-side processing needs to take into\naccount Common Gateway Interface (CGI), and, more specifically, PHP's\nabstraction and extension of CGI via its Server APIs (SAPI). PHP has provided\nsimplification around input marshaling via superglobals such as:\n\n- `$_COOKIE`, which deserializes and provides simplified access to HTTP\n  cookies.\n- `$_GET`, which deserializes and provides simplified access to query string\n  arguments.\n- `$_POST`, which deserializes and provides simplified access for urlencoded\n  parameters submitted via HTTP POST; generically, it can be considered the\n  results of parsing the message body.\n- `$_FILES`, which provides serialized metadata around file uploads.\n- `$_SERVER`, which provides access to CGI/SAPI environment variables, which\n  commonly include the request method, the request scheme, the request URI, and\n  headers.\n\n`ServerRequestInterface` extends `RequestInterface` to provide an abstraction\naround these various superglobals. This practice helps reduce coupling to the\nsuperglobals by consumers, and encourages and promotes the ability to test\nrequest consumers.\n\nThe server request provides one additional property, \"attributes\", to allow\nconsumers the ability to introspect, decompose, and match the request against\napplication-specific rules (such as path matching, scheme matching, host\nmatching, etc.). As such, the server request can also provide messaging between\nmultiple request consumers.\n\n### 1.6 Uploaded files\n\n`ServerRequestInterface` specifies a method for retrieving a tree of upload\nfiles in a normalized structure, with each leaf an instance of\n`UploadedFileInterface`.\n\nThe `$_FILES` superglobal has some well-known problems when dealing with arrays\nof file inputs. As an example, if you have a form that submits an array of files\n— e.g., the input name \"files\", submitting `files[0]` and `files[1]` — PHP will\nrepresent this as:\n\n```php\narray(\n    'files' => array(\n        'name' => array(\n            0 => 'file0.txt',\n            1 => 'file1.html',\n        ),\n        'type' => array(\n            0 => 'text/plain',\n            1 => 'text/html',\n        ),\n        /* etc. */\n    ),\n)\n```\n\ninstead of the expected:\n\n```php\narray(\n    'files' => array(\n        0 => array(\n            'name' => 'file0.txt',\n            'type' => 'text/plain',\n            /* etc. */\n        ),\n        1 => array(\n            'name' => 'file1.html',\n            'type' => 'text/html',\n            /* etc. */\n        ),\n    ),\n)\n```\n\nThe result is that consumers need to know this language implementation detail,\nand write code for gathering the data for a given upload.\n\nAdditionally, scenarios exist where `$_FILES` is not populated when file uploads\noccur:\n\n- When the HTTP method is not `POST`.\n- When unit testing.\n- When operating under a non-SAPI environment, such as [ReactPHP](http://reactphp.org).\n\nIn such cases, the data will need to be seeded differently. As examples:\n\n- A process might parse the message body to discover the file uploads. In such\n  cases, the implementation may choose *not* to write the file uploads to the\n  file system, but instead wrap them in a stream in order to reduce memory,\n  I/O, and storage overhead.\n- In unit testing scenarios, developers need to be able to stub and/or mock the\n  file upload metadata in order to validate and verify different scenarios.\n\n`getUploadedFiles()` provides the normalized structure for consumers.\nImplementations are expected to:\n\n- Aggregate all information for a given file upload, and use it to populate a\n  `Psr\\Http\\Message\\UploadedFileInterface` instance.\n- Re-create the submitted tree structure, with each leaf being the appropriate\n  `Psr\\Http\\Message\\UploadedFileInterface` instance for the given location in\n  the tree.\n\nThe tree structure referenced should mimic the naming structure in which files\nwere submitted.\n\nIn the simplest example, this might be a single named form element submitted as:\n\n```html\n<input type=\"file\" name=\"avatar\" />\n```\n\nIn this case, the structure in `$_FILES` would look like:\n\n```php\narray(\n    'avatar' => array(\n        'tmp_name' => 'phpUxcOty',\n        'name' => 'my-avatar.png',\n        'size' => 90996,\n        'type' => 'image/png',\n        'error' => 0,\n    ),\n)\n```\n\nThe normalized form returned by `getUploadedFiles()` would be:\n\n```php\narray(\n    'avatar' => /* UploadedFileInterface instance */\n)\n```\n\nIn the case of an input using array notation for the name:\n\n```html\n<input type=\"file\" name=\"my-form[details][avatar]\" />\n```\n\n`$_FILES` ends up looking like this:\n\n```php\narray (\n    'my-form' => array (\n        'name' => array (\n            'details' => array (\n                'avatar' => 'my-avatar.png',\n            ),\n        ),\n        'type' => array (\n            'details' => array (\n                'avatar' => 'image/png',\n            ),\n        ),\n        'tmp_name' => array (\n            'details' => array (\n                'avatar' => 'phpmFLrzD',\n            ),\n        ),\n        'error' => array (\n            'details' => array (\n                'avatar' => 0,\n            ),\n        ),\n        'size' => array (\n            'details' => array (\n                'avatar' => 90996,\n            ),\n        ),\n    ),\n)\n```\n\nAnd the corresponding tree returned by `getUploadedFiles()` should be:\n\n```php\narray(\n    'my-form' => array(\n        'details' => array(\n            'avatar' => /* UploadedFileInterface instance */\n        ),\n    ),\n)\n```\n\nIn some cases, you may specify an array of files:\n\n```html\nUpload an avatar: <input type=\"file\" name=\"my-form[details][avatars][]\" />\nUpload an avatar: <input type=\"file\" name=\"my-form[details][avatars][]\" />\n```\n\n(As an example, JavaScript controls might spawn additional file upload inputs to\nallow uploading multiple files at once.)\n\nIn such a case, the specification implementation must aggregate all information\nrelated to the file at the given index. The reason is because `$_FILES` deviates\nfrom its normal structure in such cases:\n\n```php\narray (\n    'my-form' => array (\n        'name' => array (\n            'details' => array (\n                'avatars' => array (\n                    0 => 'my-avatar.png',\n                    1 => 'my-avatar2.png',\n                    2 => 'my-avatar3.png',\n                ),\n            ),\n        ),\n        'type' => array (\n            'details' => array (\n                'avatars' => array (\n                    0 => 'image/png',\n                    1 => 'image/png',\n                    2 => 'image/png',\n                ),\n            ),\n        ),\n        'tmp_name' => array (\n            'details' => array (\n                'avatars' => array (\n                    0 => 'phpmFLrzD',\n                    1 => 'phpV2pBil',\n                    2 => 'php8RUG8v',\n                ),\n            ),\n        ),\n        'error' => array (\n            'details' => array (\n                'avatars' => array (\n                    0 => 0,\n                    1 => 0,\n                    2 => 0,\n                ),\n            ),\n        ),\n        'size' => array (\n            'details' => array (\n                'avatars' => array (\n                    0 => 90996,\n                    1 => 90996,\n                    2 => 90996,\n                ),\n            ),\n        ),\n    ),\n)\n```\n\nThe above `$_FILES` array would correspond to the following structure as\nreturned by `getUploadedFiles()`:\n\n```php\narray(\n    'my-form' => array(\n        'details' => array(\n            'avatars' => array(\n                0 => /* UploadedFileInterface instance */,\n                1 => /* UploadedFileInterface instance */,\n                2 => /* UploadedFileInterface instance */,\n            ),\n        ),\n    ),\n)\n```\n\nConsumers would access index `1` of the nested array using:\n\n```php\n$request->getUploadedFiles()['my-form']['details']['avatars'][1];\n```\n\nBecause the uploaded files data is derivative (derived from `$_FILES` or the\nrequest body), a mutator method, `withUploadedFiles()`, is also present in the\ninterface, allowing delegation of the normalization to another process.\n\nIn the case of the original examples, consumption resembles the following:\n\n```php\n$file0 = $request->getUploadedFiles()['files'][0];\n$file1 = $request->getUploadedFiles()['files'][1];\n\nprintf(\n    \"Received the files %s and %s\",\n    $file0->getClientFilename(),\n    $file1->getClientFilename()\n);\n\n// \"Received the files file0.txt and file1.html\"\n```\n\nThis proposal also recognizes that implementations may operate in non-SAPI\nenvironments. As such, `UploadedFileInterface` provides methods for ensuring\noperations will work regardless of environment. In particular:\n\n- `moveTo($targetPath)` is provided as a safe and recommended alternative to calling\n  `move_uploaded_file()` directly on the temporary upload file. Implementations\n  will detect the correct operation to use based on environment.\n- `getStream()` will return a `StreamInterface` instance. In non-SAPI\n  environments, one proposed possibility is to parse individual upload files\n  into `php://temp` streams instead of directly to files; in such cases, no\n  upload file is present. `getStream()` is therefore guaranteed to work\n  regardless of environment.\n\nAs examples:\n\n```\n// Move a file to an upload directory\n$filename = sprintf(\n    '%s.%s',\n    create_uuid(),\n    pathinfo($file0->getClientFilename(), PATHINFO_EXTENSION)\n);\n$file0->moveTo(DATA_DIR . '/' . $filename);\n\n// Stream a file to Amazon S3.\n// Assume $s3wrapper is a PHP stream that will write to S3, and that\n// Psr7StreamWrapper is a class that will decorate a StreamInterface as a PHP\n// StreamWrapper.\n$stream = new Psr7StreamWrapper($file1->getStream());\nstream_copy_to_stream($stream, $s3wrapper);\n```\n\n## 2. Package\n\nThe interfaces and classes described are provided as part of the\n[psr/http-message](https://packagist.org/packages/psr/http-message) package.\n\n## 3. Interfaces\n\n### 3.1 `Psr\\Http\\Message\\MessageInterface`\n\n```php\n<?php\nnamespace Psr\\Http\\Message;\n\n/**\n * HTTP messages consist of requests from a client to a server and responses\n * from a server to a client. This interface defines the methods common to\n * each.\n *\n * Messages are considered immutable; all methods that might change state MUST\n * be implemented such that they retain the internal state of the current\n * message and return an instance that contains the changed state.\n *\n * @see http://www.ietf.org/rfc/rfc7230.txt\n * @see http://www.ietf.org/rfc/rfc7231.txt\n */\ninterface MessageInterface\n{\n    /**\n     * Retrieves the HTTP protocol version as a string.\n     *\n     * The string MUST contain only the HTTP version number (e.g., \"1.1\", \"1.0\").\n     *\n     * @return string HTTP protocol version.\n     */\n    public function getProtocolVersion();\n\n    /**\n     * Return an instance with the specified HTTP protocol version.\n     *\n     * The version string MUST contain only the HTTP version number (e.g.,\n     * \"1.1\", \"1.0\").\n     *\n     * This method MUST be implemented in such a way as to retain the\n     * immutability of the message, and MUST return an instance that has the\n     * new protocol version.\n     *\n     * @param string $version HTTP protocol version\n     * @return static\n     */\n    public function withProtocolVersion($version);\n\n    /**\n     * Retrieves all message header values.\n     *\n     * The keys represent the header name as it will be sent over the wire, and\n     * each value is an array of strings associated with the header.\n     *\n     *     // Represent the headers as a string\n     *     foreach ($message->getHeaders() as $name => $values) {\n     *         echo $name . ': ' . implode(', ', $values);\n     *     }\n     *\n     *     // Emit headers iteratively:\n     *     foreach ($message->getHeaders() as $name => $values) {\n     *         foreach ($values as $value) {\n     *             header(sprintf('%s: %s', $name, $value), false);\n     *         }\n     *     }\n     *\n     * While header names are not case-sensitive, getHeaders() will preserve the\n     * exact case in which headers were originally specified.\n     *\n     * @return string[][] Returns an associative array of the message's headers.\n     *     Each key MUST be a header name, and each value MUST be an array of\n     *     strings for that header.\n     */\n    public function getHeaders();\n\n    /**\n     * Checks if a header exists by the given case-insensitive name.\n     *\n     * @param string $name Case-insensitive header field name.\n     * @return bool Returns true if any header names match the given header\n     *     name using a case-insensitive string comparison. Returns false if\n     *     no matching header name is found in the message.\n     */\n    public function hasHeader($name);\n\n    /**\n     * Retrieves a message header value by the given case-insensitive name.\n     *\n     * This method returns an array of all the header values of the given\n     * case-insensitive header name.\n     *\n     * If the header does not appear in the message, this method MUST return an\n     * empty array.\n     *\n     * @param string $name Case-insensitive header field name.\n     * @return string[] An array of string values as provided for the given\n     *    header. If the header does not appear in the message, this method MUST\n     *    return an empty array.\n     */\n    public function getHeader($name);\n\n    /**\n     * Retrieves a comma-separated string of the values for a single header.\n     *\n     * This method returns all of the header values of the given\n     * case-insensitive header name as a string concatenated together using\n     * a comma.\n     *\n     * NOTE: Not all header values may be appropriately represented using\n     * comma concatenation. For such headers, use getHeader() instead\n     * and supply your own delimiter when concatenating.\n     *\n     * If the header does not appear in the message, this method MUST return\n     * an empty string.\n     *\n     * @param string $name Case-insensitive header field name.\n     * @return string A string of values as provided for the given header\n     *    concatenated together using a comma. If the header does not appear in\n     *    the message, this method MUST return an empty string.\n     */\n    public function getHeaderLine($name);\n\n    /**\n     * Return an instance with the provided value replacing the specified header.\n     *\n     * While header names are case-insensitive, the casing of the header will\n     * be preserved by this function, and returned from getHeaders().\n     *\n     * This method MUST be implemented in such a way as to retain the\n     * immutability of the message, and MUST return an instance that has the\n     * new and/or updated header and value.\n     *\n     * @param string $name Case-insensitive header field name.\n     * @param string|string[] $value Header value(s).\n     * @return static\n     * @throws \\InvalidArgumentException for invalid header names or values.\n     */\n    public function withHeader($name, $value);\n\n    /**\n     * Return an instance with the specified header appended with the given value.\n     *\n     * Existing values for the specified header will be maintained. The new\n     * value(s) will be appended to the existing list. If the header did not\n     * exist previously, it will be added.\n     *\n     * This method MUST be implemented in such a way as to retain the\n     * immutability of the message, and MUST return an instance that has the\n     * new header and/or value.\n     *\n     * @param string $name Case-insensitive header field name to add.\n     * @param string|string[] $value Header value(s).\n     * @return static\n     * @throws \\InvalidArgumentException for invalid header names.\n     * @throws \\InvalidArgumentException for invalid header values.\n     */\n    public function withAddedHeader($name, $value);\n\n    /**\n     * Return an instance without the specified header.\n     *\n     * Header resolution MUST be done without case-sensitivity.\n     *\n     * This method MUST be implemented in such a way as to retain the\n     * immutability of the message, and MUST return an instance that removes\n     * the named header.\n     *\n     * @param string $name Case-insensitive header field name to remove.\n     * @return static\n     */\n    public function withoutHeader($name);\n\n    /**\n     * Gets the body of the message.\n     *\n     * @return StreamInterface Returns the body as a stream.\n     */\n    public function getBody();\n\n    /**\n     * Return an instance with the specified message body.\n     *\n     * The body MUST be a StreamInterface object.\n     *\n     * This method MUST be implemented in such a way as to retain the\n     * immutability of the message, and MUST return a new instance that has the\n     * new body stream.\n     *\n     * @param StreamInterface $body Body.\n     * @return static\n     * @throws \\InvalidArgumentException When the body is not valid.\n     */\n    public function withBody(StreamInterface $body);\n}\n```\n\n### 3.2 `Psr\\Http\\Message\\RequestInterface`\n\n```php\n<?php\nnamespace Psr\\Http\\Message;\n\n/**\n * Representation of an outgoing, client-side request.\n *\n * Per the HTTP specification, this interface includes properties for\n * each of the following:\n *\n * - Protocol version\n * - HTTP method\n * - URI\n * - Headers\n * - Message body\n *\n * During construction, implementations MUST attempt to set the Host header from\n * a provided URI if no Host header is provided.\n *\n * Requests are considered immutable; all methods that might change state MUST\n * be implemented such that they retain the internal state of the current\n * message and return an instance that contains the changed state.\n */\ninterface RequestInterface extends MessageInterface\n{\n    /**\n     * Retrieves the message's request target.\n     *\n     * Retrieves the message's request-target either as it will appear (for\n     * clients), as it appeared at request (for servers), or as it was\n     * specified for the instance (see withRequestTarget()).\n     *\n     * In most cases, this will be the origin-form of the composed URI,\n     * unless a value was provided to the concrete implementation (see\n     * withRequestTarget() below).\n     *\n     * If no URI is available, and no request-target has been specifically\n     * provided, this method MUST return the string \"/\".\n     *\n     * @return string\n     */\n    public function getRequestTarget();\n\n    /**\n     * Return an instance with the specific request-target.\n     *\n     * If the request needs a non-origin-form request-target — e.g., for\n     * specifying an absolute-form, authority-form, or asterisk-form —\n     * this method may be used to create an instance with the specified\n     * request-target, verbatim.\n     *\n     * This method MUST be implemented in such a way as to retain the\n     * immutability of the message, and MUST return an instance that has the\n     * changed request target.\n     *\n     * @see http://tools.ietf.org/html/rfc7230#section-5.3 (for the various\n     *     request-target forms allowed in request messages)\n     * @param mixed $requestTarget\n     * @return static\n     */\n    public function withRequestTarget($requestTarget);\n\n    /**\n     * Retrieves the HTTP method of the request.\n     *\n     * @return string Returns the request method.\n     */\n    public function getMethod();\n\n    /**\n     * Return an instance with the provided HTTP method.\n     *\n     * While HTTP method names are typically all uppercase characters, HTTP\n     * method names are case-sensitive and thus implementations SHOULD NOT\n     * modify the given string.\n     *\n     * This method MUST be implemented in such a way as to retain the\n     * immutability of the message, and MUST return an instance that has the\n     * changed request method.\n     *\n     * @param string $method Case-sensitive method.\n     * @return static\n     * @throws \\InvalidArgumentException for invalid HTTP methods.\n     */\n    public function withMethod($method);\n\n    /**\n     * Retrieves the URI instance.\n     *\n     * This method MUST return a UriInterface instance.\n     *\n     * @see http://tools.ietf.org/html/rfc3986#section-4.3\n     * @return UriInterface Returns a UriInterface instance\n     *     representing the URI of the request.\n     */\n    public function getUri();\n\n    /**\n     * Returns an instance with the provided URI.\n     *\n     * This method MUST update the Host header of the returned request by\n     * default if the URI contains a host component. If the URI does not\n     * contain a host component, any pre-existing Host header MUST be carried\n     * over to the returned request.\n     *\n     * You can opt-in to preserving the original state of the Host header by\n     * setting `$preserveHost` to `true`. When `$preserveHost` is set to\n     * `true`, this method interacts with the Host header in the following ways:\n     *\n     * - If the Host header is missing or empty, and the new URI contains\n     *   a host component, this method MUST update the Host header in the returned\n     *   request.\n     * - If the Host header is missing or empty, and the new URI does not contain a\n     *   host component, this method MUST NOT update the Host header in the returned\n     *   request.\n     * - If a Host header is present and non-empty, this method MUST NOT update\n     *   the Host header in the returned request.\n     *\n     * This method MUST be implemented in such a way as to retain the\n     * immutability of the message, and MUST return an instance that has the\n     * new UriInterface instance.\n     *\n     * @see http://tools.ietf.org/html/rfc3986#section-4.3\n     * @param UriInterface $uri New request URI to use.\n     * @param bool $preserveHost Preserve the original state of the Host header.\n     * @return static\n     */\n    public function withUri(UriInterface $uri, $preserveHost = false);\n}\n```\n\n#### 3.2.1 `Psr\\Http\\Message\\ServerRequestInterface`\n\n```php\n<?php\nnamespace Psr\\Http\\Message;\n\n/**\n * Representation of an incoming, server-side HTTP request.\n *\n * Per the HTTP specification, this interface includes properties for\n * each of the following:\n *\n * - Protocol version\n * - HTTP method\n * - URI\n * - Headers\n * - Message body\n *\n * Additionally, it encapsulates all data as it has arrived at the\n * application from the CGI and/or PHP environment, including:\n *\n * - The values represented in $_SERVER.\n * - Any cookies provided (generally via $_COOKIE)\n * - Query string arguments (generally via $_GET, or as parsed via parse_str())\n * - Upload files, if any (as represented by $_FILES)\n * - Deserialized body parameters (generally from $_POST)\n *\n * $_SERVER values MUST be treated as immutable, as they represent application\n * state at the time of request; as such, no methods are provided to allow\n * modification of those values. The other values provide such methods, as they\n * can be restored from $_SERVER or the request body, and may need treatment\n * during the application (e.g., body parameters may be deserialized based on\n * content type).\n *\n * Additionally, this interface recognizes the utility of introspecting a\n * request to derive and match additional parameters (e.g., via URI path\n * matching, decrypting cookie values, deserializing non-form-encoded body\n * content, matching authorization headers to users, etc). These parameters\n * are stored in an \"attributes\" property.\n *\n * Requests are considered immutable; all methods that might change state MUST\n * be implemented such that they retain the internal state of the current\n * message and return an instance that contains the changed state.\n */\ninterface ServerRequestInterface extends RequestInterface\n{\n    /**\n     * Retrieve server parameters.\n     *\n     * Retrieves data related to the incoming request environment,\n     * typically derived from PHP's $_SERVER superglobal. The data IS NOT\n     * REQUIRED to originate from $_SERVER.\n     *\n     * @return array\n     */\n    public function getServerParams();\n\n    /**\n     * Retrieve cookies.\n     *\n     * Retrieves cookies sent by the client to the server.\n     *\n     * The data MUST be compatible with the structure of the $_COOKIE\n     * superglobal.\n     *\n     * @return array\n     */\n    public function getCookieParams();\n\n    /**\n     * Return an instance with the specified cookies.\n     *\n     * The data IS NOT REQUIRED to come from the $_COOKIE superglobal, but MUST\n     * be compatible with the structure of $_COOKIE. Typically, this data will\n     * be injected at instantiation.\n     *\n     * This method MUST NOT update the related Cookie header of the request\n     * instance, nor related values in the server params.\n     *\n     * This method MUST be implemented in such a way as to retain the\n     * immutability of the message, and MUST return an instance that has the\n     * updated cookie values.\n     *\n     * @param array $cookies Array of key/value pairs representing cookies.\n     * @return static\n     */\n    public function withCookieParams(array $cookies);\n\n    /**\n     * Retrieve query string arguments.\n     *\n     * Retrieves the deserialized query string arguments, if any.\n     *\n     * Note: the query params might not be in sync with the URI or server\n     * params. If you need to ensure you are only getting the original\n     * values, you may need to parse the query string from `getUri()->getQuery()`\n     * or from the `QUERY_STRING` server param.\n     *\n     * @return array\n     */\n    public function getQueryParams();\n\n    /**\n     * Return an instance with the specified query string arguments.\n     *\n     * These values SHOULD remain immutable over the course of the incoming\n     * request. They MAY be injected during instantiation, such as from PHP's\n     * $_GET superglobal, or MAY be derived from some other value such as the\n     * URI. In cases where the arguments are parsed from the URI, the data\n     * MUST be compatible with what PHP's parse_str() would return for\n     * purposes of how duplicate query parameters are handled, and how nested\n     * sets are handled.\n     *\n     * Setting query string arguments MUST NOT change the URI stored by the\n     * request, nor the values in the server params.\n     *\n     * This method MUST be implemented in such a way as to retain the\n     * immutability of the message, and MUST return an instance that has the\n     * updated query string arguments.\n     *\n     * @param array $query Array of query string arguments, typically from\n     *     $_GET.\n     * @return static\n     */\n    public function withQueryParams(array $query);\n\n    /**\n     * Retrieve normalized file upload data.\n     *\n     * This method returns upload metadata in a normalized tree, with each leaf\n     * an instance of Psr\\Http\\Message\\UploadedFileInterface.\n     *\n     * These values MAY be prepared from $_FILES or the message body during\n     * instantiation, or MAY be injected via withUploadedFiles().\n     *\n     * @return array An array tree of UploadedFileInterface instances; an empty\n     *     array MUST be returned if no data is present.\n     */\n    public function getUploadedFiles();\n\n    /**\n     * Create a new instance with the specified uploaded files.\n     *\n     * This method MUST be implemented in such a way as to retain the\n     * immutability of the message, and MUST return an instance that has the\n     * updated body parameters.\n     *\n     * @param array $uploadedFiles An array tree of UploadedFileInterface instances.\n     * @return static\n     * @throws \\InvalidArgumentException if an invalid structure is provided.\n     */\n    public function withUploadedFiles(array $uploadedFiles);\n\n    /**\n     * Retrieve any parameters provided in the request body.\n     *\n     * If the request Content-Type is either application/x-www-form-urlencoded\n     * or multipart/form-data, and the request method is POST, this method MUST\n     * return the contents of $_POST.\n     *\n     * Otherwise, this method may return any results of deserializing\n     * the request body content; as parsing returns structured content, the\n     * potential types MUST be arrays or objects only. A null value indicates\n     * the absence of body content.\n     *\n     * @return null|array|object The deserialized body parameters, if any.\n     *     These will typically be an array or object.\n     */\n    public function getParsedBody();\n\n    /**\n     * Return an instance with the specified body parameters.\n     *\n     * These MAY be injected during instantiation.\n     *\n     * If the request Content-Type is either application/x-www-form-urlencoded\n     * or multipart/form-data, and the request method is POST, use this method\n     * ONLY to inject the contents of $_POST.\n     *\n     * The data IS NOT REQUIRED to come from $_POST, but MUST be the results of\n     * deserializing the request body content. Deserialization/parsing returns\n     * structured data, and, as such, this method ONLY accepts arrays or objects,\n     * or a null value if nothing was available to parse.\n     *\n     * As an example, if content negotiation determines that the request data\n     * is a JSON payload, this method could be used to create a request\n     * instance with the deserialized parameters.\n     *\n     * This method MUST be implemented in such a way as to retain the\n     * immutability of the message, and MUST return an instance that has the\n     * updated body parameters.\n     *\n     * @param null|array|object $data The deserialized body data. This will\n     *     typically be in an array or object.\n     * @return static\n     * @throws \\InvalidArgumentException if an unsupported argument type is\n     *     provided.\n     */\n    public function withParsedBody($data);\n\n    /**\n     * Retrieve attributes derived from the request.\n     *\n     * The request \"attributes\" may be used to allow injection of any\n     * parameters derived from the request: e.g., the results of path\n     * match operations; the results of decrypting cookies; the results of\n     * deserializing non-form-encoded message bodies; etc. Attributes\n     * will be application and request specific, and CAN be mutable.\n     *\n     * @return mixed[] Attributes derived from the request.\n     */\n    public function getAttributes();\n\n    /**\n     * Retrieve a single derived request attribute.\n     *\n     * Retrieves a single derived request attribute as described in\n     * getAttributes(). If the attribute has not been previously set, returns\n     * the default value as provided.\n     *\n     * This method obviates the need for a hasAttribute() method, as it allows\n     * specifying a default value to return if the attribute is not found.\n     *\n     * @see getAttributes()\n     * @param string $name The attribute name.\n     * @param mixed $default Default value to return if the attribute does not exist.\n     * @return mixed\n     */\n    public function getAttribute($name, $default = null);\n\n    /**\n     * Return an instance with the specified derived request attribute.\n     *\n     * This method allows setting a single derived request attribute as\n     * described in getAttributes().\n     *\n     * This method MUST be implemented in such a way as to retain the\n     * immutability of the message, and MUST return an instance that has the\n     * updated attribute.\n     *\n     * @see getAttributes()\n     * @param string $name The attribute name.\n     * @param mixed $value The value of the attribute.\n     * @return static\n     */\n    public function withAttribute($name, $value);\n\n    /**\n     * Return an instance that removes the specified derived request attribute.\n     *\n     * This method allows removing a single derived request attribute as\n     * described in getAttributes().\n     *\n     * This method MUST be implemented in such a way as to retain the\n     * immutability of the message, and MUST return an instance that removes\n     * the attribute.\n     *\n     * @see getAttributes()\n     * @param string $name The attribute name.\n     * @return static\n     */\n    public function withoutAttribute($name);\n}\n```\n\n### 3.3 `Psr\\Http\\Message\\ResponseInterface`\n\n```php\n<?php\nnamespace Psr\\Http\\Message;\n\n/**\n * Representation of an outgoing, server-side response.\n *\n * Per the HTTP specification, this interface includes properties for\n * each of the following:\n *\n * - Protocol version\n * - Status code and reason phrase\n * - Headers\n * - Message body\n *\n * Responses are considered immutable; all methods that might change state MUST\n * be implemented such that they retain the internal state of the current\n * message and return an instance that contains the changed state.\n */\ninterface ResponseInterface extends MessageInterface\n{\n    /**\n     * Gets the response status code.\n     *\n     * The status code is a 3-digit integer result code of the server's attempt\n     * to understand and satisfy the request.\n     *\n     * @return int Status code.\n     */\n    public function getStatusCode();\n\n    /**\n     * Return an instance with the specified status code and, optionally, reason phrase.\n     *\n     * If no reason phrase is specified, implementations MAY choose to default\n     * to the RFC 7231 or IANA recommended reason phrase for the response's\n     * status code.\n     *\n     * This method MUST be implemented in such a way as to retain the\n     * immutability of the message, and MUST return an instance that has the\n     * updated status and reason phrase.\n     *\n     * @see http://tools.ietf.org/html/rfc7231#section-6\n     * @see http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml\n     * @param int $code The 3-digit integer result code to set.\n     * @param string $reasonPhrase The reason phrase to use with the\n     *     provided status code; if none is provided, implementations MAY\n     *     use the defaults as suggested in the HTTP specification.\n     * @return static\n     * @throws \\InvalidArgumentException For invalid status code arguments.\n     */\n    public function withStatus($code, $reasonPhrase = '');\n\n    /**\n     * Gets the response reason phrase associated with the status code.\n     *\n     * Because a reason phrase is not a required element in a response\n     * status line, the reason phrase value MAY be empty. Implementations MAY\n     * choose to return the default RFC 7231 recommended reason phrase (or those\n     * listed in the IANA HTTP Status Code Registry) for the response's\n     * status code.\n     *\n     * @see http://tools.ietf.org/html/rfc7231#section-6\n     * @see http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml\n     * @return string Reason phrase; must return an empty string if none present.\n     */\n    public function getReasonPhrase();\n}\n```\n\n### 3.4 `Psr\\Http\\Message\\StreamInterface`\n\n```php\n<?php\nnamespace Psr\\Http\\Message;\n\n/**\n * Describes a data stream.\n *\n * Typically, an instance will wrap a PHP stream; this interface provides\n * a wrapper around the most common operations, including serialization of\n * the entire stream to a string.\n */\ninterface StreamInterface\n{\n    /**\n     * Reads all data from the stream into a string, from the beginning to end.\n     *\n     * This method MUST attempt to seek to the beginning of the stream before\n     * reading data and read the stream until the end is reached.\n     *\n     * Warning: This could attempt to load a large amount of data into memory.\n     *\n     * This method MUST NOT raise an exception in order to conform with PHP's\n     * string casting operations.\n     *\n     * @see http://php.net/manual/en/language.oop5.magic.php#object.tostring\n     * @return string\n     */\n    public function __toString();\n\n    /**\n     * Closes the stream and any underlying resources.\n     *\n     * @return void\n     */\n    public function close();\n\n    /**\n     * Separates any underlying resources from the stream.\n     *\n     * After the stream has been detached, the stream is in an unusable state.\n     *\n     * @return resource|null Underlying PHP stream, if any\n     */\n    public function detach();\n\n    /**\n     * Get the size of the stream if known.\n     *\n     * @return int|null Returns the size in bytes if known, or null if unknown.\n     */\n    public function getSize();\n\n    /**\n     * Returns the current position of the file read/write pointer\n     *\n     * @return int Position of the file pointer\n     * @throws \\RuntimeException on error.\n     */\n    public function tell();\n\n    /**\n     * Returns true if the stream is at the end of the stream.\n     *\n     * @return bool\n     */\n    public function eof();\n\n    /**\n     * Returns whether or not the stream is seekable.\n     *\n     * @return bool\n     */\n    public function isSeekable();\n\n    /**\n     * Seek to a position in the stream.\n     *\n     * @see http://www.php.net/manual/en/function.fseek.php\n     * @param int $offset Stream offset\n     * @param int $whence Specifies how the cursor position will be calculated\n     *     based on the seek offset. Valid values are identical to the built-in\n     *     PHP $whence values for `fseek()`.  SEEK_SET: Set position equal to\n     *     offset bytes SEEK_CUR: Set position to current location plus offset\n     *     SEEK_END: Set position to end-of-stream plus offset.\n     * @throws \\RuntimeException on failure.\n     */\n    public function seek($offset, $whence = SEEK_SET);\n\n    /**\n     * Seek to the beginning of the stream.\n     *\n     * If the stream is not seekable, this method will raise an exception;\n     * otherwise, it will perform a seek(0).\n     *\n     * @see seek()\n     * @see http://www.php.net/manual/en/function.fseek.php\n     * @throws \\RuntimeException on failure.\n     */\n    public function rewind();\n\n    /**\n     * Returns whether or not the stream is writable.\n     *\n     * @return bool\n     */\n    public function isWritable();\n\n    /**\n     * Write data to the stream.\n     *\n     * @param string $string The string that is to be written.\n     * @return int Returns the number of bytes written to the stream.\n     * @throws \\RuntimeException on failure.\n     */\n    public function write($string);\n\n    /**\n     * Returns whether or not the stream is readable.\n     *\n     * @return bool\n     */\n    public function isReadable();\n\n    /**\n     * Read data from the stream.\n     *\n     * @param int $length Read up to $length bytes from the object and return\n     *     them. Fewer than $length bytes may be returned if underlying stream\n     *     call returns fewer bytes.\n     * @return string Returns the data read from the stream, or an empty string\n     *     if no bytes are available.\n     * @throws \\RuntimeException if an error occurs.\n     */\n    public function read($length);\n\n    /**\n     * Returns the remaining contents in a string\n     *\n     * @return string\n     * @throws \\RuntimeException if unable to read.\n     * @throws \\RuntimeException if error occurs while reading.\n     */\n    public function getContents();\n\n    /**\n     * Get stream metadata as an associative array or retrieve a specific key.\n     *\n     * The keys returned are identical to the keys returned from PHP's\n     * stream_get_meta_data() function.\n     *\n     * @see http://php.net/manual/en/function.stream-get-meta-data.php\n     * @param string $key Specific metadata to retrieve.\n     * @return array|mixed|null Returns an associative array if no key is\n     *     provided. Returns a specific key value if a key is provided and the\n     *     value is found, or null if the key is not found.\n     */\n    public function getMetadata($key = null);\n}\n```\n\n### 3.5 `Psr\\Http\\Message\\UriInterface`\n\n```php\n<?php\nnamespace Psr\\Http\\Message;\n\n/**\n * Value object representing a URI.\n *\n * This interface is meant to represent URIs according to RFC 3986 and to\n * provide methods for most common operations. Additional functionality for\n * working with URIs can be provided on top of the interface or externally.\n * Its primary use is for HTTP requests, but may also be used in other\n * contexts.\n *\n * Instances of this interface are considered immutable; all methods that\n * might change state MUST be implemented such that they retain the internal\n * state of the current instance and return an instance that contains the\n * changed state.\n *\n * Typically the Host header will also be present in the request message.\n * For server-side requests, the scheme will typically be discoverable in the\n * server parameters.\n *\n * @see http://tools.ietf.org/html/rfc3986 (the URI specification)\n */\ninterface UriInterface\n{\n    /**\n     * Retrieve the scheme component of the URI.\n     *\n     * If no scheme is present, this method MUST return an empty string.\n     *\n     * The value returned MUST be normalized to lowercase, per RFC 3986\n     * Section 3.1.\n     *\n     * The trailing \":\" character is not part of the scheme and MUST NOT be\n     * added.\n     *\n     * @see https://tools.ietf.org/html/rfc3986#section-3.1\n     * @return string The URI scheme.\n     */\n    public function getScheme();\n\n    /**\n     * Retrieve the authority component of the URI.\n     *\n     * If no authority information is present, this method MUST return an empty\n     * string.\n     *\n     * The authority syntax of the URI is:\n     *\n     * <pre>\n     * [user-info@]host[:port]\n     * </pre>\n     *\n     * If the port component is not set or is the standard port for the current\n     * scheme, it SHOULD NOT be included.\n     *\n     * @see https://tools.ietf.org/html/rfc3986#section-3.2\n     * @return string The URI authority, in \"[user-info@]host[:port]\" format.\n     */\n    public function getAuthority();\n\n    /**\n     * Retrieve the user information component of the URI.\n     *\n     * If no user information is present, this method MUST return an empty\n     * string.\n     *\n     * If a user is present in the URI, this will return that value;\n     * additionally, if the password is also present, it will be appended to the\n     * user value, with a colon (\":\") separating the values.\n     *\n     * The trailing \"@\" character is not part of the user information and MUST\n     * NOT be added.\n     *\n     * @return string The URI user information, in \"username[:password]\" format.\n     */\n    public function getUserInfo();\n\n    /**\n     * Retrieve the host component of the URI.\n     *\n     * If no host is present, this method MUST return an empty string.\n     *\n     * The value returned MUST be normalized to lowercase, per RFC 3986\n     * Section 3.2.2.\n     *\n     * @see http://tools.ietf.org/html/rfc3986#section-3.2.2\n     * @return string The URI host.\n     */\n    public function getHost();\n\n    /**\n     * Retrieve the port component of the URI.\n     *\n     * If a port is present, and it is non-standard for the current scheme,\n     * this method MUST return it as an integer. If the port is the standard port\n     * used with the current scheme, this method SHOULD return null.\n     *\n     * If no port is present, and no scheme is present, this method MUST return\n     * a null value.\n     *\n     * If no port is present, but a scheme is present, this method MAY return\n     * the standard port for that scheme, but SHOULD return null.\n     *\n     * @return null|int The URI port.\n     */\n    public function getPort();\n\n    /**\n     * Retrieve the path component of the URI.\n     *\n     * The path can either be empty or absolute (starting with a slash) or\n     * rootless (not starting with a slash). Implementations MUST support all\n     * three syntaxes.\n     *\n     * Normally, the empty path \"\" and absolute path \"/\" are considered equal as\n     * defined in RFC 7230 Section 2.7.3. But this method MUST NOT automatically\n     * do this normalization because in contexts with a trimmed base path, e.g.\n     * the front controller, this difference becomes significant. It's the task\n     * of the user to handle both \"\" and \"/\".\n     *\n     * The value returned MUST be percent-encoded, but MUST NOT double-encode\n     * any characters. To determine what characters to encode, please refer to\n     * RFC 3986, Sections 2 and 3.3.\n     *\n     * As an example, if the value should include a slash (\"/\") not intended as\n     * delimiter between path segments, that value MUST be passed in encoded\n     * form (e.g., \"%2F\") to the instance.\n     *\n     * @see https://tools.ietf.org/html/rfc3986#section-2\n     * @see https://tools.ietf.org/html/rfc3986#section-3.3\n     * @return string The URI path.\n     */\n    public function getPath();\n\n    /**\n     * Retrieve the query string of the URI.\n     *\n     * If no query string is present, this method MUST return an empty string.\n     *\n     * The leading \"?\" character is not part of the query and MUST NOT be\n     * added.\n     *\n     * The value returned MUST be percent-encoded, but MUST NOT double-encode\n     * any characters. To determine what characters to encode, please refer to\n     * RFC 3986, Sections 2 and 3.4.\n     *\n     * As an example, if a value in a key/value pair of the query string should\n     * include an ampersand (\"&\") not intended as a delimiter between values,\n     * that value MUST be passed in encoded form (e.g., \"%26\") to the instance.\n     *\n     * @see https://tools.ietf.org/html/rfc3986#section-2\n     * @see https://tools.ietf.org/html/rfc3986#section-3.4\n     * @return string The URI query string.\n     */\n    public function getQuery();\n\n    /**\n     * Retrieve the fragment component of the URI.\n     *\n     * If no fragment is present, this method MUST return an empty string.\n     *\n     * The leading \"#\" character is not part of the fragment and MUST NOT be\n     * added.\n     *\n     * The value returned MUST be percent-encoded, but MUST NOT double-encode\n     * any characters. To determine what characters to encode, please refer to\n     * RFC 3986, Sections 2 and 3.5.\n     *\n     * @see https://tools.ietf.org/html/rfc3986#section-2\n     * @see https://tools.ietf.org/html/rfc3986#section-3.5\n     * @return string The URI fragment.\n     */\n    public function getFragment();\n\n    /**\n     * Return an instance with the specified scheme.\n     *\n     * This method MUST retain the state of the current instance, and return\n     * an instance that contains the specified scheme.\n     *\n     * Implementations MUST support the schemes \"http\" and \"https\" case\n     * insensitively, and MAY accommodate other schemes if required.\n     *\n     * An empty scheme is equivalent to removing the scheme.\n     *\n     * @param string $scheme The scheme to use with the new instance.\n     * @return static A new instance with the specified scheme.\n     * @throws \\InvalidArgumentException for invalid schemes.\n     * @throws \\InvalidArgumentException for unsupported schemes.\n     */\n    public function withScheme($scheme);\n\n    /**\n     * Return an instance with the specified user information.\n     *\n     * This method MUST retain the state of the current instance, and return\n     * an instance that contains the specified user information.\n     *\n     * Password is optional, but the user information MUST include the\n     * user; an empty string for the user is equivalent to removing user\n     * information.\n     *\n     * @param string $user The user name to use for authority.\n     * @param null|string $password The password associated with $user.\n     * @return static A new instance with the specified user information.\n     */\n    public function withUserInfo($user, $password = null);\n\n    /**\n     * Return an instance with the specified host.\n     *\n     * This method MUST retain the state of the current instance, and return\n     * an instance that contains the specified host.\n     *\n     * An empty host value is equivalent to removing the host.\n     *\n     * @param string $host The hostname to use with the new instance.\n     * @return static A new instance with the specified host.\n     * @throws \\InvalidArgumentException for invalid hostnames.\n     */\n    public function withHost($host);\n\n    /**\n     * Return an instance with the specified port.\n     *\n     * This method MUST retain the state of the current instance, and return\n     * an instance that contains the specified port.\n     *\n     * Implementations MUST raise an exception for ports outside the\n     * established TCP and UDP port ranges.\n     *\n     * A null value provided for the port is equivalent to removing the port\n     * information.\n     *\n     * @param null|int $port The port to use with the new instance; a null value\n     *     removes the port information.\n     * @return static A new instance with the specified port.\n     * @throws \\InvalidArgumentException for invalid ports.\n     */\n    public function withPort($port);\n\n    /**\n     * Return an instance with the specified path.\n     *\n     * This method MUST retain the state of the current instance, and return\n     * an instance that contains the specified path.\n     *\n     * The path can either be empty or absolute (starting with a slash) or\n     * rootless (not starting with a slash). Implementations MUST support all\n     * three syntaxes.\n     *\n     * If an HTTP path is intended to be host-relative rather than path-relative\n     * then it must begin with a slash (\"/\"). HTTP paths not starting with a slash\n     * are assumed to be relative to some base path known to the application or\n     * consumer.\n     *\n     * Users can provide both encoded and decoded path characters.\n     * Implementations ensure the correct encoding as outlined in getPath().\n     *\n     * @param string $path The path to use with the new instance.\n     * @return static A new instance with the specified path.\n     * @throws \\InvalidArgumentException for invalid paths.\n     */\n    public function withPath($path);\n\n    /**\n     * Return an instance with the specified query string.\n     *\n     * This method MUST retain the state of the current instance, and return\n     * an instance that contains the specified query string.\n     *\n     * Users can provide both encoded and decoded query characters.\n     * Implementations ensure the correct encoding as outlined in getQuery().\n     *\n     * An empty query string value is equivalent to removing the query string.\n     *\n     * @param string $query The query string to use with the new instance.\n     * @return static A new instance with the specified query string.\n     * @throws \\InvalidArgumentException for invalid query strings.\n     */\n    public function withQuery($query);\n\n    /**\n     * Return an instance with the specified URI fragment.\n     *\n     * This method MUST retain the state of the current instance, and return\n     * an instance that contains the specified URI fragment.\n     *\n     * Users can provide both encoded and decoded fragment characters.\n     * Implementations ensure the correct encoding as outlined in getFragment().\n     *\n     * An empty fragment value is equivalent to removing the fragment.\n     *\n     * @param string $fragment The fragment to use with the new instance.\n     * @return static A new instance with the specified fragment.\n     */\n    public function withFragment($fragment);\n\n    /**\n     * Return the string representation as a URI reference.\n     *\n     * Depending on which components of the URI are present, the resulting\n     * string is either a full URI or relative reference according to RFC 3986,\n     * Section 4.1. The method concatenates the various components of the URI,\n     * using the appropriate delimiters:\n     *\n     * - If a scheme is present, it MUST be suffixed by \":\".\n     * - If an authority is present, it MUST be prefixed by \"//\".\n     * - The path can be concatenated without delimiters. But there are two\n     *   cases where the path has to be adjusted to make the URI reference\n     *   valid as PHP does not allow to throw an exception in __toString():\n     *     - If the path is rootless and an authority is present, the path MUST\n     *       be prefixed by \"/\".\n     *     - If the path is starting with more than one \"/\" and no authority is\n     *       present, the starting slashes MUST be reduced to one.\n     * - If a query is present, it MUST be prefixed by \"?\".\n     * - If a fragment is present, it MUST be prefixed by \"#\".\n     *\n     * @see http://tools.ietf.org/html/rfc3986#section-4.1\n     * @return string\n     */\n    public function __toString();\n}\n```\n\n### 3.6 `Psr\\Http\\Message\\UploadedFileInterface`\n\n```php\n<?php\nnamespace Psr\\Http\\Message;\n\n/**\n * Value object representing a file uploaded through an HTTP request.\n *\n * Instances of this interface are considered immutable; all methods that\n * might change state MUST be implemented such that they retain the internal\n * state of the current instance and return an instance that contains the\n * changed state.\n */\ninterface UploadedFileInterface\n{\n    /**\n     * Retrieve a stream representing the uploaded file.\n     *\n     * This method MUST return a StreamInterface instance, representing the\n     * uploaded file. The purpose of this method is to allow utilizing native PHP\n     * stream functionality to manipulate the file upload, such as\n     * stream_copy_to_stream() (though the result will need to be decorated in a\n     * native PHP stream wrapper to work with such functions).\n     *\n     * If the moveTo() method has been called previously, this method MUST raise\n     * an exception.\n     *\n     * @return StreamInterface Stream representation of the uploaded file.\n     * @throws \\RuntimeException in cases when no stream is available.\n     * @throws \\RuntimeException in cases when no stream can be created.\n     */\n    public function getStream();\n\n    /**\n     * Move the uploaded file to a new location.\n     *\n     * Use this method as an alternative to move_uploaded_file(). This method is\n     * guaranteed to work in both SAPI and non-SAPI environments.\n     * Implementations must determine which environment they are in, and use the\n     * appropriate method (move_uploaded_file(), rename(), or a stream\n     * operation) to perform the operation.\n     *\n     * $targetPath may be an absolute path, or a relative path. If it is a\n     * relative path, resolution should be the same as used by PHP's rename()\n     * function.\n     *\n     * The original file or stream MUST be removed on completion.\n     *\n     * If this method is called more than once, any subsequent calls MUST raise\n     * an exception.\n     *\n     * When used in an SAPI environment where $_FILES is populated, when writing\n     * files via moveTo(), is_uploaded_file() and move_uploaded_file() SHOULD be\n     * used to ensure permissions and upload status are verified correctly.\n     *\n     * If you wish to move to a stream, use getStream(), as SAPI operations\n     * cannot guarantee writing to stream destinations.\n     *\n     * @see http://php.net/is_uploaded_file\n     * @see http://php.net/move_uploaded_file\n     * @param string $targetPath Path to which to move the uploaded file.\n     * @throws \\InvalidArgumentException if the $targetPath specified is invalid.\n     * @throws \\RuntimeException on any error during the move operation.\n     * @throws \\RuntimeException on the second or subsequent call to the method.\n     */\n    public function moveTo($targetPath);\n\n    /**\n     * Retrieve the file size.\n     *\n     * Implementations SHOULD return the value stored in the \"size\" key of\n     * the file in the $_FILES array if available, as PHP calculates this based\n     * on the actual size transmitted.\n     *\n     * @return int|null The file size in bytes or null if unknown.\n     */\n    public function getSize();\n\n    /**\n     * Retrieve the error associated with the uploaded file.\n     *\n     * The return value MUST be one of PHP's UPLOAD_ERR_XXX constants.\n     *\n     * If the file was uploaded successfully, this method MUST return\n     * UPLOAD_ERR_OK.\n     *\n     * Implementations SHOULD return the value stored in the \"error\" key of\n     * the file in the $_FILES array.\n     *\n     * @see http://php.net/manual/en/features.file-upload.errors.php\n     * @return int One of PHP's UPLOAD_ERR_XXX constants.\n     */\n    public function getError();\n\n    /**\n     * Retrieve the filename sent by the client.\n     *\n     * Do not trust the value returned by this method. A client could send\n     * a malicious filename with the intention to corrupt or hack your\n     * application.\n     *\n     * Implementations SHOULD return the value stored in the \"name\" key of\n     * the file in the $_FILES array.\n     *\n     * @return string|null The filename sent by the client or null if none\n     *     was provided.\n     */\n    public function getClientFilename();\n\n    /**\n     * Retrieve the media type sent by the client.\n     *\n     * Do not trust the value returned by this method. A client could send\n     * a malicious media type with the intention to corrupt or hack your\n     * application.\n     *\n     * Implementations SHOULD return the value stored in the \"type\" key of\n     * the file in the $_FILES array.\n     *\n     * @return string|null The media type sent by the client or null if none\n     *     was provided.\n     */\n    public function getClientMediaType();\n}\n```\n\nSince [psr/http-message version 1.1](https://packagist.org/packages/psr/http-message#1.1.0), the above interfaces have been updated to add argument type declarations.\nSince [psr/http-message version 2.0](https://packagist.org/packages/psr/http-message#2.0.0), the above interfaces have been updated to add return type declarations.\n"
  },
  {
    "path": "bylaws/001-mission-and-structure.md",
    "content": "# Mission Statement\n\nThe PHP Framework Interoperability Group (The PHP FIG) aims to advance the PHP ecosystem and promote good standards by bringing together projects and people to collaborate. It develops and publicises standards, informed by real-world experience as well as research and experimentation by itself and others, to form PHP Standard Recommendations (PSRs), PHP Evolving Recommendations (PERs), and Auxiliary Resources (ARs).\n\n# Structure\n\n## Member Projects\n\nThe PHP FIG member projects are known, publicly available PHP projects or significant PHP stakeholder organizations that have shown an interest in supporting the FIG's mission and work. Member Projects must be released projects with known production deployments, not aspirational projects. Member Projects are not required to implement any particular PSR, although are expected to give relevant PSRs due consideration.\n\nA project that exists solely as an extension or plugin of another project is not eligible. However, projects may leverage code, libraries, or frameworks from other projects without being disqualified. In cases where that distinction is unclear Project Representatives should use their best judgment to implement the spirit of this clause.\n\nAn application for membership by a project must include a current Project Representative or Core Committee member as a sponsor, the name of the proposed Project Representative, and a description of the project and its relevance to the FIG. The application once posted must be given a discussion period of at least two weeks. Once that period has passed, the sponsoring Representative may call for a Membership Vote. If it passes, the project is recognized as a Member Project with the stated Project Representative. If it does not, a project may reapply at any time if a sponsor may still be found.\n\nA Member Project may resign from the PHP FIG in writing to an official FIG public channel. Once such a statement is published and the resignation is confirmed by a secretary, a PHP project immediately ceases to be a Member Project.\n\nA former Member Project may reapply for membership at any future date.\n\n## Project Representatives\n\nThe votes of all Member Projects are cast by Project Representatives who have been authorised to do so by the Member Project. Each Project Representative is chosen solely by a Member Project and their selection is not subject to the approval of the PHP FIG. A Project Representative may be replaced by the Member Project which they represent at any time.\n\nA Member Project may not have more than one Project Representative at a time. No individual may represent more than one project at a time.\n\nA Project Representative may temporarily confer their voting rights or Working Group eligibility onto another individual who is authorised by the Member Project which they represent. This conferral must be notified to the PHP FIG by the current Project Representative, and must state the name of the temporary Project Representative and the period of time for which their temporary voting rights or eligibility will remain valid. All voting rights will automatically return to the original Project Representative at the end of the period of time stated.\n\nIf, in the judgement of the PHP FIG, a Project Representative is acting inappropriately and to the detriment of the PHP FIG's ability to meet its objectives, any member of the Core Committee may call an Expulsion Vote to request a replacement Project Representative or to expel the Member Project where replacing a Project Representative is not possible. In these instances the Member Project/Project Representative concerned may not vote. If a member project is expelled it may reapply for membership after a minimum of one year. If a project representative is voted to be replaced, they may not return to represent the project they represented at the time of the vote, or any other project, indefinitely.\n\nA Project Representative may also simultaneously serve as a Core Committee member, PSR Editor or Working Group member but not as a Secretary.\n\n## The Core Committee\n\nThe Core Committee is a twelve (12) member board of individuals recognized for their technical skill and expertise. The Core Committee is responsible for final decisions regarding what specifications FIG will consider and those that are approved. The Core Committee is responsible for ensuring a high level of quality and consistency amongst all published specifications, and that all relevant perspectives and use cases are given due consideration.\n\nCore Committee members are not permitted to also be a Secretary. A Project Representative is permitted but not required to also serve as a member of the Core Committee, however, Core Committee members are expected to consider the impact of their actions on the PHP ecosystem as a whole when acting in their capacity as a Core Committee member\n\nCore Committee members are expected to take an active interest in all topics brought before FIG.\n\n## Secretaries\n\nThe primary responsibility of a FIG Secretary is to serve as an impartial administrator of the FIG. They serve at the member projects and core committee's pleasure but act as independent and impartial adjudicators. FIG Secretaries also represent the FIG as a whole to the general community and public on matters relating to the FIG's activities.\n\nWhilst there are a number of defined functions below but they should also perform other duties as required. As the role has continuity (in that there will always be a post holder) and redundancy (There are a number of post holders in case of the absence of one) it can be ensured that responsibilities assigned to the secretary will always be completed and therefore administrative responsibilities such as vote management should always be assigned to the FIG Secretary.\n\nAll FIG Secretaries are expected to remain impartial and professional when acting in an official capacity as Secretary and should also remain aware that even when not acting in an official capacity, their actions reflect back on the PHP FIG and the FIG must not be brought into disrepute.\n\nIn order to ensure impartiality, Secretaries may not concurrently serve as a Project Representative, Core Committee Member, or Editor of a PSR. They may, however, be a member of a Working Group. Secretaries must also publicly declare all conflicts of interest for example if they are participating in a working group or are a core team member of a Member Project.\n\n### Defined functions\n\nThere are a number of defined functions that the FIG Secretaries are expected to complete but they may also, within their remit defined in the above overarching role, perform other duties as necessary.\n\n* Managing the website\n* GitHub organization and repository administration\n* Tallying votes and managing the voting system\n* Tracking member project activity\n* Ensuring bylaws are being followed\n* Clarifying any interpretation of bylaw text, subject to a lack of objection from Core Committee members and Project Representatives**\n* Ensure that relevant marketing mediums (e.g. Twitter and Facebook) are kept professional, up to date and impartial\n* Moderate discussions on GitHub, the mailing list, IRC channels and other official communication mediums to ensure that an appropriate environment is maintained. This includes the ability to restrict posting and impose bans with the exception that they cannot permanently ban or restrict a Core Committee member or Project Representative\n* Should there be a FIG meeting at a conference or other ad hoc gathering any Secretary in attendance should take notes to report back to the mailing list\n* Acting throughout their term essentially as Developer Advocates for the PHP FIG\n\n ** Should any bylaw clarification by challenged or objected to by three or more project representatives or core committee members it must go to a vote. If between Secretaries consensus cannot be found on a clarification, it must go to a full vote.\n\n### Access and Abilities\n\nFIG Secretaries will be given access to the GitHub organisation as \"Owners\" and full (admin) access to anything relating to official website, marketing and communication mediums including but not limited to the domain, Twitter, IRC channel, packagist.org packages and mailing list in order to allow them to complete their duties and ensure that FIG mediums are managed by representatives elected by the PHP FIG.\n\nAlso, whilst not full members themselves, they have the ability to start any vote, but not cast any votes. However it should be noted that any vote started by one FIG Secretary must be managed and tallied by a different secretary to ensure impartiality.\n\n## Working Groups\n\nThe majority of the PHP FIG's work is carried out by Working Groups, under the guidance and support of the Core Committee.  Members of a Working Group are expected to be actively engaged in the Working Group's efforts.\n\nEvery Working Group has a single Editor, who is responsible for the smooth operation of the Working Group's mission and has final authority on the group's output.  Editors are appointed by the Core Committee.  Editors are responsible for managing the development of the Working Group's efforts; for representing the Working Group in discussions with the rest of the PHP FIG; for coordinating other contributors; and for working with other members of the Working Group and Core Committee as appropriate to see an effort through the appropriate process.  Any individual may be an Editor, provided they are not also a Secretary. If the Editor of a proposal is missing for more than 45 days without notice then the Core Committee may agree upon a new Editor. The Editor is the final authority on the output of a Working Group's efforts, unless otherwise noted.\n\nMembers of the general public may apply to join the Working Group at any time, subject to the approval of the Editor, in their judgment, the applicant's experience and perspective would be particularly valuable to the development of the Working Group's efforts. A Working Group member may be removed at any time by the Editor if, in their judgment, the individual has become inactive for more than 30 days or if the individual is disruptive to the smooth functioning of the Working Group.\n\nProject Representatives or a proxy they specify may apply to join the Working Group at any time, unless objected to by the Editor if, in their judgment, the applicant has little value to offer the process and/or would be disruptive to the smooth functioning of the Working Group.\n\nAn individual may be the Editor for more than one Working Group simultaneously.\n\n### Full Working Group\n\nA Full Working Group consists of an Editor, a Sponsor, and at least three other individuals.  A Sponsor must be a member of the Core Committee.  In a Full Working Group, the Editor and Sponsor share membership management responsibilities.\n\nAn individual may be the Sponsor of more than one Working Group simultaneously.\n\nMultiple other Core Committee members may also be on the working group if they wish.\n\n### Limited Working Group\n\nA Limited Working Group consists of an Editor and at least two other individuals.  No Sponsor is required.  Any individual may be the Editor or member of a Limited Working Group, with the exception that the Editor may not also be a Secretary.\n\n### Working Group Management\n\nWorking Groups are created by an Entrance Vote of the Core Committee.  The Entrance Vote includes the appointment of an Editor and, if applicable, the Sponsor.\n\nThe Editor and, if applicable, the Sponsor may at any time notify the Core Committee that a given Working Group's task is complete.  At that point the Working Group is dissolved, by Implicit Approval.  If necessary, a Decision Vote to appoint a new Editor may be held.\n\nThe Editor or Sponsor of a Working Group may step down at any time by informing the Core Committee via the mailing list.  If the departing individual specifies an intended replacement from the Working Group membership, that individual will assume the vacant role immediately, by Implicit Approval.  If necessary, a Decision Vote to appoint a new Editor or Sponsor may be held following a suitable nomination period.\n\nShould a Working Group be missing an Editor for 60 days; be missing a Sponsor for 60 days; have insufficient active members for 60 days; or show no signs of activity for six months, then the Core Committee may hold a Decision Vote to name a new Editor or Sponsor, following a suitable nomination process.  One of the options in that Decision Vote must be to dissolve the Working Group.  If no suitable candidates for Editor or Sponsor may be found, then the Working Group is automatically dissolved.\n\nIf a Working Group is dissolved, a new Working Group covering the same scope may be formed at a later date through a new Entrance Vote.\n\nThe Secretaries will ensure that the Working Group is provided with necessary resources to support their efforts, such as a dedicated GitHub repository, mailing list, chat room, or similar such tools.\n\n## Maintainers\n\nThe Core Committee is ultimately responsible for all artifacts produced by the PHP FIG.  However, in the case of artifacts that are intended to change over time, the Core Committee may delegate that responsibility to a Maintainer for one or more related artifacts.\n\nEvolving artifacts follow Semantic Versioning.  If it is unclear if a given change would qualify as a bugfix vs a minor release, the Maintainer will assume minor release.\n\n* For changes that would qualify as bugfix releases, the Maintainer may issue a new release of the artifact at any time.\n* For changes that would qualify as minor releases, the Maintainer must notify the Core Committee via a post to the mailing list of an Intent to Merge a given change.  The Intent to Merge is subject to Implicit Approval with an Approval Vote if necessary.\n* For changes that would qualify as major releases, the release is subject to a mandatory Approval Vote from the Core Committee.\n\nThe Editor of a Working Group is automatically the Maintainer of that Working Group's effort and output.\n\nThe Maintainer of a given artifact is appointed by the Core Committee by Approval Vote.  Once a given artifact is created, the Maintainer may step down and name a replacement Maintainer at any time with Implicit Approval.  If necessary, a Decision vote to appoint a new Maintainer may be held following a suitable nomination period.\n\nThe Secretaries will ensure that the Maintainer has the necessary access and resources to develop the artifact, such as access to a GitHub repository, mailing list, chat room, or similar such tools.\n\n## Artifacts\n\nThe PHP FIG produces three primary forms of output artifact that are subject to established workflow processes.  This list is not exhaustive of the activity or publication that the PHP FIG may engage in.\n\n* A PHP Standard Recommendation (PSR) defines an interoperability standard that establishes a \"contract\" between providers and consumers.  The goal of any PSR is to encourage or facilitate cross-project collaboration and standardization.  PSRs are developed to a particular end-state and, once approved, are considered frozen in time to provide a stable and reliable target for implementers, with certain exceptions as specified in the PSR Amendments and PSR Evolution bylaws.  PSRs are developed by a Working Group.\n* A PHP Evolving Recommendation (PER) is a formal definition of best practices, references, guidelines, universal tooling, or tools to support the same.  They may evolve over time as the PHP language and ecosystem evolves.  PERs are developed by a Working Group.\n* Auxiliary Resources (ARs) are additional tools, code libraries, or examples that relate to or support a PSR or PER.  Examples include common partial implementations of a PSR or PER, \"no-op\" implementations, or testing utilities for PSR or PER implementations.  All ARs must directly relate to one or more PSRs or PERs.  An AR is developed by a Maintainer.\n"
  },
  {
    "path": "bylaws/002-psr-workflow.md",
    "content": "# PHP Standard Recommendation (PSR) Workflow\n\n## Pre-Draft\n\nThe goal of the Pre-Draft stage is to determine whether a majority of the PHP FIG is interested in publishing a PSR for a proposed concept.\n\nInterested parties may discuss a possible proposal, including possible implementations, by whatever means they feel is appropriate. That includes informal discussion on official FIG discussion mediums of whether or not the idea has merit and is within the scope of the PHP FIG's goals.\n\nOnce those parties have determined to move forward, they must form a Full Working Group.\n\nThe proposal is not required to be fully developed at this point, although that is permitted. At minimum, it must include a statement of the problem to be solved and basic information on the general approach to be taken. Further revision and expansion is expected during the Draft Phase.\n\nThe Sponsor may then call for an Entrance Vote of the Core Committee to enquire whether the Core Committee is generally interested in publishing a PSR for the proposed subject, even if they disagree with the details of the proposal.\n\nIf the vote passes, the proposal officially enters Draft stage. The proposal receives a PSR number incremented from the highest numbered PSR which has passed the Entrance Vote, regardless of the status of that PSR.\n\nThe Working Group may continue to work on the proposal during the complete voting period.\n\n## Draft\n\nThe goal of the Draft stage is to discuss and polish a PSR proposal up to the point that it can be considered for review by the FIG Core Committee.\n\nIn Draft stage, members of the Working Group may make any changes they see fit via pull requests, comments on GitHub, Mailing List threads, chat, and similar tools. Change here is not limited by any strict rules, and fundamental rewrites are possible if supported by the Editor. Alternative approaches may be proposed and discussed at any time. If the Editor and Sponsor are convinced that an alternative proposal is superior to the original proposal, then the alternative may replace the original. Working Group members are expected to remain engaged throughout the Draft Phase. Discussions are public and anyone, regardless of FIG affiliation, is welcome to offer constructive input. During this phase, the Editor has final authority on changes made to the proposed specification.\n\nAll knowledge gained during Draft stage, such as possible alternative approaches, their implications, pros and cons etc. as well as the reasons for choosing the proposed approach must be summarized in the meta document. The purpose of this rule is to prevent circular discussions or alternative proposals from reappearing once they have been decided upon.\n\nWhen the Editor and Sponsor agree that the proposal is ready and that the meta document is objective and complete, the Editor may call for a Readiness Vote of the Working Group to determine if the specification is substantively complete and ready for trial implementations.\n\nIf the vote passes, the proposal officially enters Review Phase. If it does not, it remains in Draft Phase.\n\n## Review\n\nThe Review Phase is an opportunity for the community to experiment with a reasonably fixed target to evaluate a proposal's practicality. At this stage, the Sponsor is the final authority on changes to the specification as well as any decisions to move the proposal forward or backward, however, the Editor may veto proposed changes they believe are harmful to the design of the specification.\n\nDuring this phase, trial implementations of the specification are expected and encouraged. Changes to the specification are limited to those directly informed by trial implementations, wording, typos, clarification, etc. Major changes are not permitted in this phase. If the development of trial implementations demonstrates the need for major changes then the specification must be pushed back to Draft Phase. Any incompatible change that would require significant effort for trial implementations to adjust for qualifies as a major change. Small to moderate incompatible changes do not necessarily mandate a return to Draft Phase.\n\nUnless a proposal is moved to Draft stage again, it must remain in Review stage for a minimum of four weeks and until two independent viable trial implementations can be demonstrated. The responsibility for finding such trial implementations and presenting them to the Core Committee lies with the Working Group, and especially the Editor and Sponsor. As not all specifications are PHP interfaces where the definition of \"implementation\" is self-evident, the Sponsor should use good faith judgement to determine when that is the case. Any member of the Core Committee may object to a given trial implementation as irrelevant or insufficient with due cause.\n\nOnce four weeks have passed and two viable trial implementations can be demonstrated, the Sponsor may call an Acceptance Vote. If the Acceptance Vote fails, the specification may remain in Review.\n\n## Accepted\n\nIf the Acceptance Vote passes, then the proposal officially becomes an accepted PSR. At this time the Working Group is automatically dissolved.  The Editor of the PSR automatically becomes the Maintainer of the specification should typos, changes or Errata on the specification be raised.  The Editor is also automatically the Maintainer of any artifacts the Working Group has produced, such as utility libraries.\n\n## Erratas\n\nIf an incongruence or the need for clarifications arise after the PSR acceptance, it is still possible to amend the document with an errata. The Maintainer of the PSR has the power to handle those situations, but any meaningful change has to go through an Errata vote before merging. Typos and any other edits that do not change the meaning of the text do not fall in this category, and can be merged by the Secretaries at will.\n\nErrata clarifications may only be added to the meta document, not to the spec itself, as items in their own section.  The spec itself may only be minimally edited to point readers toward a relevant errata if appropriate.\n\n## Deprecated\n\nA Deprecated PSR is one that has been approved, but is no longer considered relevant or recommended. Typically, this is due to the PSR being superseded by a new version, but that is not required.\n\nA PSR may be Deprecated explicitly as part of the Acceptance Vote for another PSR. Alternatively, it may be marked Deprecated by a Deprecation Vote.\n\n## Abandoned\n\nAn Abandoned PSR is one that is not actively being worked upon.  Should the Working Group for the PSR be dissolved, the PSR is automatically marked as Abandoned.\n\nOnce a PSR is in \"Abandoned\" stage it may only once again be moved to Draft after a fresh Entrance vote by the Core Committee following the same procedure as if it was a pre-draft, except it may retain its previously assigned number. If the aims of the PSR differ from the original entrance vote, it is up to the discretion of the Core Committee whether it should be considered a fresh PSR or a restart of activity on the Abandoned PSR.\n\n## Project Referendum\n\nAt any time the Editor of a PSR in Draft or Review Phase may call for a non-binding Referendum of Project Representatives on the current state of a PSR.  Such a Referendum may be called multiple times if appropriate as the PSR evolves, or never, at the Editor's discretion.  The Core Committee may also require such a Referendum as a condition of an Acceptance Vote if appropriate.  Referendum results are non-binding but the Working Group and Core Committee are expected to give the results due consideration.\n"
  },
  {
    "path": "bylaws/003-per-workflow.md",
    "content": "# PHP Evolving Recommendation Workflow\n\n## Formation\n\nThe goal of the Formation stage is to determine whether a majority of the PHP FIG is interested in establishing a PER Working Group for a proposed concept.\n\nInterested parties may discuss a possible proposal, including possible implementations, by whatever means they feel is appropriate. That includes informal discussion on official FIG discussion mediums of whether or not the idea has merit and is within the scope of the PHP FIG's goals.\n\nOnce those parties have determined to move forward, they must form a Limited Working Group.  However, the Core Committee may require that a specific PER requires a Full Working Group in cases of particularly high impact to the larger ecosystem in order to encourage greater community participation.\n\nThe proposal is not required to be fully developed at this point, although that is permitted. At minimum, it must include a statement of the problem to be solved, the scope of the PER Working Group, and the artifacts it expects to produce.\n\nThe Editor (for a Limited Working Group) or Sponsor (for a Full Working Group) may then call for an Entrance Vote of the Core Committee to enquire whether the Core Committee is generally interested in maintaining a PER for the proposed subject, even if they disagree with the details of the proposal.\n\nIf the vote passes, the proposal officially enters Draft stage. The proposal is given a unique descriptive name (such as \"Coding Standards\", \"Documentation\", etc.).\n\n## Development\n\nOnce established, the PER Working Group may collaborate in whatever way they see fit via pull requests, comments on GitHub, Mailing List threads, real-time chat, and similar tools.  The Working Group must maintain a meta document including considered but rejected approaches, the reasons for various decisions, etc.  The meta document is considered part of the Working Group's output, and must be tagged along with the main artifacts of the Working Group.\n\nDiscussions are public and anyone, regardless of FIG affiliation, is welcome to offer constructive input. The Editor has final authority on changes made to the Working Group's output.\n\n## Pre-Releases\n\nPrior to the 1.0.0 release of the PER, the Editor may make alpha, beta, or 0.x releases of any artifact at any time.  These releases are explicitly unstable, and MUST be treated as unsupported by FIG or the Working Group.  They are not subject to Core Committee approval.\n\n## Releases\n\nThe Editor of a PER artifact may release bugfix releases at any time.\n\nFor any new release that would be minor or major according to Semantic Versioning (whether text or code), the Editor must first call for a Readiness Vote of the Working Group.  If the Readiness Vote passes, the Editor in capacity as Maintainer may inform the Core Committee of an Intent to Release as specified in the Maintainers section.\n\nThe Core Committee must approve any major releases from 1.0.0 onwards.\n"
  },
  {
    "path": "bylaws/004-votes.md",
    "content": "# Votes\n\nThere are a number of different types of vote, each of which has its own rule set and expected threshold. Unless otherwise specified, all votes take place over a period of two weeks, or until all eligible voters have voted, whichever comes first, and votes are public. Explicit abstentions (+0) will count toward quorum, if applicable, but do not count toward majority.\n\nNon-trivial votes should be preceded by at least two weeks of discussion, although no formal discussion mechanism is required.\n\nThe mechanics of voting (email, forum, any conventional subject lines, etc.) may be established and publicized by the Secretaries.\n\nVotes may be changed at will until the end of the voting period.\n\nIn some cases, votes may overlap such that an individual would become eligible to cast a vote only as a result of another overlapping vote, such as a membership vote. In all cases, eligibility to vote will be defined based on membership at the moment a given vote starts. For nominations for Secretary or Core Committee member, eligibility to vote will be defined based on membership at the moment the nominating period begins.\n\nA secretary may trigger any type of vote if appropriate and necessary.\n\nRounding of quorums and majorities would occur such that:\n\n* A vote requiring a quorum of 1/3 of an electorate of 20, 21 or 22 members would require 7 votes to be cast\n* A vote requiring a quorum of 1/3 of an electorate of 23, 24 or 25 members would require 8 votes to be cast\n* A vote requiring a 50% majority with 10 or 11 votes cast would require 6 or more to be in favour to pass\n* A vote requiring a 50% majority with 12 or 13 votes cast would require 7 or more to be in favour to pass\n\n## Vote Types\n\nMost votes are held by the Core Committee, and fall into one of two categories: Approval or Decision.  Unless otherwise specified, any member of the Core Committee or a Secretary may call an Approval or Decision Vote.\n\n### Approval Vote\n\nAn Approval Vote is a yes-or-no question, in which case the status quo (voting \"no\") produces a stable outcome. Only Core Committee members may vote, either For (+1), Against (-1), or Abstain (+0). Quorum is 50%. A 2/3 majority is required for passage.\n\n### Decision Vote\n\nA Decision Vote is used to select between two or more mutually-exclusive courses of action, in which case the status quo is not stable (e.g., a vacancy is being filled).  Only Core Committee members may vote.  A Decision Vote will be conducted using Single Transferable Vote with a single-winner.  Quorum is 50%.\n\n## Entrance Vote\n\nAn Entrance Vote is called by the Sponsor of a proposed PSR.  It follows Approval Vote procedures.\n\n## Readiness Vote\n\nA Readiness Vote is called by the Editor of a proposed PSR in Draft Phase. Only members of the PSR's Working Group (including the Editor and Sponsor) may vote, either For (+1), Against (-1), or Abstain (+0). Quorum is 50%. A 2/3 majority is required for passage.\n\n## Acceptance Vote\n\nAn Acceptance Vote is called by the Sponsor of a proposed PSR in the Review Phase. It follows Approval Vote procedures.\n\n## Errata Vote\n\nAn Errata Vote is called by the Editor of an approved PSR, or a Secretary if the Editor is no longer available. It follows Approval Vote procedures.\n\n## Deprecation Vote\n\nA Deprecation Vote is called by any Core Committee Member. It follows Approval Vote procedures.\n\n## Abandonment Vote\n\nAn Abandonment Vote is called by any Secretary or Core Committee Member. It follows Approval Vote procedures.\n\n## Implicit Approval\n\nAt times, routine Working Group activity is subject to the approval of the Core Committee but in most cases is not sufficiently controversial to warrant a full vote.  In such cases, an individual may declare an Intent to take an action.  If no member of the Core Committee objects within seven days, the action is implicitly approved.\n\nAny member of the Core Committee may request during that seven-day period that the change be put to a vote.  If any member does so, the action is put to an Approval Vote or Decision Vote (as appropriate to the situation) to determine if it is accepted or not.\n\n## Membership Vote\n\nA Membership Vote is called by any Project Representative and consists of a separate concurrent vote by the Core Committee and Project Representatives.\n\nFor the Core Committee vote, Core Committee members may vote, either For (+1), Against (-1), or Abstain (+0). Quorum is 50%. A 50% majority is required for passage.\n\nFor the Project Representative vote, Project Representatives may vote, either For (+1), Against (-1), or Abstain (+0). There is no quorum. A 50% majority is required for passage.\n\nBoth the Core Committee and Project Representative votes must pass for the Membership Vote to be approved. If an individual is serving as both a Project Representative and Core Committee member, they are ineligible to vote in the Project Representative vote. If an individual is on the Core Committee and they are to be the Project Represenative for the project in question, they are not eligible to vote.\n\n## Expulsion vote\n\nAn Expulsion Vote is called by any Secretary or Core Committee member and consists of a separate concurrent vote by the Core Committee and Project Representatives.\n\nFor the Core Committee vote, Core Committee members may vote, either For (+1), Against (-1), or Abstain (+0). Quorum is 50%. A 50% majority is required for passage.\n\nFor the Project Representative vote, Project Representatives may vote, either For (+1), Against (-1), or Abstain (+0). There is no quorum. A 50% majority is required for passage.\n\nBoth the Core Committee and Project Representative votes must pass for the Expulsion Vote to be approved. If an individual is serving as both a Project Representative and Core Committee member, they are ineligible to vote in the Project Representative vote. The Project Representative that is the subject, or whose project is the subject, of the Expulsion Vote is not eligible to vote.\n\n## Recall Vote\n\nA Recall Vote is called by any two of a Secretary, Core Committee member, and Project Representative, and consists of a separate concurrent vote by the Core Committee and Project Representatives.\n\nFor the Core Committee vote, Core Committee members may vote, either For (+1), Against (-1), or Abstain (+0). Quorum is 50%. A 2/3 majority is required for passage.\n\nFor the Project Representative vote, Project Representatives may vote, either For (+1), Against (-1), or Abstain (+0). There is no quorum. A 2/3 majority is required for passage.\n\nBoth the Core Committee and Project Representative votes must pass for the Recall Vote to be approved. If an individual is serving as both a Project Representative and Core Committee member, they are ineligible to vote in the Project Representative vote. If a Core Committee member is the subject of the Recall Vote, they are not eligible to vote.\n\n## Bylaw Votes\n\nA vote to amend any FIG bylaw is called by a Secretary, and consists of a separate concurrent vote by the Core Committee and Project Representatives.\n\nFor the Core Committee vote, Core Committee members may vote, either For (+1), Against (-1), or Abstain (+0). Quorum is 50%. A 2/3 majority is required for passage.\n\nFor the Project Representative vote, Project Representatives may vote, either For (+1), Against (-1), or Abstain (+0). There is no quorum. A 2/3 majority is required for passage.\n\nBoth the Core Committee and Project Representative votes must pass for the Bylaw Vote to be approved. If an individual is serving as both a Project Representative and Core Committee member, they are ineligible to vote in the Project Representative vote.\n\n## Other Votes\n\nShould a need arise to call a formal vote for any situation not described here, the vote will be called by a Secretary. It consists of a separate vote by the Core Committee and Project Representatives.\n\nFor the Core Committee vote, Core Committee members may vote, either For (+1), Against (-1), or Abstain (+0). Quorum is 50%. A 2/3 majority is required for passage.\n\nFor the Project Representative vote, Project Representatives may vote, either For (+1), Against (-1), or Abstain (+0). There is no quorum. A 50% majority is required for passage.\n\nBoth the Core Committee and Project Representative votes must pass for the Vote to be approved. If an individual is serving as both a Project Representative and Core Committee member, they are ineligible to vote in the Project Representative vote.\n"
  },
  {
    "path": "bylaws/005-elections-and-vacancies.md",
    "content": "# Elections\n\n## Election Calendar\n\nBoth Secretaries and Core Committee members are elected for two year terms with votes staggered eight months apart. One election is held in January of even numbered years, one election is held in September of even numbered years, and one election is held in May of odd numbered years. For example there would be elections in January 2026, September 2026 and May 2027. Each regular election includes a single Secretary and four (4) Core Committee members, plus any potential unplanned vacancies.\n\nThe election calendar will be established by the Secretaries at least one week before the start of the election month. Nominations must run for a minimum of seven (7) days. The vote will open immediately upon the end of the nomination period and must run for fourteen (14) days. The new Secretary and Core Committee members will take office at 5pm UTC time on the last Sunday of the month, and the voting period must conclude at least 24 hours prior to that.\n\nThe election process will be overseen by either of the Secretaries whose term is not expiring, and both the Secretary and Core Committee elections may be overseen by the same Secretary or different Secretaries.\n\n## Eligibility\n\nAny individual may run for election as Secretary, including the outgoing Secretary. If they are a Core Committee Member or PSR Editor and are elected they must resign between the vote ending and taking office.\n\nAny individual may run for election as a Core Committee member, including the outgoing Core Committee member. If they are a Secretary and are elected they must resign between the vote ending and taking office.\n\n## Nomination\n\nCandidates for Secretary or the Core Committee must be nominated/proposed by an existing Project Representative or FIG Secretary to be considered, and must publicly accept their nomination in order to be valid. Prospective candidates may seek nominations in any way they see fit.\n\n## Electorate\n\nAny Project Representative or Core Committee member is eligible to to vote on Secretary candidates.\n\nAny individual that has posted a non-trivial message in the official FIG venue (mailing list, forum, etc.) at least five (5) times within the past calendar year as of the start of nominations or any Project Representative is eligible to vote on Core Committee candidates.\n\nThe Secretaries whose terms are not expiring have final jurisdiction to determine eligibility.\n\n## Voting\n\nThe election will be conducted using Single Transferable Vote with specific algorithms being maintained by the Secretaries. If multiple seats are open (either for Core Committee membership or due to a vacancy) then the open seats with the longest term will go to first candidate(s) to reach the required quota.\n\n## Recall Votes\n\nShould a Secretary or Core Committee member be determined to be acting with gross negligence or in a way that undermines the FIG's mission or good standing, a Recall Vote may be called by any two of a Secretary, Core Committee member, and Project Representative. Any such vote must be preceded by at least a two week discussion period. The vote will be overseen by a Secretary other than the subject of the Recall Vote. Should the vote pass the individual in question is removed immediately. If it does not pass the matter is considered closed and a new vote may not be called for the same incident, if applicable.\n\n# Vacancies\n\n## Editor Vacancies\n\nShould the Editor of a PSR under consideration resign or become inactive for a period of 60 days, the Sponsor may select a new Editor subject to rejection by the Core Committee. Current members of the Working Group should be given preference. If no new Editor is named within 30 days from the vacancy notice then the PSR can be marked as Abandoned.\n\n## Sponsor Vacancies\n\nShould the Sponsor of a PSR under consideration resign or become inactive for a period of 60 days, the Editor may select a new Sponsor subject to rejection by the Core Committee. If no new Sponsor is named within 30 days from the vacancy notice then the PSR can become Abandoned.\n\n## Secretary Vacancies\n\nShould a Secretary resign or be removed due to a Recall vote, an existing Secretary shall call a special election for a new Secretary following the same protocols as for a normal election. The newly elected Secretary will serve out the remainder of the term for the seat filled.\n\nShould the vacancy occur less than four months before the next regular election month, the seat may be left vacant until the next election at the discretion of the other Secretaries and Core Committee. In that case, the second-highest voted candidate will assume the available seat with less time remaining in its term. Should two Secretary positions become vacant simultaneously a special election must be called immediately for both seats.\n\n## Core Committee Vacancy\n\nShould a Core Committee member resign or be removed due to a Recall Vote, the Secretaries shall call a special election for a new Core Committee member following the same protocols as for a normal election. The newly elected Core Committee member will serve out the remainder of the term for the seat filled.\n\nShould the vacancy occur less than four months before the next regular election month, the seat may be left vacant until the next election at the discretion of the Secretaries and Core Committee. In that case, the fifth-highest voted candidate will assume the available seat with less time remaining in its term.\n"
  },
  {
    "path": "bylaws/006-licensing-policies.md",
    "content": "Licensing Policies\n==================\n\n## 1. Copyright Ownership\n\n1. Anytime the copyright owner of code, documentation or otherwise is listed it\n   must be shown as \"PHP Framework Interoperability Group and its contributors.\"\n\n## 2. Code\n\n1. All PHP FIG code must be licensed under the MIT license.\n\n2. Code includes any pure PHP files (including but not limited to classes,\n   functions, interfaces and procedural code), as well as any code inside of\n   examples, tutorials, supporting documents, website code and the PSRs themselves.\n\n## 3. Documentation\n\nAll remaining non-code items must be licensed under the Creative Commons BY 3.0\nlicense. Attribution policies will be defined in the bylaws based on the type\nof asset created.\n"
  },
  {
    "path": "bylaws/007-psr-amendments.md",
    "content": "Amendments\n==========\n\nFollowing the rules of the [workflow bylaw], once a PSR has been \"Accepted\" the PSR meaning\ncannot change, backwards compatibility must remain at 100%, and any confusion that arises from\noriginal wording can be clarified through errata.\n\nThe rules for errata are covered in the [workflow bylaw], and only allow backwards compatible\nclarification to be added to the meta document. Sometimes, modifications will be necessary in PSR\ndocument itself, and this document outlines those cases.\n\n## 1. Deprecation and Replacement\n\nIf a PSR is found to require substantive updates or errata is no longer able to clarify confusion,\nthen the PSR must be replaced, following the workflow set out in [workflow bylaw].\n\nThe original PSR may at some point in time be deprecated, as specified in the [votes bylaw].\n\nOnce a vote to deprecate a PSR and supersede it with another PSR has passed, the deprecated PSR must\nbe marked as such in the original document and a link should be placed in the body.\n\nFor example, the following Markdown be placed at the very top of the relevant standard file in the\nofficial PHP FIG GitHub repo `fig-standards`.\n\n> **Deprecated** - As of 2014-12-30 PSR-0 has been marked as deprecated. [PSR-4] is now recommended\nas an alternative.\n> [PSR-4]: http://php-fig.org/psr/psr-4\n\n## 2. Dependencies\n\nAs documents are expected to be replaced rather than amended, dependencies on\nother PSR's should be avoided whenever possible. For instance, the following is\nno longer permitted:\n\n> - Namespaces and classes MUST follow PSR-0.\n\nInstead - if a dependency is considered necessary by the working group creating it - then the following\nexample can be used:\n\n> - Namespaces and classes MUST follow an autoloading PSR: [ [PSR-0] ].\n\nThe outer set of square brackets denote a \"dependency list\", which is a list of PSRs\nthat are considered a compatible dependency.\n\nWhen more PSR's are added to the \"dependency list\" the same example would look like this:\n\n> - Namespaces and classes MUST follow an autoloading PSR: [ [PSR-0], [PSR-4] ].\n\nNew PSR's can be added to the \"dependency list\", but old PSR's can never be removed as this would break\nbackwards compatibility.\n\n## 3. Acceptable Amendments\n\nOther than updating the \"dependency list\", there are two other potentially acceptable amendment scenarios\nwhich do not require their own special vote.\n\n### 3.1. Annotations\n\nIf Errata is added which is deemed important enough by whoever is initiating the errata vote,\nannotations may be placed in or near the offending line so that readers know to view the errata for\nmore information, with a link containing an anchor to that specific piece of errata.\n\n> - Something confusing about where brackets go. [cf. [errata](foo-meta.md#errata-1-foo)]\n\nThis will be done as part of the errata vote, not its own.\n\n### 3.2. Formatting & Typos\n\nIf formatting is broken for any reason then changing formatting must not be considered a\nchange to the document. These can be merged or pushed without hesitation by a secretary, as long as they\ndon't change anything of any meaning or syntax.\n\nSome typos as trivial as a misplaced comma could have a subtle impact on meaning. Take special care not to\nalter backwards compatibility and create a vote if unsure. Common sense will help here.\n\nExamples:\n\n1. HTML Tables are currently broken on php-fig.org because of the syntax used.\n2. Somebody spelled something wrong and nobody spotted it for a year.\n3. Problems with GitHub Markdown\n\n[workflow bylaw]: https://github.com/php-fig/fig-standards/blob/master/bylaws/002-psr-workflow.md\n[votes bylaw]: https://github.com/php-fig/fig-standards/blob/master/bylaws/004-votes.md\n"
  },
  {
    "path": "bylaws/008-psr-evolution.md",
    "content": "# PSR evolution\n\n## Scope and objectives\n\nA PSR is often comprised of text and code, generally interfaces. Those interfaces are pieces of code that are released and tagged at a specific moment in time. However, the PHP language doesn't stand still; it evolves over time.\n\nThis means that those interfaces need to both provide a stable contract, as well as evolve to leverage new language features that could help better enforce the behaviors described in the PSR itself.\n\nAt the same time, a PSR cannot be changed after its release (at which point only erratas are allowed), to protect a package that declared compatibility from becoming de facto incompatible.\n\nThis document defines a process to be followed in updating PSR interfaces, in a way that is not breaking in regard to behavior for end users, and with an appropriate upgrade path for the consumers.\n\n## Definitions\n\n * **Consumer** - libraries and projects that consume one or more interfaces from the code released as part of the PSR in question.\n * **Implementer** - libraries and projects that implement one or more interfaces from code released as part of the PSR in question.\n * **Cross-compatibility** - the ability for a consumer or an implementer to support more than one code version of the PSR with a single release of their own.\n\n## New releases\n\nA new minor release of a PHP-FIG package containing interfaces for a PSR MUST follow these rules:\n * the new release MUST follow [Semantic Versioning](https://semver.org/) rules;\n * the PSR behavior MUST NOT be altered;\n * consumers or implementers of those interfaces MUST NOT suffer breaking changes;\n * the PHP version constraint of the PHP-FIG package MAY be increased to leverage newer language features, especially those that would aid cross-compatibility of consumers and implementers with the old and the new versions;\n * the PHP version constraint of the PHP-FIG package MUST NOT be altered to use newer language features that would create cross-compatibility issues.\n \nA new major release of a PHP-FIG package containing interfaces for a PSR MUST follow the same rules, with this exception:\n * the new major version of the package MAY contain breaking changes if the implementing packages have a reasonable upgrade path, like the possibility of releasing a cross-compatible implementation with the previous releases;\n * the new major version of the package MAY refer to a new, superseding PSR.\n \nNote that if the upgrade path causes the consumers or implementers to maintain multiple versions of their libraries side-by-side, only to support multiple versions of the same PSR, the upgrade path is to be considered too steep.\n\n### Workflow\n\nSince releasing new versions of the interfaces MUST NOT alter the PSR in its behavior, those releases can be voted in with the same process as errata changes. The new releases MUST be declared and embedded with a brief explanation and a link in the PSR document, like in the following example:\n\n> \\`\\`\\`php\ninterface ContainerInterface\n{\n> // code snippet here\n}\n\\`\\`\\`\n>\n> Since [psr/container version 1.1](https://packagist.org/packages/psr/container#1.1.0), the above interface has been updated to add argument type hints.\n\nIn the example above, the last line is indicative of what should be added to the specification.\n\nThe meta document MUST be amended with information detailing the consumer and/or implementer upgrade path.\n\n### Practical example\n\nA common case for an upgrade in the interfaces is to add types for parameters and returns, since they are new language features introduced by PHP 7, and many PSR interfaces predate that release. We'll use a method from PSR-11 as an example of how a PSR interface could be updated.\n\n#### PSR-11: the interface\n\nPSR-11 is released with the [`psr/container` package](https://packagist.org/packages/psr/container) and it holds the `ContainerInterface`, which has this method:\n\n```php\n    /**\n     * @param string $id Identifier of the entry to look for.\n     *\n     * @return bool\n     */\n    public function has($id);\n```\n\nThis method could be updated with a new minor release that adds the argument type for `$id`:\n\n```php\npublic function has(string $id);\n```\n\nThis change would technically be a breaking change, but thanks to the [limited contravariance possible in PHP 7.2](https://wiki.php.net/rfc/parameter-no-type-variance), we can avoid that. This means that just by requiring `\"php\": \"^7.2\"` in the `psr/container` `composer.json`, we could tag this change as a minor release, and have all the consumers and implementers be automatically cross-compatible, provided that they declare `\"psr/container\": \"^1.0\"` (or equivalent) as a constraint.\n\nAfter this intermediate step, it would be possible to release a new major version, adding a return type hint:\n\n```php\npublic function has(string $id): bool;\n```\n\nThis must be released as a new major version of `psr/container` (2.0); any package that would implement this would be able to declare `\"psr/container\": \"^1.1 || ^2.0\"`, since backward compatibility to the first release would be impossible, due to the sum of covariance and contravariance rules.\n\n#### PSR-11: the implementation\n\nOn the other side, the implementers would be able to do a release cycle in the opposite fashion. The first release looks like this:\n\n```php\npublic function has($id);\n```\n\nThe second release would add the return type, maintaining compatibility with the original interface:\n\n```php\npublic function has($id): bool;\n```\n\nA third release would also add the argument type hint:\n\n```php\npublic function has(string $id): bool;\n```\n"
  },
  {
    "path": "bylaws/009-naming-conventions.md",
    "content": "Naming conventions for code released by PHP FIG\n===============================================\n\n1. Interfaces MUST be suffixed by `Interface`: e.g. `Psr\\Foo\\BarInterface`.\n2. Abstract classes MUST be prefixed by `Abstract`: e.g. `Psr\\Foo\\AbstractBar`.\n3. Traits MUST be suffixed by `Trait`: e.g. `Psr\\Foo\\BarTrait`.\n4. PSR-1, 4, and 12 MUST be followed.\n5. For code released as part of a PSR, the vendor namespace MUST be `Psr` and the Composer package name MUST be `psr/<package>` (e.g., `psr/log`).\n6. For code released as part of a PER or any other Auxiliary Resources, the vendor namespace MUST be `Fig` and the Composer package name MUST be `fig/<package>` (e.g., `fig/cache-util`).\n7. There MUST be a package/second-level namespace in relation with the PSR or PER that  covers the code.\n8. Implementations of a given PSR or PER SHOULD declare a `provides` key in their `composer.json` file in the form `psr/<package>-implementation` with a version number that matches the PSR being implemented.  For example, `\"psr/<package>-implementation\": \"1.0.0\"`."
  },
  {
    "path": "bylaws/010-funding.md",
    "content": "# Funding\n\n## Scope and objectives\n\nThe PHP-FIG is an organization composed entirely of unpaid volunteers and community members focused on improving the PHP ecosystem. As part of realizing its goals, the PHP-FIG has limited operating expenses like domain names, email accounts, and similar that require ongoing funding.  \n\nThis document defines the roles, rules and processes that must be followed inside the PHP-FIG in all matters regarding money, to guarantee fairness, transparency and impartiality. This document intentionally describes the only allowed processes and ways to raise, administer and spend money, so that any change to such processes requires a bylaw change vote. \n\nThe key words \"MUST\", \"MUST NOT\", \"REQUIRED\", \"SHALL\", \"SHALL\nNOT\", \"SHOULD\", \"SHOULD NOT\", \"RECOMMENDED\", \"NOT RECOMMENDED\",\n\"MAY\", and \"OPTIONAL\" in this document are to be interpreted as\ndescribed in [BCP 14][] [[RFC 2119][]] [[RFC 8174][]] when, and only when, they\nappear in all capitals, as shown here.\n\n[BCP 14]: https://datatracker.ietf.org/doc/html/bcp14/\n[RFC 2119]: https://datatracker.ietf.org/doc/html/rfc2119\n[RFC 8174]: https://datatracker.ietf.org/doc/html/rfc8174\n\n## Fiscal hosting\n\nFor handling money and fiscal matters, the PHP-FIG MUST use [Open Collective](https://opencollective.com/) as a platform and [Open Source Collective](https://opencollective.com/opensource) as a fiscal host.\n\nAll three Secretaries, but only the Secretaries, MUST have full administrative access to PHP-FIG's OpenCollective account. They SHALL NOT use those permissions in a discretionary manner, except as stated explicitly in this bylaw.\n\nAll funds MUST be collected into the Open Collective PHP-FIG account, so that any tax considerations will be handled automatically by the fiscal host, and every financial decision MUST be published and publicly available at the bottom of this document in the appropriate table and through Open Collective's budgetary tools.\n\n## Raising money\n\nPHP-FIG SHALL NOT solicit donations from any party, especially from private individuals; all exceptions to this rule MUST be listed below.\n\n### Through OpenCollective\n\nContributions SHALL be accepted via [Open Collective](https://opencollective.com/) with the following requirements:\n\n- The description MUST include the following:\n    1. A link back to this document on the PHP-FIG website.\n    2. A statement that we'd prefer contributions from companies rather than from private individuals.\n    3. A statement that donations do not give any rights nor provide any corresponding service.\n    4. Links to other preferred options for individuals to contribute as listed in this document, if any such exist.\n    5. A list of overfunding recipients as listed in this document, if any such exist.\n- The following information MUST be configured to show:\n    1. Contributors and the amounts they contributed;\n    2. The total amount of money raised;\n    3. The total amount of money spent;\n    4. The total amount of money remaining in the account;\n    5. The itemized transactions, including the date, amount, and description\n\n## Spending money\n\nFunds donated to the PHP-FIG MUST be used solely for non-personnel operating expenses. The PHP-FIG MUST NOT pay individual contributors or other personnel, like Core Committee members, Secretaries, Project Representatives or working groups unless the payment is associated with an approved expense, such as reimbursing a Secretary that has paid for an approved expense out of pocket.\nAll expenses MUST be approved by an Approval Vote of the Core Committee. The expense MUST include whether it is one time or recurring and the frequency at which the expense is incurred. All expenses MUST be justified by their contribution to the mission of PHP-FIG. In response to supplier price changes for previously accepted recurring expenses, Secretaries MAY request Implicit Approval from the Core Committee to raise the approved amount, only if that does not exceed a 10% increase.\n\nExpenses approved by the Core Committee MUST be listed below, and reported in the Open Collective budget.\n\n### Overfunding and disbursement\n\nOverfunding SHALL be defined as any amount raised that exceeds the amount needed to cover the existing PHP-FIG's yearly expenses, as defined in the \"Approved expenses\" section below, for a period of three years with a 10% cost increase year over year. For example, if the approved budget is $10, the maximum amount before funds are considered overfunding would be `$10 + $11 + $12.1 = $33.10`. The amount of funding to keep can be easily calculated by multiplying the total yearly expenses by `3.31` and rounding up.\n\nEvery year in January, the Secretaries SHALL review the Open Collective account and disburse any overfunding to the list of recipients defined in the Approved disbursement recipients section below, in the amounts defined in aforementioned section. Disbursements MUST be made in such a way to prevent any additional tax or fees from being incurred by the PHP-FIG or the recipient, such as via [Collective to Collective Donations][c2c].\n\nIf for any reason disbursement to a recipient is not possible, the recipient MUST be skipped and the Core Committee MUST be notified so this bylaw can be updated accordingly.\n\n### Approved disbursement recipients\n\nThis section contains a list of recipients that are eligible to receive disbursements from the PHP-FIG. \n\nAs an exception to Votes Bylaw, changes to this section only SHOULD NOT trigger a Bylaw Change Vote, but only an Approval Vote by the Core Committee.\n\n\n| Recipient name | Disbursement Method | Disbursement percentage |\n|----------------|----------------------------------|-------------------------| \n| PHP Foundation | [PHP Foundation Open Collective][phpfoundation] | `100%` |\n\n[phpfoundation]: https://opencollective.com/phpfoundation\n[c2c]: https://documentation.opencollective.com/giving-to-collectives/giving-to-other-collectives\n\n### Approved expenses\n\nThis section contains a chronological list of approved budgeting decisions, either recurring or not.\n\nAs an exception to Votes Bylaw, changes to this section only SHOULD NOT trigger a Bylaw Change Vote, but only an Approval Vote by the Core Committee.\n\n| Approved since | Expense                                       | Provider  | Approved amount and frequency  |\n|----------------|-----------------------------------------------|-----------|--------------------------------|\n| 2023-09-14     | Two Domains (`php-fig.com` and `php-fig.org`) | Namecheap | $33 USD / year |\n| 2023-09-14     | Email account (`info@php-fig.org`)            | Namecheap | $15 USD / year            |\n\n[RFC 2119]: https://tools.ietf.org/html/rfc2119"
  },
  {
    "path": "bylaws/100-implementation.md",
    "content": "# Implementation of FIG 3.0 changes\n\nUpon the adoption of these bylaws:\n\nAll currently sitting Secretaries will remain in their positions with no change in their term.\n\nThe recognized Voting Representatives for member projects have 30 days to state their intent to remain member projects. If they do so, the Voting Representative will be recognized as the Project Representative going forward. No new admission vote is necessary. If the Voting Representative does not make any statement for 30 days, the project will be dropped from FIG membership.\n\nThe Core Committee will be selected as though there were a 12-member vacancy according to the Vacancy rules above. The timetable of when this vote will occur will be announced by the Secretaries.\n\nAll previously-approved PSRs will remain approved with no change, and will retain their current PSR number.\n\nThe Editor of any PSR that is in Draft or Needs Review state will have a time limit from the time the Core Committee is seated to form an official Working Group, as defined in these bylaws. If a 5-member working group is formed then the PSR will automatically continue under these rules with no need for re-approval or re-entry. If the 5-member Working Group cannot be formed in that time then the PSR will automatically be listed as Abandoned. The exact timetable will be announced by the Secretaries.\n\nThis bylaw (100) may be removed by the Secretaries when it is deemed no longer necessary to be kept and the transition to the new structure is complete.\n"
  },
  {
    "path": "personnel.md",
    "content": "# Personnel\n\n## Current\n\n### Secretaries\n\n| Name                                              | Term                    |\n|---------------------------------------------------|-------------------------|\n| Alessandro Lai ([@AlessandroLai@phpc.social])     | 2017-11-12 - 2026-08-30 |\n| Mark Niebergall ([@mbniebergall@phpc.social])     | 2023-05-25 - 2027-05-30 |\n| Lane Staples ([@mstaples])                        | 2024-02-25 - 2026-02-28 |\n\nFeel free to contact the secretaries at info AT php-fig.org. For more information on the secretaries' role, see the [bylaws](https://www.php-fig.org/bylaws/mission-and-structure/#secretaries).\n\n\n### Core Committee Members\n\n| Name                                              | Term                    |\n|---------------------------------------------------|-------------------------|\n| Larry Garfield ([@Crell@phpc.social])             | 2016-12-24 - 2027-05-30 |\n| Cees-Jan Kiewiet ([@wyri@haxim.us])               | 2016-12-24 - 2026-08-30 |\n| Korvin Szanto ([@korvinszanto])                   | 2016-12-24 - 2026-02-22 |\n| Ken Guest ([@kenguest@phpc.social])               | 2022-01-30 - 2026-02-28 |\n| Jaap van Otterdijk ([@jaapio@phpc.social])        | 2022-08-28 - 2026-08-30 |\n| Navarr Barnier ([@navarr])                        | 2022-08-28 - 2026-08-30 |\n| Vincent de Lau ([@vdelau])                        | 2023-05-25 - 2027-05-30 |\n| Steve McDougall ([@JustSteveKing])                | 2024-02-25 - 2026-02-22 |\n| Matteo Beccati ([@mbeccati@phpc.social])          | 2024-02-25 - 2026-02-22 |\n| Mathieu Rochette ([@mathroc])                     | 2024-09-29 - 2026-08-30 |\n| Chris Tankersley ([@dragonmantank])               | 2025-05-31 - 2027-05-30 |\n\n### Member Projects\n\n| Project                         | Representative                            |\n|---------------------------------|-------------------------------------------|\n| [AMPHP]                         | Aaron Piotrowski ([@_trowski])            |\n| [AzuraCast]                     | Buster Neece ([@BusterNeece@phpc.social]) |\n| [CakePHP]                       | Larry Masters ([@PhpNut])                 |\n| [Composer]                      | Jordi Boggiano ([@seldaek])               |\n| [Concrete CMS]                  | Korvin Szanto ([@korvinszanto])           |\n| [Contao Open Source CMS]        | Leo Feyer ([@leofeyer])                   |\n| [Horde]                         | Jan Schneider ([@yunosh])                 |\n| [Hyperf]                        | Leo Cavalcante ([@leocavalcante])         |\n| [IBM i Toolkit]                 | Adam Culp ([@adamculp])                   |\n| [Jackalope]                     | Lukas Kahwe Smith ([@lsmith])             |\n| [Joomla]                        | Robert Deutz ([@rdeutz])                  |\n| [Laminas Project]               | Matthew Weier O'Phinney ([@mwop])         |\n| [Lithium]                       | Nate Abele ([@nateabele])                 |\n| [Magento]                       | Igor Miniailo ([@iminyaylo])              |\n| [PEAR]                          | Chuck Burgess ([@ashnazg@phpc.social])    |\n| [Phalcon]                       | Nikolaos Dimopoulos ([@phalconphp])       |\n| [Phing]                         | Siad Ardroumli                            |\n| [phpBB]                         | Marc Alexander ([@marc1706])              |\n| [phpDocumentor]                 | Mike van Riel ([@mvriel])                 |\n| [PHPixie]                       | Roman Tsiupa ([@dracony_gimp])            |\n| [Pimcore]                       | Bernhard Rusch ([@bernhard_rusch])        |\n| [PPI Framework]                 | Paul Dragoonis ([@dr4goonis])             |\n| [PrestaShop]                    | Rémi Gaillard ([@xtaz07])                 |\n| [PyroCMS]                       | Ryan Thompson ([@RyanThePyro])            |\n| [ReactPHP]                      | Cees-Jan Kiewiet ([@wyri@haxim.us])       |\n| [Revive Adserver]               | Matteo Beccati ([@mbeccati@phpc.social])  |\n| [Sculpin]                       | Chris Tankersley ([@dragonmantank])       |\n| [Slim]                          | Jason Coward ([@drumshaman])              |\n| [SilverStripe]                  | Damian Mooyman                            |\n| [Stash]                         | Robert Hafner ([@tedivm])                 |\n| [SugarCRM]                      | Andreas Sandberg ([@yellowandy])          |\n| [TYPO3]                         | Benni Mack ([@bennimack])                 |\n| [Flow] and [Neos]               | Karsten Dambekalns ([@kdambekalns])       |\n| [Wikibase] and [Semantic Media] | Jeroen De Dauw ([@JeroenDeDauw])          |\n| [Yii framework]                 | Alexander Makarov ([@sam_dark])           |\n| [Zikula]                        | Shefik Macauley ([@shefik_info])          |\n\n\n## Past\n\n### Former Secretaries\n\n| Name                                      | Term                    |\n|-------------------------------------------|-------------------------|\n| Gary Hockin ([@GeeH])                     | 2016-01-31 - 2016-01-31 |\n| Joe Ferguson ([@joepferguson])            | 2016-01-31 - 2016-06-29 |\n| Samantha Quiñones ([@ieatkillerbees])     | 2016-02-28 - 2016-12-24 |\n| Amanda Folson ([@ambassadorawsum])        | 2016-08-28 - 2017-11-12 |\n| Michael Cullum ([@michaelcullumuk])       | 2016-01-31 - 2018-01-31 |\n| Mark Railton ([@railto])                  | 2018-01-28 - 2018-06-05 |\n| Margret Staples ([@mstaples])             | 2017-11-12 - 2019-05-31 |\n| Ian Littman ([@iansltx])                  | 2018-08-26 - 2020-01-25 |\n| Asmir Mustafic ([@goetas_asmir])          | 2019-05-26 - 2021-05-30 |\n| Buster Neece ([@BusterNeece@phpc.social]) | 2020-01-25 - 2022-01-31 |\n| Vincent de Lau ([@vdelau])                | 2021-06-25 - 2023-05-25 |\n| Steve Winter ([@SteveWinterNZ])           | 2022-01-30 - 2024-02-25 |\n\n### Former Core Committee Members\n\n| Name                                          | Term                    |\n|-----------------------------------------------|-------------------------|\n| Graham Hoefer ([@greydnls])                   | 2016-12-24 - 2018-01-31 |\n| Gary Hockin ([@GeeH])                         | 2016-12-24 - 2018-04-04 |\n| Lukas Kahwe Smith ([@lsmith])                 | 2016-12-24 - 2019-05-26 |\n| Sara Golemon ([@SaraMG])                      | 2016-12-24 - 2019-05-26 |\n| Stefano Torresi ([@storresi])                 | 2016-12-24 - 2020-01-25 |\n| Samantha Quiñones ([@ieatkillerbees])         | 2016-12-24 - 2020-08-31 |\n| Beau Simensen ([@beausimensen])               | 2016-12-24 - 2020-08-31 |\n| Michael Cullum ([@michaelcullumuk])           | 2018-01-28 - 2020-01-25 |\n| Matteo Beccati ([@mbeccati@phpc.social])      | 2019-05-26 - 2021-05-30 |\n| Massimiliano Arione ([@garakkio])             | 2020-01-25 - 2022-01-31 |\n| Ben Edmunds ([@benedmunds])                   | 2020-08-31 - 2022-08-31 |\n| Woody Gilk ([@shadowhand])                    | 2019-05-26 - 2022-08-31 |\n| Michelle Sanver ([@michellesanver])           | 2021-06-25 - 2023-05-25 |\n| Chris Tankersley ([@dragonmantank])           | 2016-12-24 - 2024-02-25 |\n| Enrico Zimuel ([@ezimuel])                    | 2020-01-25 - 2024-02-25 |\n| Chuck Burgess ([@ashnazg@phpc.social])        | 2018-08-26 - 2024-08-28 |\n| Alessandro Chitolina ([@alekitto@phpc.social])| 2021-06-25 - 2025-05-30 |\n| Matthew Weier O'Phinney ([@mwop])             | 2016-12-24 - 2025-05-30 |\n\n### Former Member Projects\n\n| Project                                | Representative                        |\n|----------------------------------------|---------------------------------------|\n| [Aura] and [Solar]                     | Paul M. Jones ([@pmjones])            |\n| [Assetic]                              | Kris Wallsmith ([@kriswallsmith])     |\n| [Agavi]                                | David Zülke ([@dzuelke])              |\n| [Doctrine]                             | Guilherme Blanco ([@guilhermeblanco]) |\n| [eZ Publish]                           | Andre Romcke ([@andrerom])            |\n| [Guzzle]                               | Jeremy Lindblom ([@jeremeamia])       |\n| [Laravel]                              | Taylor Otwell ([@taylorotwell])       |\n| [The League of Extraordinary Packages] | Graham Hoefer ([@greydnls])           |\n| [Phergie]                              | Joe Ferguson ([@joepferguson])        |\n| [Propel]                               | William Durand ([@couac])             |\n| [sabre/dav]                            | Evert Pot ([@evertp])                 |\n| [Stormpath PHP SDK]                    | Brian Retterer ([@bretterer])         |\n| [Symfony]                              | Fabien Potencier ([@fabpot])          |\n| [Drupal]                               | *vacant*                              |\n\n[@adamculp]: https://twitter.com/adamculp\n[@alekitto@phpc.social]: https://phpc.social/@alekitto\n[@AlessandroLai@phpc.social]: https://phpc.social/@AlessandroLai\n[@ambassadorawsum]: https://twitter.com/ambassadorawsum\n[@andrerom]: https://twitter.com/andrerom\n[@ashnazg@phpc.social]: https://phpc.social/@ashnazg\n[@beausimensen]: https://twitter.com/beausimensen\n[@benedmunds]: https://twitter.com/benedmunds\n[@bennimack]: https://twitter.com/bennimack\n[@bernhard_rusch]: https://twitter.com/bernhard_rusch\n[@bretterer]: https://twitter.com/bretterer\n[@BusterNeece@phpc.social]: https://phpc.social/@BusterNeece\n[@couac]: https://twitter.com/couac\n[@Crell@phpc.social]: https://phpc.social/@Crell\n[@mstaples]: https://github.com/mstaples\n[@dr4goonis]: https://twitter.com/dr4goonis\n[@dracony_gimp]: https://twitter.com/dracony_gimp\n[@dragonmantank]: https://twitter.com/dragonmantank\n[@drumshaman]: https://twitter.com/drumshaman\n[@dzuelke]: https://twitter.com/dzuelke\n[@evertp]: https://twitter.com/evertp\n[@ezimuel]: https://twitter.com/ezimuel\n[@fabpot]: https://twitter.com/fabpot\n[@garakkio]: https://twitter.com/garakkio\n[@GeeH]: https://twitter.com/GeeH\n[@goetas_asmir]: https://twitter.com/goetas_asmir\n[@greydnls]: https://twitter.com/greydnls\n[@guilhermeblanco]: https://twitter.com/guilhermeblanco\n[@iansltx]: https://twitter.com/iansltx\n[@ieatkillerbees]: https://twitter.com/ieatkillerbees\n[@iminyaylo]: https://twitter.com/iminyaylo\n[@jaapio@phpc.social]: https://phpc.social/@jaapio\n[@jeremeamia]: https://twitter.com/jeremeamia\n[@JeroenDeDauw]: https://twitter.com/JeroenDeDauw\n[@joepferguson]: https://twitter.com/joepferguson\n[@JustSteveKing]: https://twitter.com/JustSteveKing\n[@kdambekalns]: https://twitter.com/kdambekalns\n[@kenguest@phpc.social]: https://phpc.social/@kenguest\n[@korvinszanto]: https://twitter.com/korvinszanto\n[@kriswallsmith]: https://twitter.com/kriswallsmith\n[@leocavalcante]: https://twitter.com/leocavalcante\n[@leofeyer]: https://twitter.com/leofeyer\n[@lsmith]: https://twitter.com/lsmith\n[@marc1706]: https://twitter.com/marc1706\n[@mathroc]: https://github.com/mathroc\n[@mbeccati@phpc.social]: https://phpc.social/@mbeccati\n[@mbniebergall@phpc.social]: https://phpc.social/@mbniebergall\n[@michaelcullumuk]: https://twitter.com/michaelcullumuk\n[@michellesanver]: https://twitter.com/michellesanver\n[@michieltcs]: https://twitter.com/michieltcs\n[@mvriel]: https://twitter.com/mvriel\n[@mwop]: https://twitter.com/mwop\n[@nateabele]: https://twitter.com/nateabele\n[@navarr]: https://twitter.com/navarr\n[@phalconphp]: https://twitter.com/phalconphp\n[@PhpNut]: https://twitter.com/PhpNut\n[@pmjones]: https://twitter.com/pmjones\n[@railto]: https://twitter.com/railto\n[@rdeutz]: https://twitter.com/rdeutz\n[@RyanThePyro]: https://twitter.com/RyanThePyro\n[@sam_dark]: https://twitter.com/sam_dark\n[@SaraMG]: https://twitter.com/SaraMG\n[@seldaek]: https://twitter.com/seldaek\n[@shadowhand]: https://twitter.com/shadowhand\n[@shefik_info]: https://twitter.com/shefik_info\n[@SteveWinterNZ]: http://www.tedivm.com/SteveWinterNZ\n[@storresi]: https://twitter.com/storresi\n[@taylorotwell]: https://twitter.com/taylorotwell\n[@tedivm]: https://twitter.com/tedivm\n[@_trowski]: https://twitter.com/_trowski\n[@vdelau]: https://github.com/vdelau\n[@wyri@haxim.us]: https://toot-toot.wyrihaxim.us/@wyri\n[@xtaz07]: https://twitter.com/xtaz07\n[@yellowandy]: https://twitter.com/yellowandy\n[@yunosh]: https://twitter.com/yunosh\n\n[Agavi]: http://www.agavi.org\n[AMPHP]: https://amphp.org/\n[Assetic]: https://github.com/kriswallsmith/assetic\n[Aura]: http://auraphp.github.com\n[AzuraCast]: https://www.azuracast.com/\n[CakePHP]: http://cakephp.org\n[Composer]: http://getcomposer.org\n[Concrete CMS]: http://www.concretecms.org\n[Contao Open Source CMS]: https://contao.org\n[Doctrine]: http://www.doctrine-project.org\n[Drupal]: http://drupal.org\n[eZ Publish]: http://ez.no\n[Flow]: https://flow.neos.io/\n[Guzzle]: http://guzzlephp.org\n[Horde]: http://www.horde.org\n[Hyperf]: https://hyperf.io\n[IBM i Toolkit]: https://github.com/zendtech/IbmiToolkit\n[Jackalope]: http://jackalope.github.com\n[Joomla]: http://www.joomla.org\n[Laminas Project]: https://getlaminas.org\n[Laravel]: http://laravel.com\n[Lithium]: http://li3.me\n[Magento]: http://magento.com\n[Neos]: https://neos.io\n[PEAR]: http://pear.php.net\n[Phalcon]: http://www.phalconphp.com\n[Phergie]: https://www.phergie.org\n[Phing]: http://www.phing.info\n[phpBB]: http://www.phpbb.com\n[phpDocumentor]: http://www.phpdoc.org\n[PHPixie]: http://phpixie.com\n[Pimcore]: http://www.pimcore.org\n[PPI Framework]: https://github.com/ppi\n[PrestaShop]: http://www.prestashop.com\n[Propel]: http://www.propelorm.org\n[PyroCMS]: http://www.pyrocms.com\n[ReactPHP]: http://reactphp.org\n[Revive Adserver]: http://www.revive-adserver.com\n[sabre/dav]: http://sabre.io\n[Sculpin]: https://sculpin.io\n[Semantic Media]: http://www.semantic-mediawiki.org\n[SilverStripe]: http://www.silverstripe.org\n[Slim]: http://www.slimframework.com\n[Solar]: http://solarphp.com\n[Stash]: http://www.tedivm.com/stash\n[Stormpath PHP SDK]: http://www.stormpath.com\n[SugarCRM]: http://developers.sugarcrm.com/wordpress\n[Symfony]: http://www.symfony.com\n[The League of Extraordinary Packages]: http://thephpleague.com\n[TYPO3]: https://typo3.org\n[Wikibase]: http://www.wikiba.se\n[Yii framework]: http://www.yiiframework.com\n[Zikula]: https://github.com/zikula\n"
  },
  {
    "path": "proposed/.placeholder",
    "content": ""
  },
  {
    "path": "proposed/internationalization-meta.md",
    "content": "# Internationalization Meta Document\n\n## 1. Summary\n\nDevelopers of components that are not coupled to any specific framework often find themselves in need of displaying a message to the user of the web application. However, being as they are not a component of a specific framework, their options for making these messages localizable is limited. In many cases, developers will make no attempt to pass these messages through a localization layer.\n\nTo resolve this issue and encourage the localization of libraries, a standard method for translating and transforming messages is necessary.\n\n## 3. Scope\n\n### 3.1. Goals\n\n* Provide a method for an independent component to display a message in a language other than the one in which the component was written.\n\n### 3.2. Non-Goals\n\n* This PSR does not provide a standard for the storage and management of translatable items and their translations. That is, this PSR is about denoting that a _message is translatable_ - **not** providing the specific translations for it.\n* This PSR does not provide a mechanism for collecting translatable items from a component's source code.\n* This PSR only addresses text present in PHP code.  It is not concerned with the translation of user content stored in a database or similar data store.\n\n## 4. Approaches\n\nTo solve this, we currently aim to create an interface that a framework-independent component can rely on for transforming a message key and context into a translated and formatted string.\n\n## 5. People\n\n### 5.1. Editor\n* Navarr Barnier\n\n### 5.2. Sponsor\n* Larry Garfield\n\n### 5.3. Working group members\n* Alexander Makarov\n* Susanne Moog\n* Ken Guest\n* Ben Ramsey\n* Vincent de Lau\n\n## 6. Votes\n\n* [Entrance Vote](https://groups.google.com/g/php-fig/c/AgzdtXS_iU0)\n"
  },
  {
    "path": "proposed/internationalization.md",
    "content": "# Common Interfaces and Functionality for Interoperability of Message Translation and Formatting\n\nThe key words \"MUST\", \"MUST NOT\", \"REQUIRED\", \"SHALL\", \"SHALL NOT\", \"SHOULD\",\n\"SHOULD NOT\", \"RECOMMEND\", \"MAY\", and \"OPTIONAL\" in this document are to\ninterpreted as described in [RFC 2119][].\n\nThe final implementations MAY decorate the objects with more functionality than\ncovered in the recommendation however they MUST implement the indicated\ninterfaces and functionality first.\n\n[RFC 2119]: http://tools.ietf.org/html/rfc2119\n\n# 1. Specification\n\nTBD.\n"
  },
  {
    "path": "proposed/phpdoc-meta.md",
    "content": "# PHPDoc Meta Document\n\n## 1. Summary\n\nPHPDoc as a notation was first presented in 2000 by Ulf Wendel, is heavily inspired by JavaDoc,\nand is currently in use by a significant percentage of public PHP projects in the field.\n\n## 2. Why Bother?\n\nPHPDocumentor has facilitated the growth of the PHPDoc notation, but with the growing number of other\ntools that use the PHPDoc notation, it is becoming increasingly important to have a formal standard\ninstead of its de-facto status.\n\nPros:\n\n* Developers (consumers) have a common reference to refer to when confronted with PHPDoc.\n* Projects and their Developers (contributors) have an authoritative reference which they can consult.\n* IDE vendors can standardize the way they use PHPDoc to aid in concerns such as auto-completion and navigation.\n* Projects using the PHPDoc data to complement their functionality, such as Documentation generators or static\n  analysis tools, will have a common language with their consumers.\n\nCons:\n\n* If there are different uses of elements in the PHPDoc notation, then it is desirable for projects to align with this\n  specification, which will cost effort to introduce.\n* Given the age of the current standard and widespread adoption, it is not possible to introduce significant breaks in\n  backwards compatibility with the current practices without a significant risk of alienating existing users or vendors.\n\n## 3. Scope\n\n### 3.1 Goals\n\n* Provide a complete technical definition, or schema, of the PHPDoc notation.\n* Introduce new concepts matching best practices or design patterns in use today.\n\n### 3.2 Non-Goals\n\n* This PSR does not provide a recommendation on how and when to use the concepts described in this document, so it is\n  not a coding standard.\n\n## 4. Approaches\n\n### 4.1 Chosen Approach\n\nWe have decided to formalize the existing practices, observe non-documented usages (such as Doctrine-style\nannotations), and observe feature requests with Documentation generators (such as phpDocumentor).\n\nThe combination of these should be described in sufficient detail as to reduce the amount of possible interpretation.\n\nIn addition to the above, the authors have taken care to provide for future expansions and tag additions that do not\naffect the Syntax of PHPDoc itself.\n\nPros:\n\n* Delivers a machine-parsable and verifiable specification.\n* Well-rounded proposal due to the number of factors considered.\n\nCons:\n\n* Technical and verbose.\n* Can only be extended when the syntax is not affected.\n\n## 5. People\n\n### 5.1 Editor\n\n * Jaap van Otterdijk - [phpDocumentor](https://github.com/phpDocumentor/phpDocumentor2)\n\n### 5.2 Sponsor\n\n * Ken Guest - [PHP-FIG](https://www.php-fig.org/)\n\n### 5.3 Working Group members\n\n * Alexander Makarov - [Yii](https://github.com/yiisoft/yii2)\n * TBA\n\n## 6. Votes\n\n* [Entrance Vote](https://groups.google.com/forum/#!topic/php-fig/5Yd0XGd349Q)\n* **Acceptance Vote**: TBD\n\n## 7. Relevant Links\n\nMost of the relevant links are mentioned in the PSR itself as support for individual chapters.\n\n## 8. Past contributors\n\nSince this document stems from the work of a lot of people in previous years, we should recognize their effort:\n\n * Chuck Burgess (previous Editor)\n * Mike van Riel (previous Editor)\n * Phil Sturgeon (previous sponsor)\n * Donald Gilbert (previous sponsor)\n * Gary Jones (contributor)\n\n_**Note:** Order descending chronologically._\n\n* [Original draft](https://github.com/phpDocumentor/phpDocumentor2/commit/0dbdbfa318d197279b414e5c0d1ffb142b31a528#docs/PSR.md)\n"
  },
  {
    "path": "proposed/phpdoc-tags-meta.md",
    "content": "# PHPDoc Tags Meta Document\n\n## 1. Summary\n\nThe purpose of this PSR is to document (in a catalog style) the de facto list of tags historically in use\nin the PHP community.\n\n## 2. Why Bother?\n\nWe wish to properly standardize the de facto usage of tags as code documentation.\n\n## 3. Scope\n\n### 3.1 Goals\n\n* Provide a complete technical definition, or schema, of the common tags in PHPDoc notation.\n* Introduce new concepts matching best practices or design patterns in use today.\n\n### 3.2 Non-Goals\n\n* This PSR does not provide a recommendation on how and when to use the concepts described in this document, so it is\n  not a coding standard.\n\n## 4. Approaches\n\n### 4.1 Chosen Approach\n\nWe have decided to formalize the existing practices, observe non-documented usages (such as Doctrine-style\nannotations), and observe feature requests with Documentation generators (such as phpDocumentor).\n\nThe combination of these should be described in sufficient detail as to reduce the amount of possible interpretation.\n\nIn addition to the above, the authors have taken care to provide for future expansions and tag additions that do not\naffect the Syntax of PHPDoc itself.\n\nPros:\n\n* Delivers a machine-parsable and verifiable specification.\n* Well-rounded proposal due to the number of factors considered.\n\nCons:\n\n* Technical and verbose.\n* Can only be extended when the syntax is not affected.\n\n## 5. People\n\n### 5.1 Editor\n\n * Chuck Burgess - [PEAR](https://pear.php.net)\n\n### 5.2 Sponsor\n\n * Ken Guest\n\n### 5.3 Working group members\n\n * Jaap van Otterdijk - [phpDocumentor](https://github.com/phpDocumentor/phpDocumentor2)\n * Alexander Makarov - [Yii](https://github.com/yiisoft/yii2)\n\n## 6. Votes\n\n* [Entrance Vote](https://groups.google.com/forum/#!topic/php-fig/5Yd0XGd349Q)\n* **Acceptance Vote**: TBD\n\n## 7. Relevant Links\n\nMost of the relevant links are mentioned in the PSR itself as support for individual chapters.\n\n_**Note:** Order descending chronologically._\n\n* [Original draft](https://github.com/phpDocumentor/phpDocumentor2/commit/0dbdbfa318d197279b414e5c0d1ffb142b31a528#docs/PSR.md)\n"
  },
  {
    "path": "proposed/phpdoc-tags.md",
    "content": "PSR-19: PHPDoc tags\n=============\n\n## Table Of Contents\n\n- [1. Introduction](#1-introduction)\n- [2. Conventions Used In This Document](#2-conventions-used-in-this-document)\n- [3. Definitions](#3-definitions)\n- [4. Inheritance](#4-inheritance)\n  - [4.1. Making inheritance explicit using the @inheritDoc tag](#41-making-inheritance-explicit-using-the-inheritdoc-tag)\n  - [4.2. Using the {@inheritDoc} inline tag to augment a Description](#42-using-the-inheritdoc-inline-tag-to-augment-a-description)\n  - [4.3. Element-specific inherited parts](#43-element-specific-inherited-parts)\n    - [4.3.1. Class Or Interface](#431-class-or-interface)\n    - [4.3.2. Function Or Method](#432-function-or-method)\n    - [4.3.3. Constant Or Property](#433-constant-or-property)\n- [5. Tags](#5-tags)\n  - [5.1.  @api](#51-api)\n  - [5.2.  @author](#52-author)\n  - [5.3.  @copyright](#53-copyright)\n  - [5.4.  @deprecated](#54-deprecated)\n  - [5.5.  @generated](#55-generated)\n  - [5.6.  @internal](#56-internal)\n  - [5.7.  @link](#57-link)\n  - [5.8.  @method](#58-method)\n  - [5.9.  @package](#59-package)\n  - [5.10. @param](#510-param)\n  - [5.11. @property](#511-property)\n  - [5.12. @return](#512-return)\n  - [5.13. @see](#513-see)\n  - [5.14. @since](#514-since)\n  - [5.15. @throws](#515-throws)\n  - [5.16. @todo](#516-todo)\n  - [5.17. @uses](#517-uses)\n  - [5.18. @var](#518-var)\n  - [5.19. @version](#519-version)\n\n## 1. Introduction\n\nThe main purpose of this PSR is to provide a complete catalog of Tags in\nthe [PHPDoc standard][PHPDOC_PSR].\n\nThis document SHALL NOT:\n\n* Describe a catalog of Annotations.\n* Describe best practices or recommendations for Coding Standards on the\n  application of the PHPDoc standard. This document is limited to a formal\n  specification of syntax and intention.\n\n## 2. Conventions Used In This Document\n\nThe key words \"MUST\", \"MUST NOT\", \"REQUIRED\", \"SHALL\", \"SHALL NOT\", \"SHOULD\",\n\"SHOULD NOT\", \"RECOMMENDED\", \"MAY\", and \"OPTIONAL\" in this document are to be\ninterpreted as described in [RFC 2119][RFC2119].\n\n## 3. Definitions\n\nSee the Definitions section of the [PHPDoc PSR][PHPDOC_PSR], as those definitions\napply here as well.\n\n## 4. Regarding Inheritance\n\nA PHPDoc that is associated with a \"Structural Element\" that implements, extends\nor overrides a \"Structural Element\" has the ability to inherit parts of\ninformation from the PHPDoc associated with the \"Structural Element\" that is\nimplemented, extended or overridden.\n\nThe PHPDoc for every type of \"Structural Element\" MUST inherit the following\nparts if that part is absent:\n\n* [Summary][PHPDOC_PSR_SUMMARY]\n* [Description][PHPDOC_PSR_DESCRIPTION] and\n* A specific subset of [Tags][PHPDOC_PSR_TAGS]:\n  * [@author](#52-author)\n  * [@copyright](#53-copyright)\n  * [@version](#519-version)\n\nThe PHPDoc for each type of \"Structural Element\" MUST also inherit a\nspecialized subset of tags depending on which \"Structural Element\" is\nassociated.\n\nIf a PHPDoc does not feature a part, such as Summary or Description, that is\npresent in the PHPDoc of a super-element, then that part is always implicitly\ninherited.\nThe following is a list of all elements whose DocBlocks are able to inherit\ninformation from a super-element's DocBlock:\n\n1. a Class' or Interface's DocBlock can inherit information from a Class or\n   Interface which it extends.\n2. a Property's DocBlock can inherit information from a Property with the same\n   name that is declared in a superclass.\n3. a Method's DocBlock can inherit information from a Method with the same\n   name that is declared in a superclass.\n4. a Method's DocBlock can inherit information from a Method with the same\n   name that is declared in an implemented interface in the current Class\n   or that is implemented in a superclass.\n\n> For example:\n>\n> Let's assume you have a method `\\SubClass::myMethod()` and its class\n> `\\SubClass` extends the class `\\SuperClass`. And in the class `\\SuperClass`\n> there is a method with the same name (e.g. `\\SuperClass::myMethod`).\n>\n> If the above applies then the DocBlock of `\\SubClass::myMethod()` will\n> inherit any of the parts mentioned above from the PHPDoc of\n> `\\SuperClass::myMethod`. So if the `@version` tag was not redefined then it\n> is assumed that `\\SubClass::myMethod()` will have the same `@version`\n> tag.\n\nInheritance takes place from the root of a class hierarchy graph to its leafs.\nThis means that anything inherited in the bottom of the tree MUST 'bubble' up\nto the top unless overridden.\n\n## 4.1. Making inheritance explicit using the @inheritDoc tag\n\nBecause inheritance is implicit it may happen that it is not necessary to\ninclude a PHPDoc with a \"Structural Element\". This can cause confusion as it\nis now ambiguous whether the PHPDoc was omitted on purpose or whether the\nauthor of the code had forgotten to add documentation.\n\nIn order to resolve this ambiguity the `@inheritDoc` tag can be used to\nindicate that this element will inherit its information from a super-element.\n\nExample:\n\n    /**\n     * This is a summary.\n     */\n    class SuperClass\n    {\n    }\n\n    /**\n     * @inheritDoc\n     */\n    class SubClass extends SuperClass\n    {\n    }\n\nIn the example above the SubClass' Summary can be considered equal to that of\nthe SuperClass element, which is thus \"This is a summary.\".\n\n## 4.2. Using the {@inheritDoc} inline tag to augment a Description\n\nSometimes you want to inherit the Description of a super-element and add your\nown text with it to provide information specific to your \"Structural Element\".\nThis MUST be done using the `{@inheritDoc}` inline tag.\n\nThe `{@inheritDoc}` inline tag will indicate that at that location the\nsuper-element's description MUST be injected or inferred.\n\nExample:\n\n    /**\n     * This is the Summary for this element.\n     *\n     * {@inheritDoc}\n     *\n     * In addition this description will contain more information that\n     * will provide a detailed piece of information specific to this\n     * element.\n     */\n\nIn the example above it is indicated that the Description of this PHPDoc is a\ncombination of the Description of the super-element, indicated by the\n`{@inheritDoc}` inline tag, and the subsequent body text.\n\n## 4.3. Element-specific inherited parts\n\n### 4.3.1. Class Or Interface\n\nIn addition to the inherited descriptions and tags as defined in this chapter's\nroot, a class or interface MUST inherit the following tags:\n\n* [@package](#59-package)\n\n### 4.3.2. Function Or Method\n\nIn addition to the inherited descriptions and tags as defined in this chapter's\nroot, a function or method in a class or interface MUST inherit the following tags:\n\n* [@param](#510-param)\n* [@return](#512-return)\n* [@throws](#515-throws)\n\n### 4.3.3. Constant Or Property\n\nIn addition to the inherited descriptions and tags as defined in this chapter's\nroot, a constant or property in a class MUST inherit the following tags:\n\n* [@var](#518-type)\n\n## 5. Tags\n\nUnless specifically mentioned in the description each tag MAY occur zero or more\ntimes in each \"DocBlock\".\n\n### 5.1. @api\n\nThe @api tag is used to highlight \"Structural Elements\" as being part of the\nprimary public API of a package.\n\n#### Syntax\n\n    @api\n\n#### Description\n\nThe `@api` tag MAY be applied to public \"Structural Elements\" to highlight\nthem in generated documentation, pointing the consumer to the primary public\nAPI components of a library or framework.\n\nOther \"Structural Elements\" with a public visibility MAY be listed less\nprominently in generated documentation.\n\nSee also the [`@internal`](#56-internal), which MAY be used to hide internal\n\"Structural Elements\" from generated documentation.\n\n#### Examples\n\n```php\nclass UserService\n{\n    /**\n     * This method is public-API. \n     *\n     * @api\n     */\n    public function getUser()\n    {\n        <...>\n    }\n\n    /**\n     * This method is \"package scope\", not public-API\n     */\n    public function callMefromAnotherClass()\n    {\n        <...>\n    }\n}\n```\n\n### 5.2. @author\n\nThe @author tag is used to document the author of any \"Structural Element\".\n\n#### Syntax\n\n    @author [name] [<email address>]\n\n#### Description\n\nThe @author tag can be used to indicate who has created a \"Structural Element\"\nor has made significant modifications to it. This tag MAY also contain an\ne-mail address. If an e-mail address is provided it MUST follow\nthe author's name and be contained in chevrons, or angle brackets, and MUST\nadhere to the syntax defined in RFC 2822.\n\n#### Examples\n\n```php\n/**\n * @author My Name\n * @author My Name <my.name@example.com>\n */\n```\n\n### 5.3. @copyright\n\nThe @copyright tag is used to document the copyright information of any\n\"Structural element\".\n\n#### Syntax\n\n    @copyright <description>\n\n#### Description\n\nThe @copyright tag defines who holds the copyright over the \"Structural Element\".\nThe copyright indicated with this tag applies to the \"Structural Element\" to\nwhich it applies and all child elements unless otherwise noted.\n\nThe format of the description is governed by the coding standard of each\nindividual project. It is RECOMMENDED to mention the year or years which are\ncovered by this copyright and the organization involved.\n\n#### Examples\n\n```php\n/**\n * @copyright 1997-2005 The PHP Group\n */\n```\n\n### 5.4. @deprecated\n\nThe @deprecated tag is used to indicate which 'Structural elements' are\ndeprecated and are to be removed in a future version.\n\n#### Syntax\n\n    @deprecated [<\"Semantic Version\">] [<description>]\n\n#### Description\n\nThe @deprecated tag declares that the associated 'Structural elements' will\nbe removed in a future version as it has become obsolete or its usage is\notherwise not recommended, effective from the \"Semantic Version\" if provided.\n\nThis tag MAY provide an additional description stating why the associated\nelement is deprecated.\n\nIf the associated element is superseded by another it is RECOMMENDED to add a\n@see tag in the same 'PHPDoc' pointing to the new element.\n\n#### Examples\n\n```php\n/**\n * @deprecated\n *\n * @deprecated 1.0.0\n *\n * @deprecated No longer used by internal code and not recommended.\n *\n * @deprecated 1.0.0 No longer used by internal code and not recommended.\n */\n```\n\n### 5.5. @generated\n\nThe @generated tag indicates that the code has been generated using an\nautomation script.\n\n#### Syntax\n\n    @generated [description]\n\n#### Description\n\nThe `@generated` is used to denote a class or a function that has been\ngenerated using an automation script. This tag should be used to warn\nto not change the code, since the change will be overwritten by the\nautomation script.\n\n#### Examples\n\nMark a class that has been generated using a PHP script.\n\n```php\n/**\n * Index a document in Elasticsearch\n * \n * @generated class generated using bin/script.php, please DO NOT EDIT!\n * \n * @version 7.14.0 Elasticsearch\n */\nclass Index\n{\n    <...>\n}\n```\n\nMark a function that has been generated using a PHP script.\n\n```php\n\n/**\n * @generated function generated using bin/script.php, please DO NOT EDIT!\n * \n * @param array $params parameters for the index API endpoint\n * \n * @return array response from Elasticsearch\n */\nfunction index(array $params): array\n{\n    <...>\n}\n```\n\n### 5.6. @internal\n\nThe @internal tag is used to denote that the associated \"Structural Element\" is\na structure internal to this application or library. It may also be used inside\na description to insert a piece of text that is only applicable for\nthe developers of this software.\n\n#### Syntax\n\n    @internal [description]\n\nor inline:\n\n    {@internal [description]}\n\nContrary to other inline tags, the inline version of this tag may also contain\nother inline tags (see second example below).\n\n#### Description\n\nThe `@internal` tag indicates that the associated \"Structural Element\" is intended\nonly for use within the application, library or package to which it belongs.\n\nAuthors MAY use this tag to indicate that an element with public visibility should\nbe regarded as exempt from the API - for example:\n  * Library authors MAY regard breaking changes to internal elements as being exempt\n    from semantic versioning.\n  * Static analysis tools MAY indicate the use of internal elements from another\n    library/package with a warning or notice.\n\nWhen generating documentation from PHPDoc comments it is RECOMMENDED to hide the\nassociated element unless the user has explicitly indicated that internal elements\nshould be included.\n\nAn additional use of @internal is to add internal comments or additional\ndescription text inline to the Description. This may be done, for example,\nto withhold certain business-critical or confusing information when generating\ndocumentation from the source code of this piece of software.\n\n#### Examples\n\nMark the count function as being internal to this project:\n\n```php\n/**\n * @internal\n *\n * @return int Indicates the number of items.\n */\nfunction count()\n{\n    <...>\n}\n```\n\nInclude a note in the Description that only Developer Docs would show.\n\n```php\n/**\n * Counts the number of Foo.\n *\n * This method gets a count of the Foo.\n * {@internal Developers should note that it silently \n *            adds one extra Foo (see {@link http://example.com}).}\n *\n * @return int Indicates the number of items.\n */\nfunction count()\n{\n    <...>\n}\n```\n\n### 5.7. @link\n\nThe @link tag indicates a custom relation between the associated\n\"Structural Element\" and a website, which is identified by an absolute URI.\n\n#### Syntax\n\n    @link [URI] [description]\n\nor inline\n\n    {@link [URI] [description]}\n\n#### Description\n\nThe @link tag can be used to define a relation, or link, between the\n\"Structural Element\", or part of the description when used inline, to an URI.\n\nThe URI MUST be complete and well-formed as specified in [RFC 2396][RFC2396].\n\nThe @link tag MAY have a description appended to indicate the type of relation\ndefined by this occurrence.\n\n#### Examples\n\n```php\n/**\n * @link http://example.com/my/bar Documentation of Foo.\n *\n * @return int Indicates the number of items.\n */\nfunction count()\n{\n    <...>\n}\n\n/**\n * This method counts the occurrences of Foo.\n *\n * When no more Foo ({@link http://example.com/my/bar}) are given this\n * function will add one as there must always be one Foo.\n *\n * @return int Indicates the number of items.\n */\nfunction count()\n{\n    <...>\n}\n```\n\n### 5.8. @method\n\nThe @method allows a class to know which 'magic' methods are callable.\n\n#### Syntax\n\n    @method [return type] [name]([type] [parameter], [...]) [description]\n\n#### Description\n\nThe @method tag is used in situation where a class contains the `__call()` magic\nmethod and defines some definite uses.\n\nAn example of this is a child class whose parent has a `__call()` to have dynamic\ngetters or setters for predefined properties. The child knows which getters and\nsetters need to be present but relies on the parent class to use the `__call()`\nmethod to provide it. In this situation, the child class would have a @method\ntag for each magic setter or getter method.\n\nThe @method tag allows the author to communicate the type of the arguments and\nreturn value by including those types in the signature.\n\nWhen the intended method does not have a return value then the return type MAY\nbe omitted; in which case 'void' is implied.\n\n@method tags can ONLY be used in a PHPDoc that is associated with a\n*class* or *interface*.\n\n#### Examples\n\n```php\nclass Parent\n{\n    public function __call()\n    {\n        <...>\n    }\n}\n\n/**\n * @method setInteger(int $integer)\n * @method string getString()\n * @method void setString(int $integer)\n */\nclass Child extends Parent\n{\n    <...>\n}\n```\n\n### 5.9. @package\n\nThe @package tag is used to categorize \"Structural Elements\" into logical\nsubdivisions.\n\n#### Syntax\n\n    @package [level 1]\\[level 2]\\[etc.]\n\n#### Description\n\nThe @package tag can be used as a counterpart or supplement to Namespaces.\nNamespaces provide a functional subdivision of \"Structural Elements\" where the\n@package tag can provide a *logical* subdivision in which way the elements can\nbe grouped with a different hierarchy.\n\nIf, across the board, both logical and functional subdivisions are equal it\nis NOT RECOMMENDED to use the @package tag, to prevent maintenance overhead.\n\nEach level in the logical hierarchy MUST separated with a backslash (`\\`) to\nbe familiar to Namespaces. A hierarchy MAY be of endless depth but it is\nRECOMMENDED to keep the depth at less or equal than six levels.\n\nThe package applies to that namespace, class or interface and their contained\nelements. This means that a function which is contained in a namespace with the\n@package tag assumes that package.\n\nThis tag MUST NOT occur more than once in a \"DocBlock\".\n\n#### Examples\n\n```php\n/**\n * @package PSR\\Documentation\\API\n */\n```\n\n### 5.10. @param\n\nThe @param tag is used to document a single parameter of a function or method.\n\n#### Syntax\n\n    @param [\"Type\"] [...]$[name] [<description>]\n\n#### Description\n\nWith the @param tag it is possible to document the type and function of a\nsingle parameter of a function or method. When provided it MUST contain a\n\"Type\" to indicate what is expected. The \"name\" is required only when some\n@param tags are omitted due to all useful info already being visible in the\ncode signature itself. The description is OPTIONAL yet RECOMMENDED.\n\nThe name of the parameter MUST be prefixed with a dollar sign (`$`) to indicate\nthe start of a variable name. OPTIONAL variadic operator (`...`) MAY be used\nto indicate that the parameter is variadic. The variadic operator MAY only be\napplied to the last parameter.\n\nIt is RECOMMENDED when documenting to use this tag with every function and\nmethod.\n\nThis tag MUST NOT occur more than once per parameter in a \"PHPDoc\" and is\nlimited to \"Structural Elements\" of type method or function.\n\n#### Examples\n\n```php\n/**\n * Counts the number of items in the provided array.\n *\n * @param mixed[] $items Array structure to count the elements of.\n *\n * @return int Returns the number of elements.\n */\nfunction count(array $items)\n{\n    <...>\n}\n```\n\n### 5.11. @property\n\nThe `@property` tag is used to declare which \"magic\" properties are supported.\n\n#### Syntax\n\n    @property[<-read|-write>] [\"Type\"] $[name] [<description>]\n\n#### Description\n\nThe `@property` tag is used when a `class` (or `trait`) implements the `__get()`\nand/or `__set()` \"magic\" methods to resolve non-literal properties at run-time.\n\nThe `@property-read` and `@property-write` variants MAY be used to indicate \"magic\"\nproperties that can only be read or written.\n\nThe `@property` tags can ONLY be used in a PHPDoc that is associated with a\n*class* or *trait*.\n\n#### Example\n\nIn the following example, a class `User` implements the magic `__get()` method, in\norder to implement a \"magic\", read-only `$full_name` property:\n\n```php\n/**\n * @property-read string $full_name\n */\nclass User\n{\n    /**\n     * @var string\n     */\n    public $first_name;\n\n    /**\n     * @var string\n     */\n    public $last_name;\n\n    public function __get($name)\n    {\n        if ($name === \"full_name\") {\n            return \"{$this->first_name} {$this->last_name}\";\n        }\n    }\n}\n```\n\n### 5.12. @return\n\nThe @return tag is used to document the return value of functions or methods.\n\n#### Syntax\n\n    @return <\"Type\"> [description]\n\n#### Description\n\nWith the @return tag it is possible to document the return type of a\nfunction or method. When provided, it MUST contain a \"Type\"\nto indicate what is returned; the description on the other hand is OPTIONAL yet\nRECOMMENDED in case of complicated return structures, such as associative arrays.\n\nIt is RECOMMENDED to use this tag with every function or method where PHP native\ntypes are insufficient.  If no `@return` type is given, and no return type\ndeclaration is provided in the code signature, an interpreter MUST interpret\nthis as if `@return mixed` is provided.\n\nThis tag MUST NOT occur more than once in a \"DocBlock\" and is limited to the\n\"DocBlock\" of a \"Structural Element\" of a method or function.\n\n#### Examples\n\n```php\n/**\n * @return int Indicates the number of items.\n */\nfunction count()\n{\n    <...>\n}\n\n/**\n * @return string|null The label's text or null if none provided.\n */\nfunction getLabel()\n{\n    <...>\n}\n```\n\n### 5.13. @see\n\nThe @see tag indicates a reference from the associated \"Structural Elements\" to\na website or other \"Structural Elements\".\n\n#### Syntax\n\n    @see [URI | \"FQSEN\"] [<description>]\n\n#### Description\n\nThe @see tag can be used to define a reference to other \"Structural Elements\"\nor to a URI.\n\nWhen defining a reference to another \"Structural Elements\" you can refer to a\nspecific element by appending a double colon and providing the name of that\nelement (also called the \"FQSEN\").\n\nA URI MUST be complete and well-formed as specified in [RFC 2396][RFC2396].\n\nThe @see tag SHOULD have a description to provide additional information\nregarding the relationship between the element and its target.\n\n#### Examples\n\n```php\n/**\n * @see number_of() :alias:\n * @see MyClass::$items           For the property whose items are counted.\n * @see MyClass::setItems()       To set the items for this collection.\n * @see http://example.com/my/bar Documentation of Foo.\n *\n * @return int Indicates the number of items.\n */\nfunction count()\n{\n    <...>\n}\n```\n\n### 5.14. @since\n\nThe @since tag is used to denote _when_ an element was introduced or modified,\nusing some description of \"versioning\" to that element.\n\n#### Syntax\n\n    @since [<\"Semantic Version\">] [<description>]\n\n#### Description\n\nDocuments the \"version\" of the introduction or modification of any element.\n\nIt is RECOMMENDED that the version matches a semantic version number (x.x.x)\nand MAY have a description to provide additional information.\n\nThis information can be used to generate a set of API Documentation where the\nconsumer is informed which application version is necessary for a specific\nelement.\n\nThe @since tag SHOULD NOT be used to show the current version of an element...\nthe @version tag SHOULD be used for that purpose.\n\n#### Examples\n\n```php\n/**\n * This is Foo\n * @version 2.1.7 MyApp\n * @since 2.0.0 introduced\n */\nclass Foo\n{\n    /**\n     * Make a bar.\n     *\n     * @since 2.1.5 bar($arg1 = '', $arg2 = null)\n     *        introduced the optional $arg2\n     * @since 2.1.0 bar($arg1 = '')\n     *        introduced the optional $arg1\n     * @since 2.0.0 bar()\n     *        introduced new method bar()\n     */\n    public function bar($arg1 = '', $arg2 = null)\n    {\n        <...>\n    }\n}\n```\n\n### 5.15. @throws\n\nThe @throws tag is used to indicate whether \"Structural Elements\" throw a\nspecific type of Throwable (exception or error).\n\n#### Syntax\n\n    @throws [\"Type\"] [<description>]\n\n#### Description\n\nThe @throws tag MAY be used to indicate that \"Structural Elements\" throw a\nspecific type of error.\n\nThe type provided with this tag MUST represent an object that is a subtype of Throwable.\n\nThis tag is used to present in your documentation which error COULD occur and\nunder which circumstances. It is RECOMMENDED to provide a description that\ndescribes the reason an exception is thrown.\n\nIt is also RECOMMENDED that this tag occurs for every occurrence of an\nexception, even if it has the same type. By documenting every occurrence a\ndetailed view is created and the consumer knows for which errors to check.\n\n#### Examples\n\n```php\n/**\n * Counts the number of items in the provided array.\n *\n * @param mixed[] $array Array structure to count the elements of.\n *\n * @throws InvalidArgumentException if the provided argument is not of type\n *     'array'.\n *\n * @return int Returns the number of elements.\n */\nfunction count($items)\n{\n    <...>\n}\n```\n\n### 5.16. @todo\n\nThe @todo tag is used to indicate whether any development activities should\nstill be executed on associated \"Structural Elements\".\n\n#### Syntax\n\n    @todo [description]\n\n#### Description\n\nThe @todo tag is used to indicate that an activity surrounding the associated\n\"Structural Elements\" must still occur. Each tag MUST be accompanied by\na description that communicates the intent of the original author; this could\nhowever be as short as providing an issue number.\n\n#### Examples\n\n```php\n/**\n * Counts the number of items in the provided array.\n *\n * @todo add an array parameter to count\n *\n * @return int Returns the number of elements.\n */\nfunction count()\n{\n    <...>\n}\n```\n\n### 5.17. @uses\n\nIndicates whether the current \"Structural Element\" consumes the\n\"Structural Element\", or project file, that is provided as target.\n\n#### Syntax\n\n    @uses [\"FQSEN\"] [<description>]\n\n#### Description\n\nThe `@uses` tag describes whether any part of the associated \"Structural\nElement\" uses, or consumes, another \"Structural Element\" that is situated in\nthe current project.\n\nWhen defining a reference to another \"Structural Element\" you can refer to a\nspecific element by appending a double colon and providing the name of that\nelement (also called the \"FQSEN\").\n\nThis tag MUST NOT be used to indicate relations to elements outside of the\nsystem, so URLs are not usable. To indicate relations with outside elements the\n@see tag can be used.\n\nApplications consuming this tag, such as generators, are RECOMMENDED to provide\na `@usedby` tag on the destination element. This can be used to provide a\nbi-directional experience and allow for static analysis.\n\n#### Examples\n\n```php\n/**\n * @uses \\SimpleXMLElement::__construct()\n */\nfunction initializeXml()\n{\n    <...>\n}\n```\n\n```php\n/**\n * @uses MyView.php\n */\nfunction executeMyView()\n{\n    <...>\n}\n```\n\n### 5.18. @var\n\nYou may use the @var tag to document the \"Type\" of the following\n\"Structural Elements\":\n\n* Constants, both class and global scope\n* Properties\n* Variables, both global and local scope\n\n#### Syntax\n\n    @var [\"Type\"] [element_name] [<description>]\n\n#### Description\n\nThe @var tag defines which type of data is represented by a value of a\nConstant, Property or Variable.\n\nEach Constant or Property definition or Variable where the type is ambiguous\nor unknown SHOULD be preceded by a DocBlock containing the @var tag. Any\nother variable MAY be preceded with a DocBlock containing the @var tag.\n\nThe @var tag MUST contain the name of the element it documents, unless this\nproperty declaration only refers to a single property. In this case the name of\nthe property MAY be omitted.\n\n`element_name` is used when compound statements are used to define a series of Constants\nor Properties. Such a compound statement can only have one DocBlock while several\nitems are represented.\n\n#### Examples\n\n```php\n/** @var int $int This is a counter. */\n$int = 0;\n\n// there should be no docblock here\n$int++;\n```\n\nOr:\n\n```php\nclass Foo\n{\n  /**\n   * @var string|null Should contain a description\n   */\n  protected $description = null;\n\n  public function setDescription($description)\n  {\n      // there should be no docblock here\n      $this->description = $description;\n  }\n}\n```\n\nAnother example is to document the variable in a foreach explicitly; many IDEs\nuse this information to help you with auto-completion:\n\n```php\n/** @var \\Sqlite3 $sqlite */\nforeach ($connections as $sqlite) {\n    // there should be no docblock here\n    $sqlite->open('/my/database/path');\n    <...>\n}\n```\n\nEven compound statements may be documented... these two property blocks are\nequivalent:\n\n```php\nclass Foo\n{\n  /**\n   * @var string $name Should contain a description\n   * @var string $description Should contain a description\n   */\n  protected $name, $description;\n\n}\n```\n\n```php\nclass Foo\n{\n  protected\n      /**\n       * @var string Should contain a description\n       */\n      $name,\n      /**\n       * @var string Should contain a description\n       */\n      $description;\n\n}\n```\n\nOr constants:\n\n```php\nclass Foo\n{\n  const\n      /**\n       * @var string Should contain a description\n       */\n      MY_CONST1 = \"1\",\n      /**\n       * @var string Should contain a description\n       */\n      MY_CONST2 = \"2\";\n\n}\n```\n\n### 5.19. @version\n\nThe @version tag is used to denote some description of \"versioning\" to an\nelement.\n\n#### Syntax\n\n    @version [\"Semantic Version\"] [<description>]\n\n#### Description\n\nDocuments the current \"version\" of any element.\n\nThis information can be used to generate a set of API Documentation where the\nconsumer is informed about elements at a particular version.\n\nIt is RECOMMENDED that the version number matches a semantic version number as\ndescribed in the [Semantic Versioning Standard version 2.0][SEMVER2].\n\nVersion vectors from Version Control Systems are also supported, though they\nMUST follow the form:\n\n    name-of-vcs: $vector$\n\nA description MAY be provided, for the purpose of communicating any additional\nversion-specific information.\n\nThe @version tag MAY NOT be used to show the last modified or introduction\nversion of an element, the @since tag SHOULD be used for that purpose.\n\n#### Examples\n\n```php\n/**\n * File for class Foo\n * @version 2.1.7 MyApp\n *          (this string denotes the application's overall version number)\n * @version @package_version@\n *          (this PEAR replacement keyword expands upon package installation)\n * @version $Id$\n *          (this CVS keyword expands to show the CVS file revision number)\n */\n\n/**\n * This is Foo\n */\nclass Foo\n{\n  <...>\n}\n```\n\n\n[RFC2119]:                https://tools.ietf.org/html/rfc2119\n[RFC2396]:                https://tools.ietf.org/html/rfc2396\n[SEMVER2]:                http://www.semver.org\n[PHP_SUBSTR]:             https://php.net/manual/function.substr.php\n[SPDX]:                   https://www.spdx.org/licenses\n[PHPDOC_PSR]:             https://github.com/php-fig/fig-standards/blob/master/proposed/phpdoc.md\n[PHPDOC_PSR_SUMMARY]:     https://github.com/php-fig/fig-standards/blob/master/proposed/phpdoc.md#51-summary\n[PHPDOC_PSR_DESCRIPTION]: https://github.com/php-fig/fig-standards/blob/master/proposed/phpdoc.md#52-description\n[PHPDOC_PSR_TAGS]:        https://github.com/php-fig/fig-standards/blob/master/proposed/phpdoc.md#53-tags\n"
  },
  {
    "path": "proposed/phpdoc.md",
    "content": "PSR-5: PHPDoc\n=============\n\n## Table Of Contents\n\n- [1. Introduction](#1-introduction)\n- [2. Conventions Used In This Document](#2-conventions-used-in-this-document)\n- [3. Definitions](#3-definitions)\n- [4. Basic Principles](#4-basic-principles)\n- [5. The PHPDoc Format](#5-the-phpdoc-format)\n  - [5.1. Summary](#51-summary)\n  - [5.2. Description](#52-description)\n  - [5.3. Tags](#53-tags)\n    - [5.3.1. Tag Name](#531-tag-name)\n  - [5.4. Examples](#54-examples)\n- [Appendix A. Types](#appendix-a-types)\n  - [ABNF](#abnf)\n  - [Details](#details)\n  - [Valid Class Name](#valid-class-name)\n  - [Keyword](#keyword)\n\n## 1. Introduction\n\nThe purpose of the PSR is to provide a formal definition of the PHPDoc standard.\n\n## 2. Conventions Used In This Document\n\nThe key words \"MUST\", \"MUST NOT\", \"REQUIRED\", \"SHALL\", \"SHALL NOT\", \"SHOULD\",\n\"SHOULD NOT\", \"RECOMMENDED\", \"MAY\", and \"OPTIONAL\" in this document are to be\ninterpreted as described in [RFC 2119][RFC2119].\n\n## 3. Definitions\n\n* \"PHPDoc\" is a section of documentation which provides information on aspects\n  of a \"Structural Element\".\n\n  > It is important to note that a PHPDoc and a DocBlock are two separate\n  > entities. The DocBlock is the combination of a DocComment, which is a type\n  > of comment, and a PHPDoc entity. It is the PHPDoc entity that contains the\n  > syntax as described in this specification (such as the Description and tags).\n\n* \"Structural Element\" is a collection of programming constructs which MAY be\n  preceded by a DocBlock. The collection contains the following constructs:\n\n  * `require` / `include` (and their `\\_once` variants)\n  * `class` / `interface` / `trait`\n  * `function` (both standalone functions and class methods)\n  * variables (local and global scope) and class properties\n  * constants (global constants via `define` and class constants)\n\n  It is RECOMMENDED to precede a \"Structural Element\" with a DocBlock where it\n  is defined. It is common practice to have the DocBlock precede a Structural\n  Element but it MAY also be separated by any number of empty lines.\n\n  Examples:\n\n  ```php\n  /**\n   * This is a counter.\n   * @var int $int\n   */\n  $int = 0;\n\n  /** @var int $int This is a counter. */\n  $int = 0;\n\n  /* comment block... this is not a docblock */\n  $int++;\n\n  // single line comment... this is not a docblock\n  $int++;\n  ```\n\n  ```php\n  /**\n   * This class shows an example on where to position a DocBlock.\n   */\n  class Foo\n  {\n      /** @var ?string $title contains a title for the Foo */\n      protected $title = null;\n\n      /**\n       * Sets a single-line title.\n       *\n       * @param string $title A text for the title.\n       *\n       * @return void\n       */\n      public function setTitle($title)\n      {\n          // there should be no docblock here\n          $this->title = $title;\n      }\n  }\n  ```\n\n  It is NOT RECOMMENDED to use compound definitions for constants or properties,\n  since the handling of DocBlocks in these situations can lead to unexpected\n  results. If a compound statement is used, each element SHOULD have a preceding\n  DocBlock.\n\n  Example:\n\n  ```php\n    class Foo\n    {\n      protected\n        /**\n         * @var string Should contain a name\n         */\n        $name,\n        /**\n         * @var string Should contain a description\n         */\n        $description;\n    }\n  ```\n\n* \"DocComment\" is a special type of comment which MUST\n\n  - start with the character sequence `/**` followed by a whitespace character\n  - end with `*/` and\n  - have zero or more lines in between.\n\n  When a DocComment spans multiple lines, every line MUST start with an asterisk\n  (`*`) that SHOULD be aligned with the first asterisk of the opening clause.\n\n  Single line example:\n\n  ```php\n  /** <...> */\n  ```\n\n  Multiline example:\n\n  ```php\n    /**\n     * <...>\n     */\n  ```\n\n* \"DocBlock\" is a \"DocComment\" containing a single \"PHPDoc\" structure and\n  represents the basic in-source representation.\n\n* \"Tag\" is a single piece of meta information regarding a \"Structural Element\".\n\n* \"Type\" is the determination of what type of data is associated with an element.\n  This is used to determine the exact data type (primitive, class, object) of\n  arguments, properties, constants, etc.\n\n  See Appendix A for more detailed information about types.\n\n* \"FQSEN\" is an abbreviation for Fully Qualified Structural Element Name. This\n  notation expands on the Fully Qualified Class Name and adds a notation to\n  identify class / interface / trait members and re-apply the principles of the\n  FQCN to Interfaces, Traits, Functions and global Constants.\n\n  The following notations can be used per type of \"Structural Element\":\n\n  - *Namespace*:      `\\My\\Space`\n  - *Function*:       `\\My\\Space\\myFunction()`\n  - *Constant*:       `\\My\\Space\\MY_CONSTANT`\n  - *Class*:          `\\My\\Space\\MyClass`\n  - *Interface*:      `\\My\\Space\\MyInterface`\n  - *Trait*:          `\\My\\Space\\MyTrait`\n  - *Method*:         `\\My\\Space\\MyClass::myMethod()`\n  - *Property*:       `\\My\\Space\\MyClass::$my_property`\n  - *Class Constant*: `\\My\\Space\\MyClass::MY_CONSTANT`\n\n  A FQSEN has the following [ABNF][RFC5234] definition:\n\n      FQSEN    = fqnn / fqcn / constant / method / property  / function\n      fqnn     = \"\\\" [name] *(\"\\\" [name])\n      fqcn     = fqnn \"\\\" name\n      constant = ((fqnn \"\\\") / (fqcn \"::\")) name\n      method   = fqcn \"::\" name \"()\"\n      property = fqcn \"::$\" name\n      function = fqnn \"\\\" name \"()\"\n      name     = (ALPHA / \"_\") *(ALPHA / DIGIT / \"_\")\n\n## 4. Basic Principles\n\n* A PHPDoc MUST always be contained in a \"DocComment\"; the combination of these\n  two is called a \"DocBlock\".\n\n* A DocBlock MUST directly precede a \"Structural Element\".\n\n## 5. The PHPDoc Format\n\nThe PHPDoc format has the following [ABNF][RFC5234] definition:\n\n    PHPDoc             = [summary [description]] [tags]\n    eol                = [CR] LF ; to compatible with PSR-12\n    summary            = 1*CHAR 2*eol\n    description        = 1*(CHAR / inline-tag) 1*eol ; any amount of characters\n                                                     ; with inline tags inside\n    tags               = *(tag 1*eol)\n    inline-tag         = \"{\" tag \"}\"\n    tag                = \"@\" tag-name [\":\" tag-specialization] [tag-details]\n    tag-name           = (ALPHA / \"\\\") *(ALPHA / DIGIT / \"\\\" / \"-\" / \"_\")\n    tag-specialization = 1*(ALPHA / DIGIT / \"-\")\n    tag-details        = (1*SP tag-description)\n    tag-description    = (CHAR / inline-tag) *(CHAR / inline-tag / eol)\n    tag-argument       = *SP 1*CHAR [\",\"] *SP\n\nExamples of use are included in chapter 5.4.\n\n### 5.1. Summary\n\nA Summary MUST contain an abstract of the \"Structural Element\" defining the\npurpose. It is RECOMMENDED for Summaries to span a single line or two, but not\nmore than that.\n\nA Summary MUST end with two sequential line breaks, unless it is the only\ncontent in the PHPDoc.\n\nIf a Description is provided, then it MUST be preceded by a Summary. Otherwise\nthe Description risks being mistaken as the Summary.\n\nBecause a Summary is comparable to a chapter title, it is RECOMMENDED to use as\nlittle formatting as possible. Contrary to the Description, no recommendation is\nmade to support a mark-up language.\n\n### 5.2. Description\n\nThe Description is OPTIONAL but SHOULD be included when the \"Structural Element\"\ncontains more complexity than can be described by the Summary alone.\n\nAny application parsing the Description is RECOMMENDED to support the\nMarkdown mark-up language, to make it possible for the author to provide\nformatting and a clear way of representing code examples.\n\nCommon uses for the Description:\n* To provide more detail on what this method does than the Summary can do\n* To specify of what child elements an array / object is composed\n* To provide a set of common use cases or scenarios in which the \"Structural\n  Element\" may be applied\n\n### 5.3. Tags\n\nTags supply concise metadata for a \"Structural Element\". Each tag starts on a\nnew line, followed by an at-sign (`@`) and a tag-name, followed by whitespace and\nmetadata (including a description).\n\nIf metadata is provided, it MAY span multiple lines and COULD follow a strict\nformat, as dictated by the specific tag.\n\n> `@param string $argument1 This is a parameter.`\n>\n> The above tag consists of a _name_ (`param`) and metadata\n> ('string $argument1 This is a parameter.'), where the metadata is split into a\n> _type_ (`string`), variable name (`$argument1`),  and description (`This is a\n> parameter.`).\n\nThe description MUST support Markdown as a formatting language.  The\ndescription of the tag MAY start on the same line or next line.  The following\ntags are semantically identical:\n\n```php\n    /**\n     * @var string This is a description.\n     * @var string This is a\n     *    description.\n     * @var string\n     *    This is a description.\n     */\n```\n\nThis definition does NOT apply to _Annotation_ tags, which are not in scope.\n\n#### 5.3.1. Tag Name\n\nTag names indicate what type of information is represented by this tag.\n\n### 5.4. Examples\n\nThe following examples serve to illustrate the basic use of DocBlocks; it is\nadvised to read through the list of tags in the [Tag Catalog PSR][TAG_PSR].\n\nA complete example could look like this:\n\n```php\n/**\n * This is a Summary.\n *\n * This is a Description. It may span multiple lines\n * or contain `code` examples using the _Markdown_ markup\n * language.\n *\n * @see Markdown\n *\n * @param int        $parameter1 A parameter description.\n * @param \\Exception $e          Another parameter description.\n *\n * @\\Doctrine\\Orm\\Mapper\\Entity()\n *\n * @return string\n */\nfunction test($parameter1, $e)\n{\n    ...\n}\n```\n\nThe Description MAY be omitted:\n\n```php\n/**\n * This is a Summary.\n *\n * @see Markdown\n *\n * @param int        $parameter1 A parameter description.\n * @param \\Exception $parameter2 Another parameter description.\n *\n * @\\Doctrine\\Orm\\Mapper\\Entity()\n *\n * @return string\n */\nfunction test($parameter1, $parameter2)\n{\n}\n```\n\nTags MAY also be omitted:\n\n```php\n/**\n * This is a Summary.\n */\nfunction test($parameter1, $parameter2)\n{\n}\n```\n\nA DocBlock may also span a single line:\n\n```php\n/** @var \\ArrayObject $array An array of things. */\npublic $array = null;\n```\n\n## Appendix A. Types\n\n### ABNF\n\nA Type has the following [ABNF][RFC5234] definition:\n\n    type-expression  = type *(\"|\" type) *(\"&\" type)\n    type             = class-name / keyword / array\n    array            = (type / array-expression) \"[]\"\n    array-expression = \"(\" type-expression \")\"\n    class-name       = [\"\\\"] label *(\"\\\" label)\n    label            = (ALPHA / %x7F-FF) *(ALPHA / DIGIT / %x7F-FF)\n    keyword          = \"array\" / \"bool\" / \"callable\" / \"false\" / \"float\" / \"int\" / \"iterable\" / \"mixed\" / \"never\"\n    keyword          =/ \"null\" / \"object\" / \"resource\" / \"self\" / \"static\" / \"string\" / \"true\" / \"void\" / \"$this\"\n\n### Details\n\nWhen a \"Type\" is used, the user will expect a value, or set of values, as detailed below.\n\nWhen the \"Type\" consists of multiple types, then these MUST be separated with\neither the vertical bar (|) for union type or the ampersand (&) for intersection\ntype.  Any interpreter supporting this specification MUST recognize this and\nsplit the \"Type\" before evaluating.\n\nUnion type example:\n>`@return int|null`\n\nIntersection type example:\n>`@var \\MyClass&\\PHPUnit\\Framework\\MockObject\\MockObject $myMockObject`\n\n#### Arrays\n\nThe value represented by \"Type\" can be an array. The type MUST be defined\nfollowing one of the following options:\n\n1. unspecified: no definition of the contents of the array is given.\n   Example: `@return array`\n\n2. specified as a specific type: each member of the array is the same one type.\n   Example: `@return int[]`\n\n   Note that `mixed` is also a single type and thus can explicitly indicate that\n   each member is any possible type.\n\n3. specified as containing multiple explicit types:  each member can be of any\n   of the given types.\n   Example: `@return (int|string)[]`\n\n### Valid Class Name\n\nA valid class name is based on the context where this type is mentioned. This\nmay be a Fully Qualified Class Name (FQCN) or a local name if present in a\nnamespace.\n\nThe element to which this type applies is either an instance of this class\nor an instance of a class that is a sub/child to the given class.\n\n> It is RECOMMENDED for applications that collect and shape this information to\n> show a list of child classes with each representation of the class. This makes\n> it more obvious for the user which classes are acceptable as this type.\n\n### Keyword\n\nA keyword defines the purpose of this type. Not every element is determined by a\nclass, but it is still worthy of classification to assist the developer in\nunderstanding the code covered by the DocBlock.\n\n> Some of these keywords are allowed as class names in PHP and can be difficult\n> to distinguish from real classes. As such, the keywords MUST be lowercase, as\n> most class names start with an uppercase first character... it is RECOMMENDED\n> that you not use classes with these names in your code.\n\nThe following keywords are recognized by this PSR:\n\n1.  `bool`: the element to which this type applies only has state `TRUE` or `FALSE`.\n\n2.  `int`: the element to which this type applies is a whole number or integer.\n\n3.  `float`: the element to which this type applies is a continuous, or real, number.\n\n4.  `string`: the element to which this type applies is a string of binary characters.\n\n5.  `object`: the element to which this type applies is the instance of an undetermined class.\n\n6.  `array`: the element to which this type applies is an array of values.\n\n7.  `iterable`: the element to which this type applies is an array or Traversable object per the [definition of PHP][PHP_ITERABLE].\n\n8.  `resource`: the element to which this type applies is a resource per the [definition of PHP][PHP_RESOURCE].\n\n9.  `mixed`: the element to which this type applies can be of any type as specified here. It is not known at compile\n    time which type will be used.\n\n10. `void`: this type is commonly only used when defining the return type of a method or function, indicating\n    \"nothing is returned\", and thus the user should not rely on any returned value.\n\n    ```php\n    /**\n     * @return void\n     */\n    function outputHello()\n    {\n        echo 'Hello world';\n    }\n    ```\n\n11. `null`: the element to which this type applies is a `NULL` value or, in technical terms, does not exist.\n\n    Compared to `void`, this type is used in any situation where the described element may at\n    any given time contain an explicit `NULL` value.\n\n    ```php\n    /**\n     * @return null\n     */\n    function foo()\n    {\n        echo 'Hello world';\n        return null;\n    }\n    ```\n\n    ```php\n    /**\n     * @param bool $create_new When true returns a new stdClass.\n     *\n     * @return stdClass|null\n     */\n    function foo($create_new)\n    {\n        if ($create_new) {\n            return new stdClass();\n        }\n        return null;\n    }\n    ```\n\n12. `callable`: the element to which this type applies is a pointer to a function call. This may be any type of callable\n    as per the [definition of PHP][PHP_CALLABLE].\n\n13. `false` or `true`: the element to which this type applies will have the exact value `TRUE` or `FALSE`. No other value will\n    be returned from this element.\n\n14. `self`: the element to which this type applies is of the same class in which the documented element is originally\n    contained.\n\n    **Example:**\n\n    > Method *c* is contained in class *A*. The DocBlock states that its return value is of type `self`. As such, method\n    > *c* returns an instance of class *A*.\n\n    This may lead to confusing situations when inheritance is involved.\n\n    **Example (previous example situation still applies):**\n\n    > Class *B* extends class *A* and does not redefine method *c*. As such, it is possible to invoke method *c* from\n    > class *B*.\n\n    In this situation, ambiguity may arise as `self` could be interpreted as either class *A* or *B*. In these cases,\n    `self` MUST be interpreted as being an instance of the class where the DocBlock containing the `self` type is\n    written.\n\n    In the examples above, `self` MUST always refer to class *A*, since it is defined with method *c* in class *A*.\n\n    > Due to the above nature, it is RECOMMENDED for applications that collect and shape this information to show a list\n    > of child classes with each representation of the class. This would make it obvious for the user which classes are\n    > acceptable as type.\n\n15. `static`: the element to which this type applies is of the same class in which the documented element is contained,\n    or, when encountered in a subclass, is of type of that subclass instead of the original class.\n\n    This keyword behaves the same way as the [keyword for late static binding][PHP_OOP5LSB] (not the static method,\n    property, nor variable modifier) as defined by PHP.\n\n16. `$this`: the element to which this type applies is the same exact instance as the current class in the given\n    context. As such, this type is a stricter version of `static`, because the returned instance must not only be\n    of the same class but also the same instance.\n\n    This type is often used as return value for methods implementing the [Fluent Interface][FLUENT] design pattern.\n\n17. `never`: denotes that element isn't going to return anything and always throws exception or terminates\n    the program abnormally (such as by calling the library function `exit`).\n\n[RFC2119]:      https://tools.ietf.org/html/rfc2119\n[RFC5234]:      https://tools.ietf.org/html/rfc5234\n[PHP_RESOURCE]: https://php.net/manual/language.types.resource.php\n[PHP_ITERABLE]: https://php.net/manual/language.types.iterable.php\n[PHP_PSEUDO]:   https://php.net/manual/language.pseudo-types.php\n[PHP_CALLABLE]: https://php.net/manual/language.types.callable.php\n[PHP_OOP5LSB]:  https://php.net/manual/language.oop5.late-static-bindings.php\n[DEFACTO]:      http://www.phpdoc.org/docs/latest/index.html\n[PHPDOC.ORG]:   http://www.phpdoc.org/\n[FLUENT]:       https://en.wikipedia.org/wiki/Fluent_interface\n[TAG_PSR]:      TBD\n"
  },
  {
    "path": "proposed/psr-8-hug/PSR-8-hug-meta.md",
    "content": "PSR-8 Meta Document\n===================\n\n1. Summary\n----------\n\nThe intent of this spec is to improve the overall amicability and cooperative\nspirit of the PHP community through a standardized means of inter-project\naffection and support.\n\n2. Votes\n--------\n\n- **Entrance Vote:**\n- **Acceptance Vote:**\n\n3. Errata\n---------\n\n4. People\n---------\n\n### 5.1 Editor\n\n- Larry Garfield\n\n### 5.2 Sponsors\n\n- Vacant (Coordinator)\n- Vacant\n"
  },
  {
    "path": "proposed/psr-8-hug/psr-8-hug.md",
    "content": "Mutually Assured Hug\n====================\n\nThe key words \"MUST\", \"MUST NOT\", \"REQUIRED\", \"SHALL\", \"SHALL NOT\", \"SHOULD\",\n\"SHOULD NOT\", \"RECOMMENDED\", \"MAY\", and \"OPTIONAL\" in this document are to be\ninterpreted as described in [RFC 2119](http://tools.ietf.org/html/rfc2119).\n\n## 1. Overview\n\nThis standard establishes a common way for objects to express mutual\nappreciation and support by hugging.  This allows objects to support each other\nin a constructive fashion, furthering cooperation between different PHP projects.\n\n## 2. Specification\n\nThis specification defines two interfaces, \\Psr\\Hug\\Huggable and\n\\Psr\\Hug\\GroupHuggable.\n\n### Huggable objects\n\n1. A Huggable object expresses affection and support for another object by invoking\nits hug() method, passing $this as the first parameter.\n\n2. An object whose hug() method is invoked MUST hug() the calling object back\nat least once.\n\n3. Two objects that are engaged in a hug MAY continue to hug each other back for\nany number of iterations. However, every huggable object MUST have a termination\ncondition that will prevent an infinite loop.  For example, an object MAY be\nconfigured to only allow up to 3 mutual hugs, after which it will break the hug\nchain and return.\n\n4. An object MAY take additional actions, including modifying state, when hugged.\nA common example is to increment an internal happiness or satisfaction counter.\n\n### GroupHuggable objects\n\n1. An object may optionally implement GroupHuggable to indicate that it is able\nto support and affirm multiple objects at once.\n\n## 3. Interfaces\n\n### HuggableInterface\n\n```php\nnamespace Psr\\Hug;\n\n/**\n * Defines a huggable object.\n *\n * A huggable object expresses mutual affection with another huggable object.\n */\ninterface Huggable\n{\n\n    /**\n     * Hugs this object.\n     *\n     * All hugs are mutual. An object that is hugged MUST in turn hug the other\n     * object back by calling hug() on the first parameter. All objects MUST\n     * implement a mechanism to prevent an infinite loop of hugging.\n     *\n     * @param Huggable $h\n     *   The object that is hugging this object.\n     */\n    public function hug(Huggable $h);\n}\n```\n\n```php\nnamespace Psr\\Hug;\n\n/**\n * Defines a huggable object.\n *\n * A huggable object expresses mutual affection with another huggable object.\n */\ninterface GroupHuggable extends Huggable\n{\n\n  /**\n   * Hugs a series of huggable objects.\n   *\n   * When called, this object MUST invoke the hug() method of every object\n   * provided. The order of the collection is not significant, and this object\n   * MAY hug each of the objects in any order provided that all are hugged.\n   *\n   * @param Huggable[] $huggables\n   *   An array or iterator of objects implementing the Huggable interface.\n   */\n  public function groupHug($huggables);\n}\n```\n"
  },
  {
    "path": "proposed/security-disclosure-publication-meta.md",
    "content": "Security Disclosure Meta Document\n=================================\n\n1. Summary\n----------\n\nThere are two aspects with dealing with security issues: One is the process\nby which security issues are reported and fixed in projects, the other\nis how the general public is informed about the issues and any remedies\navailable. While PSR-9 addresses the former, this PSR, ie. PSR-10, deals with\nthe later. So the goal of PSR-10 is to define how security issues are disclosed\nto the public and what format such disclosures should follow. Especially today\nwhere PHP developers are sharing code across projects more than ever, this PSR\naims to ease the challenges in keeping an overview of security issues in all\ndependencies and the steps required to address them.\n\n2. Why Bother?\n--------------\n\nEnd users  want to ensure that they stay informed about security issues.\nHowever they also want to be able to quickly check if they are affected to be\nable to take the necessary steps.\n\nUpstream users of code will also want to know these details. Furthermore they\nwill want to know if its possible for them to be included into possible closed\ndiscussions before details about a security issue are made public.\n\n3. Scope\n--------\n\n## 3.1 Goals\n\n* Means to help in (semi-)automating discovery and fixing of known security\n  issues in projects using the affected code\n\n## 3.2 Non-Goals\n\n* Process for how vulnerabilities are reported and fixed\n* Methods for reducing security vulnerabilities\n\n4. Approaches\n-------------\n\nA key aspect here is that the information flow should be as structured as\npossible to enable as much automation as possible. For example,\nvulnerabilities should be published in a defined location and in a defined\nformat. Inspiration could be taken from [1].\n\nThat being said, the standard should not rely on any central authority\nabove the projects. This is to ensure that no project becomes depend on an\noutside authority for something as sensitive as security related topics.\nHowever due to defined locations and formats, it will become possible for\nother people to build centralized tools around this information.\n\n5. People\n---------\n\n### 5.1 Editor\n\n* Michael Hess\n\n### 5.2 Sponsors\n\n* Larry Garfield (Drupal)\n* Korvin Szanto (concrete5)\n\n### 5.3 Coordinator\n\n* Korvin Szanto (concrete5)\n\n### 5.4 Contributors\n\n* Lukas Kahwe Smith\n\n6. Votes\n--------\n\n7. Relevant Links\n-----------------\n\n[1]: https://github.com/FriendsOfPHP/security-advisories\n\nInitial discussion: https://groups.google.com/d/msg/php-fig/45AIj5bPHJ4/ThERB43j-u8J\nDiscussion: https://groups.google.com/forum/#!forum/php-fig-psr-9-discussion\n"
  },
  {
    "path": "proposed/security-disclosure-publication.md",
    "content": "## Introduction\n\nThere are two aspects with dealing with security issues: One is the process\nby which security issues are reported and fixed in projects, the other\nis how the general public is informed about the issues and any remedies\navailable. While PSR-9 addresses the former, this PSR, ie. PSR-10, deals with\nthe later. So the goal of PSR-10 is to define how security issues are disclosed\nto the public and what format such disclosures should follow. Especially today\nwhere PHP developers are sharing code across projects more than ever, this PSR\naims to ease the challenges in keeping an overview of security issues in all\ndependencies and the steps required to address them.\n\nThe key words \"MUST\", \"MUST NOT\", \"REQUIRED\", \"SHALL\", \"SHALL NOT\", \"SHOULD\",\n\"SHOULD NOT\", \"RECOMMENDED\", \"MAY\", and \"OPTIONAL\" in this document are to be\ninterpreted as described in [RFC 2119][].\n\n[RFC 2119]: http://tools.ietf.org/html/rfc2119\n\n## Goal\n\nThe goal of this PSR is to give project leads a clearly defined approach\nto enabling end users to discover security disclosures using a clearly\ndefined structured format for these disclosures.\n\n## Disclosure Discovery\n\nEvery project MUST provide a link to its security vulnerability database in\nan obvious place. Ideally this should be on the root page of the main domain of the given\nproject. This MAY be a sub-domain in case it is a sub-project of a larger\ninitiative. If the project has a dedicated page for its disclosure process\ndiscovery then this is also considered a good place for this link.\nThe link MAY use the custom link relation ``php-vuln-disclosures``,\nie. for example\n``<link rel=\"php-vuln-disclosures\" href=\"http://example.org/disclosures\"/>``.\n\nNote that projects MAY choose to host their disclosure files on a domain\nother than their main project page. It is RECOMMENDED to not store the\ndisclosures in a VCS as this can lead to the confusions about which branch\nis the relevant branch. If a VCS is used then additional steps SHOULD be taken\nto clearly document to users which branch contains all vulnerabilities for\nall versions. If necessary projects MAY however split vulnerability disclosure\nfiles by major version number. In this case again this SHOULD be clearly\ndocumented.\n\n## Disclosure Format\n\nThe disclosure format is based on Atom [1], which in turn is based on XML. It\nleverages the \"The Common Vulnerability Reporting Framework (CVRF) v1.1\" [2].\nSpecifically it leverages its dictionary [3] as its base terminology.\n\n**TODO**: Should we also provide a JSON serialization to lower the bar for projects.\nAggregation services can then spring up to provide an Atom representation of\nthese disclosures in JSON format.\n\nThe Atom extensions [4] allow a structured description of the vulnerability to\nenable automated tools to determine if installed is likely affected by the\nvulnerability. However human readability is considered highly important and as\nsuch not the full CVRF is used.\n\n**TODO**: Review the Atom format and the supplied XSD\n\nNote that for each vulnerability only a single entry MUST be created. In case\nany information changes the original file MUST be updated along with the last\nupdate field.\n\nAny disclosure uses ``entryType`` using the following tags from the Atom\nnamespace (required tags are labeled with \"MUST\"):\n\n* title (short description of the vulnerability and affected versions, MUST)\n* summary (description of the vulnerability)\n* author (contact information, MUST)\n* published (initial publication date, MUST)\n* updated (date of the last update)\n* link (to reference more information)\n* id (project specific vulnerability id)\n\nIn addition the following tags are added:\n\n* reported (initial report date)\n* reportedBy (contact information for the persons or entity that initially reported the vulnerability)\n* resolvedBy (contact information for the persons or entity that resolved the vulnerability)\n* name (name of the product, MUST)\n* cve (unique CVE ID)\n* cwe (unique CWE ID)\n* severity (low, medium high)\n* affected (version(s) using composer syntax [5])\n* status (open, in progress, disputed, completed, MUST)\n* remediation (textual description for how to fix an affected system)\n* remediationType (workaround, mitigation, vendor fix, none available, will not fix)\n* remediationLink (URL to give additional information for remediation)\n\n[1] https://tools.ietf.org/html/rfc4287\n[2] http://www.icasi.org/cvrf-1.1\n[3] http://www.icasi.org/cvrf-1.1-dictionary\n[4] security-disclosure-publication.xsd\n[5] https://getcomposer.org/doc/01-basic-usage.md#package-versions\n"
  },
  {
    "path": "proposed/security-disclosure-publication.xsd",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<xs:schema\n        xmlns:xs=\"http://www.w3.org/2001/XMLSchema\"\n        targetNamespace=\"http://www.php-fig.org/schemas/security-disclosure\"\n        xmlns:sd=\"http://www.php-fig.org/schemas/security-disclosure\"\n        xmlns:atom=\"http://www.w3.org/2005/Atom\"\n        elementFormDefault=\"qualified\">\n\n    <xs:element name=\"name\" type=\"xs:string\" />\n\n    <xs:element name=\"cve\" type=\"xs:string\" />\n\n    <xs:element name=\"cwe\" type=\"xs:string\" minOccurs=\"0\" />\n\n    <xs:element name=\"reported\" type=\"atom:dateTimeType\" minOccurs=\"0\" maxOccurs=\"1\" />\n\n    <xs:element name=\"reportedBy\" type=\"atom:personType\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n\n    <xs:element name=\"resolvedBy\" type=\"atom:personType\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n\n    <xs:simpleType name=\"severity\">\n        <xs:restriction base=\"xs:string\">\n            <xs:enumeration value=\"low\" />\n            <xs:enumeration value=\"medium\" />\n            <xs:enumeration value=\"high\" />\n        </xs:restriction>\n    </xs:simpleType>\n\n    <xs:simpleType name=\"status\">\n        <xs:restriction base=\"xs:string\">\n            <xs:enumeration value=\"open\" />\n            <xs:enumeration value=\"in progress\" />\n            <xs:enumeration value=\"disputed\" />\n            <xs:enumeration value=\"completed\" />\n        </xs:restriction>\n    </xs:simpleType>\n\n    <xs:element name=\"remediation\" type=\"sd:remediationType\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n\n    <xs:complexType name=\"remediationType\">\n        <xs:annotation>\n            <xs:documentation>\n                The PHP FIG security disclosure remediation construct is to be used to specify a specific remediation\n                option for a specific vulnerability.\n            </xs:documentation>\n        </xs:annotation>\n        <xs:choice maxOccurs=\"unbounded\">\n            <xs:element name=\"summary\" type=\"xs:string\" />\n\n            <xs:element name=\"affected\" type=\"xs:string\" />\n\n            <xs:simpleType name=\"type\">\n                <xs:restriction base=\"xs:string\">\n                    <xs:enumeration value=\"workaround\" />\n                    <xs:enumeration value=\"mitigation\" />\n                    <xs:enumeration value=\"none available\" />\n                    <xs:enumeration value=\"will not fix\" />\n                </xs:restriction>\n            </xs:simpleType>\n\n            <xs:element name=\"link\" type=\"atom:linkType\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n        </xs:choice>\n    </xs:complexType>\n\n</xs:schema>\n"
  },
  {
    "path": "proposed/security-reporting-process-meta.md",
    "content": "Security Disclosure Meta Document\n=================================\n\n1. Summary\n----------\n\nThere are two aspects with dealing with security issues: One is the process\nby which security issues are reported and fixed in projects, the other\nis how the general public is informed about the issues and any remedies\navailable. While PSR-10 addresses the later, this PSR, ie. PSR-9, deals with\nthe former. So the goal of PSR-9 is to define the process by which security\nresearchers and report security vulnerabilities to projects. It is important\nthat when security vulnerabilities are found that researchers have an easy\nchannel to the projects in question allowing them to disclose the issue to a\ncontrolled group of people.\n\n2. Why Bother?\n--------------\n\nAs of right now, there isn't a common standard for most parts of this process.\nThat is there isn't a standard where researchers can find out about the\nprocess for handling security issues for any given project. There is also\nno standard that explains to researchers what they can expect to happen if\nthey report a vulnerability. More importantly there is no standard on which\nprojects can base the security reporting process that best fits them.\n\n3. Scope\n--------\n\n## 3.1 Goals\n\n* A defined process for how vulnerabilities are reported, the process by which\n  these get fixed and finally disclosed to the public\n\n## 3.2 Non-Goals\n\n* Methods for reducing security vulnerabilities\n* Publication of security issues and fixes (see PSR-10)\n\n4. Approaches\n-------------\n\nCurrently the most viable approach seems to be defining a base line workflow\nfor how security vulnerabilities go from discovery to fixing to public\ndisclosure. Inspiration could be drawn from this list of security disclosure\nprocesses in various PHP and non-PHP projects:\n\n* https://symfony.com/security\n* https://framework.zend.com/security\n* https://www.yiiframework.com/security\n* https://www.drupal.org/security\n* https://codex.wordpress.org/FAQ_Security\n* https://www.sugarcrm.com/legal/security-policy\n* https://typo3.org/teams/security/\n* https://book.cakephp.org/3.0/en/contributing/tickets.html#reporting-security-issues\n* https://www.concrete5.org/developers/security/\n* https://developer.joomla.org/security.html\n* https://wiki.horde.org/SecurityManagement\n* https://www.revive-adserver.com/support/bugs/\n* https://magento.com/security\n* https://www.apache.org/security/committers.html\n* https://www.mozilla.org/en-US/about/governance/policies/security-group/bugs/\n* https://www.openbsd.org/security.html\n\nA summary of the differences and similarities can be found here:\nhttps://groups.google.com/d/msg/php-fig-psr-9-discussion/puGV_X0bj_M/Jr_IAS40StsJ\n\n5. People\n---------\n\n### 5.1 Editor\n\n* Michael Hess\n\n### 5.2 Sponsors\n\n* Larry Garfield (Drupal)\n* Korvin Szanto (concrete5)\n\n### 5.3 Coordinator\n\n* Larry Garfield (Drupal)\n\n### 5.4 Contributors\n\n* Lukas Kahwe Smith\n\n6. Votes\n--------\n\n7. Relevant Links\n-----------------\n"
  },
  {
    "path": "proposed/security-reporting-process.md",
    "content": "## Introduction\n\nThere are two aspects with dealing with security issues: One is the process\nby which security issues are reported and fixed in projects, the other\nis how the general public is informed about the issues and any remedies\navailable. While PSR-10 addresses the later, this PSR, ie. PSR-9, deals with\nthe former. So the goal of PSR-9 is to define the process by which security\nresearchers and report security vulnerabilities to projects. It is important\nthat when security vulnerabilities are found that researchers have an easy\nchannel to the projects in question allowing them to disclose the issue to a\ncontrolled group of people.\n\nThe key words \"MUST\", \"MUST NOT\", \"REQUIRED\", \"SHALL\", \"SHALL NOT\", \"SHOULD\",\n\"SHOULD NOT\", \"RECOMMENDED\", \"MAY\", and \"OPTIONAL\" in this document are to be\ninterpreted as described in [RFC 2119][].\n\n[RFC 2119]: http://tools.ietf.org/html/rfc2119\n\n## Goal\n\nThe goal of this PSR is to give researchers, project leads, upstream project\nleads and end users a defined and structured process for disclosing security\nvulnerabilities.\n\n## Security Disclosure Process Discovery\n\nEvery project MUST provide a link to its security disclosure process in\nan obvious place. Ideally this should be on the root page the main domain of\nthe given project. This MAY be a sub-domain in case it is a sub-project of a\nlarger initiative. The link MAY use the custom link relation\n``php-vuln-reporting``, ie. for example\n``<link rel=\"php-vuln-reporting\" href=\"http://example.org/security\"/>``.\n\nProjects SHOULD ideally make the location prominent itself\nby either creating a dedicated sub-domain like ``http://security.example.org``\nor by making it a top level directory like ``http://example.org/security``.\nAlternatively projects MAY also simply reference this document, ie. PSR-9.\nBy referencing PSR-9 a project basically states that they follow the\ndefault procedures as noted in the section \"Default Procedures\" towards\nthe end of this document. Projects MUST list the variables noted at the start\nof that section in this reference (ie. project name, project domain, etc.).\nProjects MAY choose to list any part of the procedures that is not a MUST\nwhich they choose to omit.\n\nNote that projects MAY not have a dedicated domain. For example a project\nhosted on GitHub, Bitbucket or other service should still ensure that the\nprocess is referenced on the landing page, ie. for example\nhttp://github.com/example/somelib should ensure that the default branch\nhas a README file which references the procedures used so that it is\nautomatically displayed.\n\nIf necessary projects MAY have different disclosure process\nfor different major version number. In this case one URL MUST be provided\nfor each major version. In the case a major version is no longer receiving\nsecurity fixes, instead of an URL a project MAY opt to instead simply\nnote that the version is no longer receiving security fixes.\n\n## Security Disclosure Process\n\nEvery project MUST provide an email address in their security disclosure\nprocess description as the ``contact email address``. Projects SHALL NOT\nuse contact forms.\n\n**TODO**: Add more things found here https://groups.google.com/d/msg/php-fig-psr-9-discussion/puGV_X0bj_M/Jr_IAS40StsJ?\n\n## Default Procedures\n\n* ``[project name]`` denotes the name on which the project uses to identify itself.\n* ``[project domain]`` denotes the main (sub)domain on which the project relies.\n\nIf not specified otherwise, the ``contact email address`` is ``security@[project domain]``.\n\n**TODO**: Add more things noted in the previous section"
  },
  {
    "path": "proposed/tracing-meta.md",
    "content": "# Application Tracing Meta Document\n\n## 1. Summary\n\nApplication performance monitoring (APM) tools are becoming increasingly popular, however, the lack of formal interfaces is holding back the ecosystem.\nWhilst developers are inherently free to use whichever tools suit their use-cases, this is not the case for framework and library creators/maintainers.\n\nThis standard aims to create an intentionally minimalist set of interfaces that can be used to provide tracing signals to 3rd party libraries in a unified manner.\n\n## 2. Why Bother?\n\nThe [OpenTelemetry][] team are in the process of releasing a set of SDK's that would allow frameworks and libraries to send signals to providers in a uniformed manner.\nHowever, there is a perceived expectation of a 1-way flow of responsibility, where Frameworks and Libraries are expected to accept Jagger-formatted traces.\n\nThis PSR provides a bridge between Frameworks and Libraries who want to provide tracing signals, and Providers, without the requirement to make large scale changes to their infrastructure, etc.  \nBy taking transmission mechanisms [out of scope](#31-non-goals) for this PSR, we drastically increase the simple adoptability of tracing for all parties involved\n\n[OpenTelemetry]: https://opentelemetry.io/\n\n## 3. Scope\n\n### 3.1 Goals\n\n* To provide a set of interfaces for library and framework developers to add tracing signals to their codebase.  \n  This would in turn allow other libraries to receive the same signals for further processing or analysis.\n* To allow traces collected by various providers to be reused by other providers.\n* This PSR may provide a minimal `TraceProvider`, etc. for other providers to extend, should they choose.\n\n### 3.1 Non-goals\n\n* This PSR does not provide a comprehensive tracing client\n* This PSR does not define the mechanisms used for transmitting the data to 3rd party systems\n* This PSR does not cover collecting metrics within a codebase, only traces\n\n## 4. Approaches\n\nTo fulfil the requirement of most providers, this PSR will be loosely modeled on the [OpenTelemetry Tracing Specification][OTelTrace] and [Tracing API][OtelTraceApi].  \nWe aim to allow the majority of providers to use the PSR interfaces with minimum backwards incompatible changes to encourage adoption.\n\n[OtelTrace]: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/overview.md#tracing-signal\n[OtelTraceApi]: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/api.md\n\n## 5. People\n\n### 5.1 Editor\n* Adam Allport\n\n### 5.1 Sponsor\n* Alessandro Chitolina\n\n### Working Group Members\n* Alex Bouma\n* Ben Edmunds\n* Brett McBride\n* Timo Michna\n\n## 6. Votes\n\n* [Entrance Vote](TBD)\n"
  },
  {
    "path": "proposed/tracing.md",
    "content": "# Application Tracing\n\nThe key words \"MUST\", \"MUST NOT\", \"REQUIRED\", \"SHALL\", \"SHALL NOT\", \"SHOULD\",\n\"SHOULD NOT\", \"RECOMMEND\", \"MAY\", and \"OPTIONAL\" in this document are to\ninterpreted as described in [RFC 2119][].\n\nThe final implementations MAY decorate the objects with more functionality than\ncovered in the recommendation however they MUST implement the indicated\ninterfaces and functionality first.\n\n[RFC 2119]: http://tools.ietf.org/html/rfc2119\n\n## Goal\n\nTBD\n\n## Definitions\n\n* **Framework** - An application framework (or micro-framework) that runs a developers code.  \n  Eg. Laravel, Symfony, CakePHP, Slim\n* **Library** - Any library that developers may include that adds additional functionality  \n  Eg. Image Manipulation, HTTP Clients, 3rd Party SDK's \n* **Provider** - An organization that offers APM as a service. Typically via a composer package\n"
  }
]