I am implementing the state pattern in one of my projects and is running into a design issue; my problem can be abstractly described as follows:
Let's say I have the StatefulObject Class that has a state property which holds the CurrentState object.
Much of the functionally I'd like the CurrentState object to access, is encapsulated in the StatefulObject object.
The problem is that allowing access to this functionality forces me to provide public methods in the StatefulObject class that I would otherwise have not exposed, and also feel I shouldn't.
I'd welcome suggestions on how to handle this visibility issue.
The implementation language is PHP, if that maters.
I've put together some example code, according to request:
Class StatefulObject{
protected $state;
public function StatefulObject(){
$this->state = new PrepareSate($this);
}
public function execute(){
$this->state->execute();
}
/* I am not intrested in providing public access to these methods
Optimaly I would have this visible only for the PrepareState*/
public function setX(){
};
public function setY(){
};
}
Abstract class StateObject{
protected $stateFulObjectRef;
public function StateObject(StateFulObject $ref){
$this->stateFulObjectRef = $ref;
}
}
Class PrepareState extends StateObject{
public function execute(){
/* This is why I need the public access for */
$this->stateFulObjectRef->setX();
$this->stateFulObjectRef->setY();
}
}
I think that the solution in Java would be having the methods setX setY with no access modifier, which means they will be visible at package level.
I don't think PHP has an equivalent solution though.
EDIT, on to possible answer:
I think the best solution I came up with so far is making StatefulObject and the StateObject inherit the same father (solely for visibility). and the declare the setX setY methods as protected. Sibling classes has access to each other protected methods in PHP - as pointed out here - http://www.php.net/manual/en/language.oop5.visibility.php#93743
The question is very general but I will try to answer based on my understanding of your problem (which could be not a correct understanding of the problem)
I will suggest that you make an interface and implement it in your class and than use that interface object to interact with the methods.
If your StateObject does not need access to the StatefulObject at all, then just simply pass the needed values in parameters(Strategy pattern).
Class StatefulObject{
protected $state;
public function StatefulObject(){
$this->state = new PrepareSate($this);
}
public function execute(){
$this->state->execute($this->x, $this->y);
}
}
Class PrepareState extends StateObject{
public function execute($x, $y){
// Now you have access to $x and $y.
}
}
Related
Say I have a class A that has another class B as its property.
When class A needs to do modifications to class B, is it better to use the getter method to do modifications or access the property directly to access?
So as an example.
public class Car() {
private $engine;
public function __constructor() {
$this->$engine = new Engine();
}
public function getEngine() {
return $this->engine;
}
public function replaceEngine() {
// Should I use
$this->engine->change();
// Or should I use
$this->getEngine()->change();
}
}
I am thinking using the getter method so that if I had to stub Class Engine methods, I can mock what getEngine() returns and remove the dependency.
But I'd like to see more opinions on this.
Thank you!
Opinion based questions don't do well on stack overflow, but you really should use getters and setters.
This method is better programming practice for several reasons.
-You can easily use mock classes
-If you need the class to update in response to have an attribute change (or may in the future). E.g: The setSpouse function can update both the 'spouse' and 'relationshipStatus' attributes
-If you ever want to do refactoring
Learning PHP in a OOP way and i often come across people who makes functions like this.
public function getUsername() {
return $this->username;
}
Is there some security reasoning behind this? Instead of just calling the username property of the class directly? Why wrap getting a property around a function.
This type of functions are used for accessing private or protected members of class. You can not access them them directly outside of the class as they can be accessible only inside the class. So what would you do if you want to access a private member? The answer is this.
Lets take an example -
class A {
private $x;
public $y;
public function test() {
echo $this->x;
}
}
$obj = new A();
$obj->x; // Error : You can not access private data outside the class
$obj->y; // Its fine
$obj->test(); // it will print the value of $x
Hope this will help.
In OOP, class should hide its implementation details, and just provide necessary public functions. Users are more concerned with function rather than details.
For example you have class Test. You are using direct access to property and you have hundred place like $obj->date = 'now' etc.
class Test {
public $date;
}
But what if you need to insert some code before updating value or modificate input value? In this case you have to find all usage of the property and update it. But if you will use getters/setters you can insert some code into them.
class Test {
private $date;
public getDate() { return $this->date; }
public setDate($date) {
// here some modification value or something else
$this->date = $date;
}
}
A quick reason is that you be writing a piece of code and want to prevent a user from overwriting a value in an object instance (a good example is configuration data).
Writing functions in the way you have stated also provides a standard interface which is essential when developing complex programs. It would be crazy to have a team of developers working with the one class and not defining access to variables!
Here is a good explanation of the PHP OOP basics and explains private, public and protected
http://php.net/manual/en/language.oop5.basic.php
I have a Bcrypt.class which contains my hashing methods and I have a userDAO.class which contains my register method.
In my Bcrypt.class the methods are private. How can I access them in my userDAO.class so I can hash my password?
Please let me know if you need to see any code.
You cannot access private methods from outside of the class declaring them. If API developer decided to use private then there is no chance. I personally prefer protected in almost every situation. Some API developers don't..
If you have personal access to the source code of the Bcrypt class and you can change it without breaking anything then make the methods either protected and extend the class or make them even public
Another design approach would be to place the algorihms in a separate class and use them in the Bcrypt class and others
Make your methods in the Bcrypt class either public or protected.
These are things you should keep in mind.
Public Methods : Can be accessed from anywhere
Protected Methods : Can be accessed by the class and other classes that inherits it.
Private Methods : Only the corresponding will have access.
As of PHP 5.4 and ReflectionMethod::getClosure() it looks like accessing private methods from the outside is possible. To be honest - had to try out the following solution before believing it actually works.
Code from the User Contributed Notes section by Denis Doronin.
function call_private_method($object, $method, $args = array())
{
$reflection = new ReflectionClass(get_class($object));
$closure = $reflection->getMethod($method)->getClosure($object);
return call_user_func_array($closure, $args);
}
class Example
{
private $x = 1;
private $y = 10;
private function sum()
{
print $this->x + $this->y;
}
}
call_private_method(new Example(), 'sum');
// Output is 11.
I have these classes:
class User{
private $user_ID;
private $first_name;
private $surname;
...
private $website;
private $company;
function __construct($array){
$this->user_ID = $array["userId"];
$this->first_name = $array["first"];
$this->surname = $array["last"];
$this->telephone = $array["tele"];
...
}
public function addWebsite($array){
$this->website = $array;
}
public function addCompany($array){
$this->company = $array;
}
public function getData(){
$array = array();
foreach($this as $var => $value) {
$array[$var] = $value;
}
return $array;
}
}
class Website{
private $webId;
private $url;
private $description;
...
function __contruct($array){
$this->webId = $array["webId"];
$this->url = $array["url"];
$this->description = $array["desc"];
...
}
}
the getData() method in User is exactly the same for the Website class.
so how can i get the website class to implement this method? But ONLY the getData() method
While inheritance forms an behaves-as relationship, this is not a situation for Inheritance. Your Website is not related to the User in any way, so there shouldn't be a relationship between them.
Having base classes like suggested elsewhere here will quickly lead to monolithic architecture and god objects. Those in turn lead to less maintainability, high coupling, fragile code and hampers reuse. Likewise, making everything public or resorting to similar means that defeat information hiding and widen the public API lead to similar problems and you will want to avoid them.
What you are looking for is Traits, but these are only supported as of PHP 5.4. The easiest approach is really just to duplicate that method in both classes. Keep in mind that you usually want to avoid code duplication, but in this case its the lesser evil over the other suggested alternatives.
A viable alternative would be to use an Introspection Service that uses Reflection to fetch the data from the object into an array. Although in general, you should put methods on the objects having the data the methods operate on.
if you are using php5.4 you can use traits instead of classes. It´s solve the cases witch you need the implementation of one method in two diferents classes.
To make it type save you can define an interface for example "arraySerializable" which has the getData method. You can use this interface later in TypeHints instead of the class.
But this still doesn't give you the functionality. I suppose a common base class is not the thing you want here. So if you can't use traits you have to duplicate the code. This might be one of the rare cases where some lines duplicated code is ok.
Make another class that only has the getData method, and make both of your existing classes extend that new class.
If you do not have Traits there was an older implementation of Mixins that you could use.
You may know that:
<?php
class A {
public function B() {
var_dump($this->data);
}
}
class X {
protected $data;
public function Y() {
A::B()
}
}
$x = new X;
$x->Y(); // will execute the code for A::B
// but will assume the object context
// of $x (of class X) and will have
// access to $this->data
// ! this is not a static call
Using this principle you can create a static array of class names and/or method names that you can "mix-in" or "use" (like traits) via the magic method __get.
?>
As opposed to the other answerers, I think I should comment on your design. You want to create a method that exposes all private properties of any object. An object is, in most cases, somewhat more than simply a property bag, so in what situations would you need to know all properties? And why do you then mark them as private?
To solve the real problem, you should take a look at public properties, or private ones with getters and setters if you want to control the incoming and outgoing data.
If you however think you need all properties of a given object (and are willing to accept "hacks" like copypaste-programming, traits and whatnot), why not simply mark them as public and call get_object_vars()?
How is it done?
I have a Model class that is the parent to many sub-classes, and that Model depends on a database connection and a caching mechanism.
Now, this is where it starts getting troublesome: I have no control over how each object gets instantiated or used, but I have control over methods that get used by the sub-classes.
Currently I have resorted to using static methods and properties for dependency injection, as such:
class Model
{
private static $database_adapter;
private static $cache_adapter;
public static function setDatabaseAdapter(IDatabaseAdapter $databaseAdapter)
{
self::$databaseAdapter = $databaseAdapter;
}
public static function setCacheAdapter(ICacheAdapter $cacheAdapter)
{
self::$cacheAdapter = $cacheAdapter;
}
}
Which has worked out well, but it feels dirty (it creates a global state for all Models).
I have considered the factory pattern, but that removes the control of the instantiation from the sub-classes (how do I instantiate an object with a variable number of parameters in it's constructor?).
Now I am at a loss. Any help would be appreciated.
As far as I know this is a perfectly acceptable alternative. Another possibility suggested by Sebastian Bergmann, the creator of PHPUnit, is to have a $testing static property. You can read his recent article regarding the Testing of Singletons. It sounds like you have similar issues.
You're solution would be fine for setting default adapters, but I'd add a way for the individual models to have a different adapter. Consider this:
abstract class Model {
protected $_database_adapter;
protected $_default_database_adapter;
public function getDatabaseAdapter() {
if(!$this->_database_adapter) {
if(self::$_default_database_adapter) {
$this->_database_adapter = self::$_default_database_adapter;
} else {
throw new Exception("No adapter set yet");
}
}
return $this->_database_adapter;
}
public function setDatabaseAdapter(IDatabaseAdapter $databaseAdapter) {
$this->_database_adapter = $databaseAdapter;
}
public static function setDefaultDatabaseAdapter(IDatabaseAdapter $databaseAdapter) {
self::$_default_database_adapter = $databaseAdapter;
}
}
Of course you could extract all static methods/properties into a Registry, Container or anything else as central.
For example, perhaps you don't want to collect data from the same database host over your whole application. Then your original script would look like the following:
Model::setDatabaseAdapter($default);
$my_model->query('....');
Model::setDatabaseAdapter($another_adapter);
$my_other_model->query('....');
Model::setDatabaseAdapter($default);
which is awfully alike:
mysql_select_db('default_db');
mysql_query('...');
mysql_select_db('other_db');
mysql_query('...');
mysql_select_db('default_db');