overriding PHP class methods referenced by non-overridden $this - php

So, I'm having trouble with some php OO stuff. I think the code will explain it best:
class foo {
$someprop;
public function __construct($id){
$this->populate($id);
}
private function populate($id){
global $db;
// obviously not the call, but to illustrate the point:
$items = $db->get_from_var1_by_var2(get_class($this),$id);
while(list($k,$v) = each($items)){
$this->setVar($k,$v);
}
}
private function setVar($k,$v){
// filter stuff, like convert JSON to arrays and such.
$this->$k = $v;
}
}
class bar extends foo {
$otherprop;
public function __construct($id){
parent::__construct($id);
}
private function setVar($k,$v){
// different filters than parent.
$this->$k = $v;
}
}
Now, assuming my foo table has someprop in it, and my bar table has otherprop in it, this should set the vars on my object when I pass in an ID.
But, for some reason, foo works perfectly, but bar doesn't set anything.
My assumption is that it is falling apart on the $this->setVar() call, and calling the wrong setVar, but if get_class($this) is working (which it is), shouldn't $this be bar, and by association, setVar() be the $bar method?
Anyone see something I'm missing/doing wrong?

You cannot override private methods in subclasses. A private method is known to the implementing class ONLY, not even subclasses.
You CAN do this though:
class foo {
$someprop;
public function __construct($id){
$this->populate($id);
}
private function populate($id){
global $db;
// obviously not the call, but to illustrate the point:
$items = $db->get_from_var1_by_var2(get_class($this),$id);
while(list($k,$v) = each($items)){
$this->setVar($k,$v);
}
}
protected function setVar($k,$v){
// filter stuff, like convert JSON to arrays and such.
$this->$k = $v;
}
}
class bar extends foo {
$otherprop;
public function __construct($id){
parent::__construct($id);
}
protected function setVar($k,$v){
// different filters than parent.
$this->$k = $v;
}
}

Related

PHP Sibling Class Inheritance

I'm a bit confused on whether or not this is possible. I've checked a couple of posts here on SO and they don't really explain what I'm looking for.
I have 3 classes. One main class and two classes extending that main class. (see code below). Is it possible to run a method in one of the two extended classes from it's sibling (the other extended class)?
If it's not possible, how can I change my code to accomplish what I'm doing in the example below?
DECLARATION
class A {
public function __construct() {
//do stuff
}
}
class B extends A {
private $classb = array();
public function __construct() {
parent::__construct();
//do stuff
}
public function get($i) {
return $this->classb[$i];
}
public function set($i, $v) {
$this->classb[$i] = $v;
}
}
class C extends A {
public function __construct() {
parent::__construct();
//do stuff
}
public function display_stuff($i) {
echo $this->get($i); //doesn't work
echo parent::get($i); //doesn't work
}
}
USAGE
$b = new B();
$c = new C();
$b->set('stuff', 'somestufftodisplay');
$c->display_stuff('stuff'); // <----- Displays nothing.
Your code shows an additional problem apart from the main question so there are really two answers:
No, you cannot run a method from a sibling class in another sibling class. If you need that, the method should be in the parent class. The same applies to properties.
You cannot use the value of a property from one object in another object, even if they are both of the same class. Setting a property value in one object sets its value only there as different objects can have the same properties with completely different values. If you need to share the value of a property between the objects and also be able to modify it, you should use a static property. In this case you would have to define that in the parent class, see my previous point.
So to make it work, you would need something like
class A {
private static $var = array();
public function get($i) {
return self::$var[$i];
}
public function set($i, $v) {
self::$var[$i] = $v;
}
}
class B extends A {
}
class C extends A {
public function display_stuff($i) {
echo $this->get($i); // works!
}
}
$b = new B();
$c = new C();
$b->set('stuff', 'somestufftodisplay');
$c->display_stuff('stuff');
An example.

Detect changes to Array in PHP

