Could someone explain me, why is it possible to do the following in PHP, but, for example, not in C# or Java:
Class A {
protected $a = 'Howdy!';
}
Class B extends A {
public function howdy() {
$created = new A();
echo $created->a; <----- This is legal due to per-class visibility
}
}
$b = new B();
echo $b->howdy(); <----- Hence, no fatal error here
This behavior seems to be specified here, but I can't understand the fundamental reason behind this (to my mind, one can't simply implement the per-class visibility instead of the per-instance one without having a strong reason for that).
The reason it doesn't work is, as you specified, PHP implements access control on a class level, where other languages use an instance level approach.
Why is it useful? It allows your classes to operate on other instances of itself without exposing its private data. Let's take a simple value-object example:
class Int {
protected $value = 0;
public function __construct($value) {
$this->value = (int) $value;
}
public function add(Int $new) {
return new Int($new->value + $this->value);
}
}
$a = new Int(1);
$b = new Int(2);
$c = $a->add($b);
This lets you keep protected info encapsulated, yet still work with it across instances...
There are pros and cons to both approaches...
That is also possible in C# (and Java for that matter).
class A // declare new class type B
{
protected string a = "Howdy!"; // that has a protected member called `a`
}
class B : A // declare new type B which extends type A
{
public void howdy()
{
A created = new A();
Console.WriteLine(created.a); // no problem accessing a b/c B extends A
}
}
B bInst = new B(); // create a new instance of type B
bInst.howdy(); // invoke it's public method howdy()
Basically what is going on is this:
class A contains a protected member called a which means it is visible in the scope of classes which extend A (in our case class B)
class B extend a so it has access to it's protected members (in our case to a)
It is possible to do in both C# and Java as well. protected means the variable is accessible from any subclass of A. B is a subclass of A, hence it can access the variable. There's no magic here.
The page you linked to has a section titled "Visibility from other objects" which states that:
Objects of the same type will have access to each others private and protected members even though they are not the same instances. This is because the implementation specific details are already known when inside those objects.
It wouldn't work if you'd done this:
$b = new B();
echo $b->a;
In your example, you're not accessing the $a member direct from B(). You're accessing it from an A() object that happens to have been instantiated from inside B().
Related
I have a strange behavior in my php 5.3
i have a class wich dous this in a function
$new = new self($data);
$new->setServiceManager($this->service);
$new->cacheInstance();
BUT the function cacheInstance is a private function....
private function cacheInstance()
{
foreach ($this->data as $name => $class) {...}
}
Can some one give an explanation why the hell can this be used like this? shouldn`t this method be private aka unaccessible from outside?
UPDATE:
ok now im totally lost... i can even acess the private variables of the instance... like what the ... this has to be some intended behavior, can somone point me in a direction?
If you can create a class instance with new self() it means you are in the class, and of course you can access private properties an functions. This snippet is taken from the PHP Docs (link)
/**
* Define MyClass
*/
class MyClass
{
public $public = 'Public';
protected $protected = 'Protected';
private $private = 'Private';
function printHello()
{
echo $this->public;
echo $this->protected;
echo $this->private;
}
}
$obj = new MyClass();
echo $obj->public; // Works
echo $obj->protected; // Fatal Error
echo $obj->private; // Fatal Error
$obj->printHello(); // Shows Public, Protected and Private
IN YOUR CASE:
class Cache {
private $service = null;
private function cacheInstance()
{
foreach ($this->data as $name => $class) {}
}
public function setServiceManager( $service ) {
}
public function myTest( $data ) {
$new = new self( $data );// you are in the class, so you can call new self()
$new->setServiceManager($this->service);
$new->cacheInstance();
}
}
$cache = new Cache();
$cache->service; //Fatal error: Cannot access private property
$data = array();
$cache->myTest( $data );// working
$cache->cacheInstance();// not working
private, protected and public accessibility works on class level, not on object level.
While it may seem counter intuitive first, this is not your usual PHP weirdness.
It's the same in other OOP languages, like Java
Note that accessibility is a static property that can be determined at compile time; it depends only on types and declaration modifiers.
and C#
The private keyword is a member access modifier. Private access is the least permissive access level. Private members are accessible only within the body of the class or the struct in which they are declared
(highlights added)
Explanation
The accessibility is a mechanism to hide implementation details from code in other classes, not for encapsulation of objects. Or as it's stated in the Java specs, accessibility can be determined at compile time, i.e. there cannot be a runtime violation because it's a different object.
It makes sense, if you look at the difference between private and protected. For private members, an object does not have access to its own members if they are declared in a parent class. Sounds weird? That's because the terminology is wrong. The class does not have access to privates of its parent class (i.e. it may not use them).
Now in your method, you use private variables within the same class. There is no need to hide this implementation detail from yourself, the author of this class, no matter what the objects are at runtime.
ok... wierd like quantum mechanics... have been pointed in RL to the answer
http://php.net/manual/en/language.oop5.visibility.php
QUOTE:
Objects of the same type will have access to each others private and
protected members even though they are not the same instances. This is
because the implementation specific details are already known when
inside those objects.
Talking about wierd...
Noticed something about PHP's classes and I don't know if it's a bug or why it works, this is the code:
<?php
class A {
private $prop = 'value';
public function fun()
{
$obj = new A;
$obj->echoProp();
}
private function echoProp()
{
echo 'Prop has value: '.$this->prop;
}
}
$obj = new A;
$obj->fun();
And the result isn't an error as I was expecting since I'm calling a private method (tested on PHP 5.3.10-1ubuntu3.7 with Suhosin-Patch). The result is "Prop has value: value"
As long as you're in the class, you can call your class' private methods on any instance.
At the php documentation http://www.php.net/manual/en/language.oop5.visibility.php#language.oop5.visibility-other-objects it says:
Visibility from other objects
Objects of the same type will have access to each others private and
protected members even though they are not the same instances. This is
because the implementation specific details are already known when
inside those objects.
So this isn't a bug but a wanted feature of php.
Been searching all around but still cannot find a solution for this problem.
My problem is that i got these snips of code(Examples):
Core file
class Core {
public $DB = null;
public $Handler = null;
function run() {
$this->DB = "somedatabase";
include_once('handler.php');
$this->Handler = new Handler;
$this->Handler->run();
}
}
This is the helper.php example
class Handler extends Core {
function run() {
echo "<pre>"; print_r($this); echo "</pre>"; die();
}
}
Even tho i defined the DB variable before i include the helper then it is still empty inside the helper class. It's defined yes but it's empty. Which means it properly doesn't share the same memory as the Core class.
Keep in mind that the Core class it self is instanced too.
-
Thanks for all suggestions
Edit
PhpMyCoder got it right. Thank you for the detailed and well written reply.
For over 2 years i been seeing PHP scopes as being the same or sorta the same as JavaScript's scope. Now i realize that if i extend my "Core" class i get all the methods and properties within it. But the values is private to my class and my class alone.
This is great. Finally i got it.
From what I gather here you are talking about public instance variables. They are performing as OOP would require. Each time you instantiate a class with
$core = new Core(); // or
$handler = new Handler();
Each of them gets a fresh space in memory to store their instance variables. Instance variables are unique to each instance of a class, as the name would suggest. So, two separate instances of Core and Handler do not share instance variables. However since Handler extends Core, two instances of Core are created. One instance is the one that I created on the first line. The other is created so that Handler can extend it on the second line. These two instances of Core are not the same object. To have the same values for Core across all core objects you will need to use static (class) variables.
class Core {
public static $hello = 'World';
}
var_dump(Core::$hello); //string('Word')
In my example, $hello will always be available to everyone by accessing it with the scope resolution operator, ::. So Handler could access it with either Core::$hello or parent::$hello. If you wanted to only expose this static variable to Core and its subclasses, then you would need to make it protected and access it from within Core with self::$hello and from its subclasses with parent::$hello.
class Core {
protected static $hello = 'World';
public function sayHello() {
echo 'Hello '.self::$hello; //from within Core, access with `self`
}
}
class Handler extends Core {
public function myParentSays() {
echo 'My parent says: Hello '.parent::$hello;
}
}
$core = new Core();
$core->sayHello(); // 'Hello World'
$handler = new Handler();
$handler->myParentSays(); // 'My parent says: Hello World'
Check the PHP docs for more on the static keyword and the scope resolution operator.
EDIT
I believe your confusion lies in a misunderstanding of how inheritance works in OOP so let me give you a little real-world-ish example. Let's say you create a class for employees called Employee. This class has a public instance variable (that is, one that can be accessed with ->) for the name of the person. In PHP this would be:
class Employee {
public $name;
public __construct($name) {
$this->name = $name;
}
}
Now let's create a new employee:
$tim = new Employee('Tim');
Let's say that we need a new class, Intern, that should subclass Employee. That should be easy enough:
class Intern extends Employee {
public function makeCoffee(Employee $receiver) {}
}
If we create a new intern now, should his name be Time just because we have already created another employee named Tim? No. That doesn't make sense.
$intern = new Intern();
var_dump($intern->name); //string(0) ""
Now say that setting the name was some complicated and arduous process and we'd rather not have to code it again. With a little modification to our Intern class we can leave the name setting to its superclass, Employee.
class Intern {
public function __construct($name) {
parent::__construct($name);
}
public function makeCoffee(Employee $receiver) {}
}
Now we can create a new intern and set his or her name. Notice how the other Employee keeps his name.
$intern = new Intern('Something Forgettable');
var_dump($intern->name); // string(21) "Something Forgettable"
var_dump($employee->name); // string(3) "Tim"
Now why is this? In OOP, a subclass/superclass is an "is a" relationship. The Intern "is an" Employee. The Intern has all the same properties and methods as an Employee but because each Intern and Employee are distinct they have their own values for these properties.
With this in mind, I suggest you rethink your strategy for your classes. Does it really make sense that Handler is a Core? Does it make sense that MainController is a Handler?
Classes don't share memory unless you pass a reference to them. When you make an instance of a class (an object), it is unique. You could have:
$a = new Core();
$b = new Core();
$a->var1 = 'foo';
$b->var1 = 'bar';
echo $a->var1; // 'foo'
echo $b->var1; // 'bar'
The same holds for extending a class. It doesn't explicitly share the values of the fields, it just shares their existence/visibility.
To share the value, you would do something more like this:
$a = new Core();
$b = new Core();
$c = 'foo';
$a->var1 = &$c;
$b->var1 = &$c;
echo $a->var1; // 'foo'
$b->var1 = 'bar';
echo $a->var1; // 'bar'
$c = 'baz';
echo $a->var1; // 'baz'
Variables are only set on objects (class instances). Don't confuse classes with objects.
If you want to have variables bound to classes, use the static keyword:
class Core {
public static $static = 'abc';
public $instance = 'xyz';
}
Core::$static = 'x';
$core = new Core();
$core->instance = 'a';
In PHP, classes are extended, not objects. This is class:
class SomeClass{
// ...
}
And this is object:
$object = new SomeClass();
So, when your are extending some class, all its protected/public properties are become available to child class.
This is a follow up question on the following answer : Parent Object in php
class A {
protected function doSomeStuff(){
echo 'a method that all children will need to call';
}
}
class B {
protected $_parent;
public function __construct($parent) {
$this->_parent = $parent;
}
public function doSomeLocalStuff() {
$this->_parent->doSomeStuff(); // Fatal Error
}
}
$a = new A(); // will be used for other children as well.
$b = new B($a);
$b->doSomeLocalStuff();
In the above code, parent object Injection was used, allowing class B to be initialized using a specific instance of class A, but class B wont be able to access class A protected properties or methods (e.g., doSomeStuff()).
But by mixing the above with inheritance, we get the best of both worlds :)
class B extends A {
protected $_parent;
public function __construct($parent) {
$this->_parent = $parent;
}
public function doSomeLocalStuff() {
$this->_parent->doSomeStuff(); // Works :)
}
}
So, is this acceptable ? .. any drawbacks ?
P.S: I'm trying to implement a non-static factory pattern.
Clarification
Consider this, I'm trying to design a class which will be used for calling an external API. We've over 400 different calls, divided into 10 categories (billing, customers, products ... ).
All the 400 calls shares the same parent-url, username/password and some other common properties.
So, instead of putting the 400 method in one big class, I decided to divide them into 10 classes, with a parent class handling common functions (e.g., authentication, url construction, web call ... ), then created a factory pattern, where I can load only needed classes/categories on run-time.
Something like :
$apiCall = new parentPlusFactory();
//contains common methods and a mechanism to load sub-classes
$apiCall->setAPIuserName("user");
$apiCall->setAPIpassword("pass");
$apiCall->useClass('customers')->doSomeCustomerStuff();
$apiCall->useClass('products')->doSomeProductStuff();
That's why I need to share the same parent class instance.
There is no friend keyword in PHP, like in C++. You could check this discussion for a way to implement friend classes.
But do you really need that function to be declared protected?
In general you should favor composition over inheritance. To me your use case sounds like B should not be extending A at all, but instead you should have two separate classes.
Now, PHP 5.4 will have "horizontal reuse", also known as "traits", where it will be possible to "include" a trait into your class.
trait A
{
public function doSomeStuff()
{
echo 'doing some stuff';
}
}
class B
{
use A;
public function doSomeLocalStuff()
{
$this->doSomeStuff();
}
}
class C
{
use A;
public function doSomeLocalStuff()
{
echo 'Doing something completely different here';
}
}
See also PHP manual: traits and PHP 5.4 beta1 released.
Say you have two classes, A and B. Is it possible to instantiate both classes once and then let class B call methods in class A, and vice versa?
It can be done using double colon (::) ... ... but then the method becomes static - is that a disadvantage? (see example below)
Can it be done in other ways? With interfaces?
This code shows what I try to do:
class A {
function horse() {
echo "horse";
}
}
class B {
function jump() {
// $A = new A; ... don't want to add this in each method.
$A->horse(); // Fails - $A is out of scope ($A = new A;).
// A::horse(); // Old code style - works.
// $this->horse(); // Works if you extend A - not self-documenting.
// $this->A->horse(); // Fails - out of scope.
}
}
$A = new A;
$B = new B; // Better to use "$B = new B($A);" ?
$B->jump(); // fails - the horse is sleeping.
Edit
Well, I am building a MVC-framework and I want to re-use code from other classes.
Some real-world examples:
a database object that is being passed across classes.
a "url" class that creates/manipulates URLs - used by other classes.
... and a code example:
class url {
function anchor($url,$name) {
return "{$name}";
}
}
class someclass {
function text($str,$url) {
return "{$str}. " . $url->anchor($url,"Read more...");
}
}
I think what you are asking for is multiple inheritance where you could extend both A and B like this
<?php
class C extends A,B {
//...
}
This however is not possible in PHP for good reasons(it actually is creating more problems than it's trying to solve).
Now you might ask yourself if there is any alternative to multiple inheritance and the answer is: Yes, there is! Have a look at the strategy pattern(as Benjamin Ortuzar also has pointed out).
UPDATE:
I just read your question a second time and figured that you might be looking for the singleton pattern, which lets you instantiate an instance of an class only once like this:
class A
{
protected static $_instance;
protected function __construct() //prohibit creating instances from outside
{ }
public static function getInstance()
{
if( self::$_instance === NULL ) {
self::$_instance = new self();
}
return self::$_instance;
}
}
$instance = A::getInstance();
Now A::getInstance() always returns the same instance of A which you can use in B and you can have both the advantages of dynamic functions and the accessibility of static functions.
UPDATE2:
Your database belongs into a registry if you can have more than one db-connection. If you're absolutely certain that you will always need only one db-connection you could as well make it a singleton.
For the URL helper I'd suggest writing a static class if you can and if you really need it to be dynamic make it a singleton, as mentioned before.
I think that this should work:
$B = new B();
$B->jump();
But you should read/refer to http://www.php.net/manual/en/language.oop5.php
Of course you should import the class if you're accessing it from a different php file. And if you're in the object you're calling the method of you should use
$this->jump();
I would suggest reading about the factory and strategy pattern. You can read more about this from chapter one of this fantastic book. link text
I would recomend you reading the whole book.
Maybe (just guessing) you're looking for something like aggregation in COM:
Aggregation is the object reuse mechanism in which the outer object exposes interfaces from the inner object as if they were implemented on the outer object itself.
You can build something like that with the "magic method" __call. Each time a method is called that isn't callable in the object's context this method is invoked and your code can decide what to do with this call. E.g. it can test if another object that is stored as a property of the "outer" object exposes a method with that name and than call that inner object's method.
class Foo {
protected $inner = null;
public function __construct($inner=null) {
if ( is_null($inner) && !is_object($inner) ) {
throw new Exception('...');
}
$this->inner = $inner;
}
public function __call($name, $arguments) {
// also check http://uk.php.net/is_callable
if ( !is_null($this->inner) && method_exists($this->inner, $name) ) {
return call_user_func_array( array($this->inner, $name), $arguments);
}
else {
// add some error handler here
throw new Exception('...');
}
}
function jump() {
$this->horse();
echo " jumps";
}
}
class Bar {
function horse() {
echo "horse";
}
}
$foo = new Foo(new Bar);
$foo->jump();
This works. But I'd recommend something like that only for quite specific circumstances. The most obvious reason beeing that it's hard to tell from the outside what this object $foo really can and cannot do.