Hi php internals,
I recently discovered the "friendship concept" in c++ and i really love
the concept.
And i wonder if the php internals would be interested to implements it in
the next 7.x major version.
The concept is simple:
It would allow declared "friend"class method/function to call a
private/protected member of an other class:
The syntax could be like this (for a single friendship):
private function extractDataFromCache() friend myFriendClass1
{
}
or like this for many friendships:
private function extractDataFromCache() friend
{myFriendClass1::method1, myFriendClass2::method1,
myFriendClass3::method1}
{
}
In this way extractDataFromCache() could be called directly by method1 in
myFriendClass1 and myFriendClass2 etc....
Off course deep calling should not be allowed. (E.g a function inside
myFriendClass1 that will call extractDataFromCache() won't inherit the
friendship.
Regards,
Georges
Hi Georges,
georges wrote:
Hi php internals,
I recently discovered the "friendship concept" in c++ and i really love
the concept.
And i wonder if the php internals would be interested to implements it in
the next 7.x major version.
I recently wished PHP had this feature when trying to implement the
Khronos Group Typed Arrays specification in PHP, which requires sharing
certain data between unrelated (inheritance-wise) classes. I ended up
having to expose a public method to get the data, but named in a way
that was likely to deter use.
I think friend classes might be useful, then. I'm not sure if they're
necessarily something we should add to HPP, though. Are there that many
use-cases?
Thanks.
--
Andrea Faulds
http://ajf.me/
Andrea Faulds wrote on 01/11/2015 19:35:
I recently wished PHP had this feature when trying to implement the
Khronos Group Typed Arrays specification in PHP, which requires
sharing certain data between unrelated (inheritance-wise) classes. I
ended up having to expose a public method to get the data, but named
in a way that was likely to deter use.
Would "package" (namespace-based) visibility have solved the problem in
this case? That's something I've often wanted - "this is public within
this Lib, but should never be used outside it".
Regards,
Rowan Collins
[IMSoP]
Andrea Faulds wrote on 01/11/2015 19:35:
I recently wished PHP had this feature when trying to implement the
Khronos Group Typed Arrays specification in PHP, which requires sharing
certain data between unrelated (inheritance-wise) classes. I ended up
having to expose a public method to get the data, but named in a way that
was likely to deter use.Would "package" (namespace-based) visibility have solved the problem in
this case? That's something I've often wanted - "this is public within this
Lib, but should never be used outside it".This was worked on for 7, but had a fundamental problem blocking it - See
Guilherme's recent runtime execution scope mail.
Hi Rowan,
Rowan Collins wrote:
Andrea Faulds wrote on 01/11/2015 19:35:
I recently wished PHP had this feature when trying to implement the
Khronos Group Typed Arrays specification in PHP, which requires
sharing certain data between unrelated (inheritance-wise) classes. I
ended up having to expose a public method to get the data, but named
in a way that was likely to deter use.Would "package" (namespace-based) visibility have solved the problem in
this case? That's something I've often wanted - "this is public within
this Lib, but should never be used outside it".
Yep, that would have worked, and that sounds like a much cleaner
solution. Package/namespace visibility would solve a bunch of other
use-cases too.
Thanks!
--
Andrea Faulds
http://ajf.me/
Hi Georges,
I quite like this idea. Although I struggle to see many use cases. The only one I’ve thought of in the past is the ability to ‘befriend’ the test case for your class. So you don’t have to extend the class in your tests if you want access to non-public class members.
This is purely a dev use-case, so I question it’s worth. But i’d be interested to hear any other use-case suggestions.
Regards,
James Tancock
Hi Georges,
Le 01/11/2015 17:04, georges a écrit :
Hi php internals,
I recently discovered the "friendship concept" in c++ and i really love
the concept.
And i wonder if the php internals would be interested to implements it in
the next 7.x major version.
You may be interested by an article I wrote some weeks ago about
adapting the 'friendship' concept to PHP
(http://tekwire.net/joomla/projects/ideas/php-friend). IMO, we should
enable friendship from classes and/or namespaces, with and without
inheritance, giving four cases : class, class and descendants,
namespace, namespace and sub-namespaces.
One more detail : I wouldn't set the 'friend' information on the same
line as the class declaration. First reason is that it already contains
'extends' and 'implements' stances. 2nd reason is that the information
is not required by the compiler to start compiling the class body. So,
'friend' lines can be part of the class body.
Use cases go well beyond test classes. There are many cases where you
need to access methods and/or even whole classes from a set of known
locations, but don't want to make them public. Today, the only way is to
use protected access but it implies class inheritance which, often, is
not an option. An example is symfony using the '@internal' tag to mark
class/properties/methods which mustn't be accessed from the outside of
symfony (see
http://symfony.com/doc/current/contributing/code/bc.html#using-our-classes).
Information is better than nothing but a way to enforce access
restrictions would be welcome.
About Guilherme's proposal : it seems fine but, IMHO, the 'friend'
concept includes it, is easier to implement, and goes much further.
Regards
François
Hi,
One thing that should be worth mentioning is that my approach of private
classes is decoupled in 2 parts.
The first one as the ability to prevent instantiation outside of namespace
and sub-namespaces. The second is the ability to access protected members,
which matches your wish of friend classes nicely.
However, I could not even tackle the second part without discussing and
agreeing on the first one, so I limited the scope of my wish in order to
simplify overall RFC phase.
Regards,
Hi Georges,
Le 01/11/2015 17:04, georges a écrit :
Hi php internals,
I recently discovered the "friendship concept" in c++ and i really love
the concept.
And i wonder if the php internals would be interested to implements it in
the next 7.x major version.You may be interested by an article I wrote some weeks ago about adapting
the 'friendship' concept to PHP (
http://tekwire.net/joomla/projects/ideas/php-friend). IMO, we should
enable friendship from classes and/or namespaces, with and without
inheritance, giving four cases : class, class and descendants, namespace,
namespace and sub-namespaces.One more detail : I wouldn't set the 'friend' information on the same line
as the class declaration. First reason is that it already contains
'extends' and 'implements' stances. 2nd reason is that the information is
not required by the compiler to start compiling the class body. So,
'friend' lines can be part of the class body.Use cases go well beyond test classes. There are many cases where you need
to access methods and/or even whole classes from a set of known locations,
but don't want to make them public. Today, the only way is to use protected
access but it implies class inheritance which, often, is not an option. An
example is symfony using the '@internal' tag to mark
class/properties/methods which mustn't be accessed from the outside of
symfony (see
http://symfony.com/doc/current/contributing/code/bc.html#using-our-classes).
Information is better than nothing but a way to enforce access restrictions
would be welcome.About Guilherme's proposal : it seems fine but, IMHO, the 'friend' concept
includes it, is easier to implement, and goes much further.Regards
François
One more detail : I wouldn't set the 'friend' information on the same
line as the class declaration.
I agree, it can look horrible to read, and the way to use the "friend"
syntax as the way that we currently "use" traits can be an interesting idea.
Geolim4
2015-11-02 15:42 GMT+01:00 guilhermeblanco@gmail.com <
guilhermeblanco@gmail.com>:
Hi,
One thing that should be worth mentioning is that my approach of private
classes is decoupled in 2 parts.The first one as the ability to prevent instantiation outside of namespace
and sub-namespaces. The second is the ability to access protected members,
which matches your wish of friend classes nicely.However, I could not even tackle the second part without discussing and
agreeing on the first one, so I limited the scope of my wish in order to
simplify overall RFC phase.Regards,
Hi Georges,
Le 01/11/2015 17:04, georges a écrit :
Hi php internals,
I recently discovered the "friendship concept" in c++ and i really love
the concept.
And i wonder if the php internals would be interested to implements it in
the next 7.x major version.You may be interested by an article I wrote some weeks ago about adapting
the 'friendship' concept to PHP (
http://tekwire.net/joomla/projects/ideas/php-friend). IMO, we should
enable friendship from classes and/or namespaces, with and without
inheritance, giving four cases : class, class and descendants, namespace,
namespace and sub-namespaces.One more detail : I wouldn't set the 'friend' information on the same
line as the class declaration. First reason is that it already contains
'extends' and 'implements' stances. 2nd reason is that the information is
not required by the compiler to start compiling the class body. So,
'friend' lines can be part of the class body.Use cases go well beyond test classes. There are many cases where you
need to access methods and/or even whole classes from a set of known
locations, but don't want to make them public. Today, the only way is to
use protected access but it implies class inheritance which, often, is not
an option. An example is symfony using the '@internal' tag to mark
class/properties/methods which mustn't be accessed from the outside of
symfony (see
http://symfony.com/doc/current/contributing/code/bc.html#using-our-classes).
Information is better than nothing but a way to enforce access restrictions
would be welcome.About Guilherme's proposal : it seems fine but, IMHO, the 'friend'
concept includes it, is easier to implement, and goes much further.Regards
François
Le 02/11/2015 15:42, guilhermeblanco@gmail.com a écrit :
Hi,
One thing that should be worth mentioning is that my approach of
private classes is decoupled in 2 parts.The first one as the ability to prevent instantiation outside of
namespace and sub-namespaces. The second is the ability to access
protected members, which matches your wish of friend classes nicely.However, I could not even tackle the second part without discussing
and agreeing on the first one, so I limited the scope of my wish in
order to simplify overall RFC phase.
If I understand well, in a second step, you plan to extend access
control to protected class members. But it will still be reserved to the
current namespace and sub-namespaces. What I want to implement is the
possibility to authorize access from any class/namespace I want, not
only the current namespace.
I may be wrong, but I consider restricting access to the currrent
namespace as sometimes too rigid, sometimes too permissive. Too rigid
when, in some existing codebase, I want to authorize access from outside
of the current namespace. Too permissive when I want to authorize only a
pair of classes in the current namespace. 'Package-private' does not
provide this flexibility, even if extended to protected members.
Another argument : Imagine you have authorized protected access to
'private' classes from the current namespace. It will happen only in
classes marked as 'private'. So, you will end up with cases where access
to a method is refused because the class was not marked 'private'. In
the case of instantiation, 'private' brings a restriction, which seems
fine. In the case of protected access, 'private' will enable some
additional access, which seems weird, IMO.
Here is a possible syntax for an equivalent of 'package-private' :
class Foo
{
friend NAMESPACE+;
protected function __construct(...) // Access from current namespace
and sub-spaces only
{
...
Another concept I was thinking about is to define several 'friendship'
types in a single class. This would allow a better access control at the
property/method level. Example:
class Foo
{
friend current_ns NAMESPACE+;
friend purge_enabled \MyNS\bar;
protected(current_ns) function __construct(...) // Access from
current namespace and sub-spaces only
{
...
}
protected(purge_enabled) function purge(...) // Can be called from
\MyNS\bar class only
{
...
Combined with a future separated read/write access permission to
properties, this could provide some very precise access control.
Regards
François
I recently discovered the "friendship concept" in c++ and i really
love the concept.
And i wonder if the php internals would be interested to implements it
in the next 7.x major version.
Could you provide use cases where this provides a better interface than
other alternatives? I think there are only very few cases ...
In C++ the primary use-case are binary operators which have to be
written as a free function but need access to private elements. i.e.
class Complex {
int _real, _im;
public:
Complex(int r, int i) : _real(r), _im(i) {}
friend Complex operator+(int a, const Complex& b);
};
Complex operator+(int a, const Complex& b) {
return Complex(a + b._real, b._im);
}
Here the operator+(int, const Complex&) can't be part of a class as the
first operand is a built-in while logically it belongs to the class's
interface.
(note: this specific example isn't good as we could provide accessors to
the real and imaginary part of our complex number but there are cases
where this isn't possible/wanted)
We don't have this situation in PHP, though.
johannes
Hi php internals,
I recently discovered the "friendship concept" in c++ and i really love
the concept.
And i wonder if the php internals would be interested to implements it in
the next 7.x major version.The concept is simple:
It would allow declared "friend"class method/function to call a
private/protected member of an other class:The syntax could be like this (for a single friendship):
private function extractDataFromCache() friend myFriendClass1
{}
or like this for many friendships:
private function extractDataFromCache() friend
{myFriendClass1::method1, myFriendClass2::method1,
myFriendClass3::method1}
{}
In this way extractDataFromCache() could be called directly by method1 in
myFriendClass1 and myFriendClass2 etc....Off course deep calling should not be allowed. (E.g a function inside
myFriendClass1 that will call extractDataFromCache() won't inherit the
friendship.Regards,
Georges
As Rowan already wrote, package / namespace visibility is the way to go
here instead. Personally I found adding "friendship" in C++ to be a poor
decision, since it's usually a sign of a code smell (not always
though). There are admittedly a couple of use cases, but keeping things
inside a private namespace is probably a more elegant solution.
I'd support namespace visibility. +1
--
Stephen