I've been using __set magic method with protected properties to monitor changes so that my classes know if they have something to save. Is there any way to monitor an array type property for changes? I understand that normally you access the array via a reference and functions like array_push won't trigger the __set method, they'll use a reference to the array.
What I want is basically this:
class Skill{ public $Player, $Name, $Level;}
class Player {
protected $Name, /*Other properties*/, $Skills /*Array*/
}
I then do tracking on all of the properties in Player to tell me if the persistence needs updated. (Skill would also have this function, but this shows the basic example). Also, I want to force them to remain synchronized (it's a bidirectional relationship).
Is there any way to do this that allows it to behave like an array (don't want to go through making a class just to synchronize those if I don't have to).
You could extend ArrayObject and proxy append:
class Skills extends ArrayObject
{
public function append($value)
{
// track changes
parent::append($value);
}
}
You could look into something like runkit_function_redifine(), but is it really too cumbersome to make helper methods for what you want? e.g.
class Player
{
private $skills = array();
protected function addSkill($skill)
{
// Do something.
//
$this->skills[] = $skill;
}
}
Or even a wrapper for an array to make it cleaner:
class FancyArray
{
private $content = array();
public function add($value)
{
// Do something.
//
$this->content[] = $value;
}
public function remove($value){ /* blah */ }
public function getContent(){ return $this->content; }
}
class Player
{
protected $skills;
public function __construct()
{
$this->skills = new FancyArray();
$this->skills->add("Ninjitsu");
}
}

__get and __set magic methods not accessible

I have a class 'base' and a class 'loader', which looks like this.
class base {
protected $attributes = Array();
public $load = null;
function __construct() {
$this->load = loader::getInstance();
echo $this->load->welcome(); //prints Welcome foo
echo $this->load->name; //prints Foo
echo $this->name; //doesnt print anything and i want it to print Foo
}
public function __get($key) {
return array_key_exists($key, $this->attributes) ? $this->attributes[$key] : null;
}
public function __set($key, $value) {
$this->attributes[$key] = $value;
}
}
class loader {
private static $m_pInstance;
private function __construct() {
$this->name = "Foo";
}
public static function getInstance() {
if (!self::$m_pInstance) {
self::$m_pInstance = new loader();
}
return self::$m_pInstance;
}
function welcome() {
return "welcome Foo";
}
}
$b = new base();
Now what I want is a way to store variables from loader class and access them from base class using $this->variablename.
How can I achieve this? I don't want to use extends. Any idea ?
I don't feel like you've fully understood what coding the OOP way means. And usually Singletons are code smells so I'll just warn you:
There's probably a better way of accomplish you goal. If you provide more informations we will help you out. In its current form the answer is the following; just remember that I higly discourage its implementation in your code.
Assuming that you want to access only public (and non static) loader's variables as this->varname in the base class you should just insert this line in the beginning of the base class constructor:
$this->attributes = get_object_vars(loader::getInstance());
This will basically initialize the attributes array with all the loader public vars so that via your __get() method you can access its value.
On a side note, take a look at Dependency Injection design pattern in order to avoid using Singletons.
Your __get/__set methods access $this->attributes but not $this->load.
You could e.g. do something like (pseudocode)
function __get($key) {
- if $attribute has an element $key->$value return $attribute[$key] else
- if $load is an object having a property $key return $load->$key else
- return null;
}
see also: http://docs.php.net/property_exists
You can make static variable and then you can access this variable from anywhere
public statis $var = NULL;
and you can access it like this
classname::$var;

PHP: Detect instances of same class

I have a PHP Class which requires a unique value in its constructor. If multiple instances of the same class are passed the same value the results are horrific.
How would I go about detecting other instances of a Class so I can check and prevent this from happening before constructing any new ones?
A simple solution would be to keep a static array of the values inside the class. Then, when a new instance is created, check the static array's contents in the constructor.
Something like..
class Foo {
private static $usedValues = array();
public function __construct($val) {
if(in_array($val, self::$usedValues)) {
throw new Exception('blah');
}
self::$usedValues[] = $val;
}
}
I think the multiton pattern is right for you.
class Foo {
static protected $_instances = array();
static public function getInstance($id) {
if(!self::exists($id)) {
self::$_instances[$id] = new Foo($id);
}
return self::$_instances[$id];
}
static public function exists($id) {
return isset(self::$_instances[$id]);
}
protected function __construct($id) {
}
}

Get a caller class instance from another object

Please take a look at this code:
class Foo {
public $barInstance;
public function test() {
$this->barInstance = new Bar();
$this->barInstance->fooInstance = $this;
$this->barInstance->doSomethingWithFoo();
}
}
class Bar {
public $fooInstance;
public function doSomethingWithFoo() {
$this->fooInstance->something();
}
}
$foo = new Foo();
$foo->test();
Question: is it possible to let the "$barInstance" know from which class it was created (or called) without having the following string: "$this->barInstance->fooInstance = $this;"
In theory, you might be able to do it with debug_backtrace(), which as objects in the stack trace, but you better not do it, it's not good coding.
I think the best way for you would be to pass the parent object in Bar's ctor:
class Foo {
public $barInstance;
public function test() {
$this->barInstance = new Bar($this);
$this->barInstance->doSomethingWithFoo();
}
}
class Bar {
protected $fooInstance;
public function __construct(Foo $parent) {
$this->fooInstance = $parent;
}
public function doSomethingWithFoo() {
$this->fooInstance->something();
}
}
This limits the argument to being proper type (Foo), remove the type if it's not what you want. Passing it in the ctor would ensure Bar is never in the state when doSomethingWithFoo() would fail.

Categories