{"action":"created","issue":{"url":"https://api.github.com/repos/phpDocumentor/fig-standards/issues/114","labels_url":"https://api.github.com/repos/phpDocumentor/fig-standards/issues/114/labels{/name}","comments_url":"https://api.github.com/repos/phpDocumentor/fig-standards/issues/114/comments","events_url":"https://api.github.com/repos/phpDocumentor/fig-standards/issues/114/events","html_url":"https://github.com/phpDocumentor/fig-standards/issues/114","id":112562705,"number":114,"title":"@api vs @internal and @package - package scopes","user":{"login":"mindplay-dk","id":103348,"avatar_url":"https://avatars.githubusercontent.com/u/103348?v=3","gravatar_id":"","url":"https://api.github.com/users/mindplay-dk","html_url":"https://github.com/mindplay-dk","followers_url":"https://api.github.com/users/mindplay-dk/followers","following_url":"https://api.github.com/users/mindplay-dk/following{/other_user}","gists_url":"https://api.github.com/users/mindplay-dk/gists{/gist_id}","starred_url":"https://api.github.com/users/mindplay-dk/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mindplay-dk/subscriptions","organizations_url":"https://api.github.com/users/mindplay-dk/orgs","repos_url":"https://api.github.com/users/mindplay-dk/repos","events_url":"https://api.github.com/users/mindplay-dk/events{/privacy}","received_events_url":"https://api.github.com/users/mindplay-dk/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":16,"created_at":"2015-10-21T11:02:36Z","updated_at":"2015-10-26T10:53:58Z","closed_at":null,"body":"I think that dealing with package scopes and internal/external APIs needs work.\r\n\r\nStarting with `@api`, which I find to be extremely backwards:\r\n\r\n> The @api tag represents those \"Structural Elements\" with a public visibility which are intended to be the public API components for a library or framework\r\n\r\nFor the most part, the `public`, `protected` and `private` keywords are more than sufficient to designate something as being part of a public API (`public` or `protected`) vs things that are internal (`private`) to a library or framework.\r\n\r\n> Other \"Structural Elements\" with a public visibility serve to support the internal structure and are not recommended to be used by the consumer.\r\n\r\nIn other words, you're trying to make public APIs an \"opt-in\" feature, which seems completely backwards to me.\r\n\r\nAs a matter of fact, due to the way that the PHP language (and most other OO lanugages) works, `public` and `protected` *are* the keywords that designate elements as being public API components.\r\n\r\nIn the large majority of cases, this is also true, though there are of course exceptions - and we don't have any means of dealing with that in the PHP language, nor do we currently have an annotation for that.\r\n\r\nC# for example has the [internal](https://msdn.microsoft.com/en-us/library/7c5ka91b.aspx) keyword, which is an annotation that can be used to designate a `public` or `private` member as being internal *to the package it belongs to*.\r\n\r\nThis is useful, and a much more sensible default - opting *out* of your natural (per the language itself) responsibility to support a public or protected API is much less of a burden, since, most of the time, if you declared something `public` or `protected`, you're actually doing so because you intend those members for public consumption.\r\n\r\nThe exception is cases like e.g. internal models or services - components intended for consumption only internally by the package itself, but which have `public` or `protected` visibility, in order to provide internal API structures. Internal to the package, that is.\r\n\r\nThe burden of having to sift through existing codebases and flag the large majority of classes and interfaces as non-internal, is staggering - to expect that the community at large is going to do so, is completely unrealistic.\r\n\r\nIt's far more realistic to expect that some project maintainers have certain internal components (or members) that they would like to flag as internal, and it's much less of a burden.\r\n\r\nI'm suggesting that internal APIs need to opt-out from the public/protected visibility defined by the language itself, by flagging those as internal - rather than opting into the natural, default, given behavior implied by PHP itself. We should assume things are non-internal, because that's what the language assumes.\r\n\r\nIn other words, we shouldn't have to flag elements as non-internal - we should assume they're non-internal, and provide a means of flagging elements as internal instead.\r\n\r\n> all tagged \"Structural Elements\" SHOULD NOT change after publication unless the new version is tagged as breaking Backwards Compatibility\r\n\r\nThis would immediately, at the inception of this PSR, mean that *every package in existence* will have to make a BC break and a major version increase, because currently every single API point in very package is *assumed* internal. I think this is pretty clearly wrong.\r\n\r\nThe other big question raised by the introduction of the concept of internal/external visibility itself is, if an element is considered internal, internal to what scope? A Composer package? A namespace? (which one?) or a \"package\" in php-doc terms perhaps, e.g. defined using [@package](https://github.com/phpDocumentor/fig-standards/blob/master/proposed/phpdoc.md#812-package) ?\r\n\r\nThis question appears to be unaddressed at the moment. We can't introduce the concept of internal/external visibility without defining what that means.\r\n\r\nIn C#, internal means internal the current module. The closest analog to modules in PHP at the moment would be Composer packages. They are also the only of the three (composer, namespaces, php-doc package tags) that have any physical boundary defining any applicable scope, e.g. the folder (and sub-folders) under the nearest `composer.json` package definition.\r\n\r\nThis might once again throws the meaningfulness of `@package` into question, but perhaps that's another discussion.\r\n\r\nOn the other hand, if `@package` provides a \"logical subdivision\", and assuming elements were external by default, when you tag something as internal, requiring you to tag files and classes with `@package` would force you to define which components *are* allowed to access something that has been marked as internal. And to do so independently of namespaces or package boundaries. It could actually lend more meaning to the idea of \"logical subdivisions\" which currently aren't very meaningful, in my opinion.\r\n\r\nFinally, this has to raise natural questions about [@internal](https://github.com/phpDocumentor/fig-standards/blob/master/proposed/phpdoc.md#88-internal) due to the terminology - internal being the semantic opposite of external.\r\n\r\n> The `@internal` tag is used to denote that the associated \"Structural Element\" is a structure internal to this application or library\r\n\r\nWhich is precisely what we're trying to do. Although, as discussed above, \"to this application or library\" is a fuzzy boundary - an IDE or other static analysis tool wouldn't be able to verify anything based on that, and to a human being, it would be a subjective assessment, so for this to make sense, we still need a clear definition of that boundary.\r\n\r\n> The `@internal` tag can be used as counterpart of the `@api` tag, indicating that the associated \"Structural Element\" is used purely for the internal workings of this piece of software.\r\n\r\nThis doesn't make sense. The `@api` tag says you have to opt-out and everything is internal by default, but this tag says you have to opt-in.\r\n\r\nWe're talking about a strictly binary condition here: things are either internal or external. They can't be both, so having two opposing tags doesn't make sense. If it's a binary condition, every element for which nothing is defined *has* to be either internal or external by default, otherwise there's a third \"undefined\" state, which would raise even more questions.\r\n\r\nI would suggest removing the `@api` tag and defining (after further discussion) the strict meaning and scope of `@internal`.\r\n"},"comment":{"url":"https://api.github.com/repos/phpDocumentor/fig-standards/issues/comments/151098800","html_url":"https://github.com/phpDocumentor/fig-standards/issues/114#issuecomment-151098800","issue_url":"https://api.github.com/repos/phpDocumentor/fig-standards/issues/114","id":151098800,"user":{"login":"mindplay-dk","id":103348,"avatar_url":"https://avatars.githubusercontent.com/u/103348?v=3","gravatar_id":"","url":"https://api.github.com/users/mindplay-dk","html_url":"https://github.com/mindplay-dk","followers_url":"https://api.github.com/users/mindplay-dk/followers","following_url":"https://api.github.com/users/mindplay-dk/following{/other_user}","gists_url":"https://api.github.com/users/mindplay-dk/gists{/gist_id}","starred_url":"https://api.github.com/users/mindplay-dk/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mindplay-dk/subscriptions","organizations_url":"https://api.github.com/users/mindplay-dk/orgs","repos_url":"https://api.github.com/users/mindplay-dk/repos","events_url":"https://api.github.com/users/mindplay-dk/events{/privacy}","received_events_url":"https://api.github.com/users/mindplay-dk/received_events","type":"User","site_admin":false},"created_at":"2015-10-26T10:53:58Z","updated_at":"2015-10-26T10:53:58Z","body":"IMO, overloading the meaning of the terms public, private and protected is even worse than overloading the term \"package\".\r\n\r\nI don't know Java very well - but in C#, the internal modifier is applicable to:\r\n\r\n  * classes: all classes are \"public\" by default (same as in PHP and most languages) but can be made \"internal\" to the package.\r\n  * public methods/properties: an internal public property/method is visible only to other components in the same package.\r\n  * protected methods/properties: an internal protected property/method is visible only to components in the same package inheriting those members from a parent class.\r\n\r\nThere were common use-cases for all of those scenarios while I worked with C# some years ago - and there was never a case where I was unable to declare a suitable visibility. I think it covers everything \"real\".\r\n\r\nIn C#, the `internal` modifier applies to the current assembly - PHP itself has no analog to that, and probably the closest analog would be Composer packages, but namespaces (used properly) would work as well, except in some cases (as mentioned) where you'd have to specify which (parent) namespace something is internal to.\r\n\r\nBesides, IMO, what you're proposing is far too complex and difficult to explain - we need to come up with a simple solution; preferably something that requires no introduction of new concepts, and, especially, something that doesn't overload known concepts. (and I don't consider what I proposed as \"overloading\" the namespace concept, because it doesn't *change* the meaning of what a namespace is - it just introduces the new, independent concept of being \"internal\", and reuses the existing namespace concept as-is.)\r\n\r\nAs far as inheritance, with this approach, there's not much to worry about - it's simple:\r\n\r\n  * If a class is internal, you can't extend that class from an external scope, at all - hence no further rules about accessing it's members are needed.\r\n  * If a member method/property is internal, you can't access that method/property from an external scope, at all - hence no further rules about accessing those members is needed.\r\n\r\nInternally in a package, the internal attribute is *never* inherited by classes - if you extend an internal class, and you want the new class to also be internal, you have to declare it as internal. An extended class is a new class - we make no assumptions about whether it's internal. The same goes for interfaces - you don't inherit being internal by implementing an internal interface - any class/interface declaration is external unless explicitly marked as internal.\r\n\r\nContrary to that, when it comes to methods/properties, the internal attribute is *always* inherited, and can't be suppressed. This follows the same basic rules as inheriting public/protected/private methods/properties: if something was declared public/protected/private/internal, and is inherited, you inherit the visibility of that member - and you're not allowed to lower the visibility. (public internal is a lower visibility than public, protected is lower than that, internal protected is even lower, and so on.)\r\n\r\n> First thing is that we limit this stuff to classes, interfaces, and traits. Nothing else can use these tags because it does not make much sense for anything else. Well, maybe namespace functions and constants, but I think they should always be public to the world; do you agree? Other procedural stuff is per language global and thus does not need any modifier.\r\n\r\nClasses, interfaces and traits are also globally visible per the language - I think anything that is globally visibile (and namespaced) should be applicable, so that includes namespaced functions/consts; I don't see any reason not to allow controlling the visibility of those?\r\n\r\nThe important limitation on this modifier, is that it's only applicable within a namespace - since, if something was \"internal\" to the global namespace, that means it's \"internal\" to, well, everyone ;-)\r\n"}}