Jump to content

Recommended Posts

I have two classes were one extends the other but they both have magic methods __get __call and __set but when trying to call a magic method it conflicts one with the other as you can imagaine...is there a way of getting around this ie. name spaces

 

or do I simply have to rewrite my classes

 

thank you

Link to comment
https://forums.phpfreaks.com/topic/290062-oop-magic-methods-confliction/
Share on other sites

Here are my class files

 

but yeah basically my __get method in my action class conflicts with the view class...is there anything I could do to get around this?

<?php

class Action extends View
{
	protected $_request;
	protected $_response;
	protected $_partial;
		
	public function __construct(Request $request, Response $response)
	{
		$this->set_request($request);
		$this->set_response($response);
		$this->set_model();
	}

	protected function set_request(Request $request)
	{
		$this->_request = $request;
		return $this;
	}
	
	protected function set_response(Response $response)
	{
		$this->_response = $response;
		return $this;
	}

	protected function get_request()
	{
		return $this->_request;
	}
	
	protected function get_response()
	{
		return $this->_response;
	}
		
	public function dispatch($method, $parameters)
	{		
		if ($this->get_request()->is_dispatched())
		{
			if(method_exists($this, $method))
			{
				call_user_func_array(array($this, $method), $parameters);
			}
			else 
			{
				echo "unable to load method";
			}
		} 
	}
	
	public function __get($property)
	{
		$property = '_' . $property;

		if (property_exists($this, $property))
		{	
			if ($property !== '$this->_request' ||
			    $property !== '$this->_responce')
	        {
				return 	$this->$property;
			}
		}
	}
	
	public function set_model()
	{		
		$class_name       = get_class($this);
		$model_name       = trim($class_name, "_Controller");
		$model_name       = strtolower($model_name);
		$attribute_name   = '_' . $model_name;
		$model_name       = Inflection::singularize($model_name);
		$model_name       = ucfirst($model_name);
		$model_class      = $model_name . '_Model';
		
		$this->$attribute_name = new $model_class();
	}
}

?>
<?php

class View
{
	protected $_request   = null;
	protected $_variables = array();
	protected $_helper    = array();
	
	public function __construct(Request $request)
	{
		$this->set_request($request);
	}
	
	public function __set($name, $value)
	{
		echo $name;
		$this->_variables[$name] = $value;
	}
	
	protected function set_request(Request $request)
	{
		$this->_request = $request;
	}
	
	public function __get($name)
	{
		return $this->_variables[$name];
	}
	
	protected function get_request()
	{
		return $this->_request;
	}
	
	public function __call($name, $arguments)
	{	
		$helper = $this->get_helper($name);
		
		if (!$helper)
		{
			$helper = call_user_func_array(array(new $name(), "__construct"), $arguments); 
			$this->set_helper($name, $helper);
		}
		
		return $helper;
	}

	protected function set_helper($helper, $instance)
	{
		$this->_helper[$helper] = $instance;
	}
	
	protected function get_helper($helper)
	{
		if (isset($this->_helper[$helper]))
		{
			return $this->_helper[$helper];
		}
		
		return false;
	}
	
	public function render($file)
	{
		if (preg_match("/\.html$/i", $file))
		{
			require_once PRIVATE_DIRECTORY . 'application' . DS . 'views' . DS . $file;
		}
	}
}
?>

If your sub-classes __get (and etc) method does not have anything useful to do then just call the parents __get method.

public function __get($property)
	{
		$prop = '_' . $property;

		if (property_exists($this, $prop ))
		{	
			if ($prop !== '$this->_request' ||
			    $prop !== '$this->_responce')
			{
				return 	$this->$prop;
			}
		}

		return parent::__get($property);
	}
Edited by kicken

I've been fiddling about and changed the property exist search from $this to __class__ then if not i'll load it from the parent :)

 

although im having trouble with setting the model...I want to set it to self:: if possible

	public function set_model()
	{		
		$class_name       = get_class($this);
		$model_name       = trim($class_name, "_Controller");
		$model_name       = strtolower($model_name);
		$attribute_name   = '_' . $model_name;
		$model_name       = Inflection::singularize($model_name);
		$model_name       = ucfirst($model_name);
		$model_class      = $model_name . '_Model';
		
		self::$attribute_name = new $model_class();
	}

the problem im getting doing it like that is that is adds as a variable on the view subclass on __set...which then allows it to be accessible in my header.html =/

is there a away around this?...without setting a property above like $_model?

 

thank you 

well I have a News Controller were all my actions are...the News Controller extends Actions and Actions extend View

 

why how should it be...any pointers will be great

 

Is there any particular reason the 2 cannot be dependent on one another. Sorry, don't mean to be off-topic, just trying to understand the logic behind why are would make the 2 dependent in the first place.

It's not about dependency. It's about inheritance. Extending a class is saying "this class here is a specialized type of this other class". An action is not a specialized form of a view. An action may use a view, but it shouldn't be inheriting from it.

  • Like 1

Yup. Despite PHP being dynamically typed, type still matters. Every class is a type. Inheritance creates a new type, yes, but an instance of that subclass is considered an instance of the parent. Quick example:

 

class Shape
{
    // some base code
}

class Square extends Shape
{
    // Square-specific code
}

class Triangle extends Shape
{
    // Triangle-specific code
}
Both Triangle and Square are Shapes. An object of type Square can be considered a Shape, and be passed into functions and methods as a Shape. Example:

 

class Shape {}
  
class Square extends Shape {}
  
class Color {}
  
function test(Shape $shape)
{
    echo "Success";
}
  
$sq = new Square();
$co = new Color();
  
test($sq);
test($co);
The first test will pass, even though we're passing in a Square. The second will fail.

 

So, since inheritance means that an instance of the child type is also considered an instance of the parent type, that means you need to be very careful about what you choose to extend. Is a View an Action? No, of course not. One may have to refer to the other, but they shouldn't be considered the same thing. Which is what's happening when you decide to use inheritance.

 

If you need to use or refer to an object of a different class, just compose them:

 

class Action
{
    private $view;

    public function __construct(View $view)
    {
        $this->view = $view;
    }
}
Composition - including other objects in your current object - is generally the way to go in most cases. Inheritance gets a lot of attention because it's an OO-specific functionality, but it has limited usefulness. It's unfortunate that so many resources seem to oversell it.

thank you guys...really helpful specially with the shapes example...although one more question on that topic of inheritance, im currently using my News_Controller to extend my Action...would that be the correct way of doing things?

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.