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 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()?
As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 10 years ago.
Could this be classified as correct OOP programming?
class Greeting {
public $greet = array('Hi','Hello', 'Howzit', 'Ola', 'Whats up');
function __construct($name) {
$this->name = $name;
shuffle($this->greet);
}
}
$hi = new Greeting('INSERTNAMEHERE'); /*NAME OF PERSON GOES HERE*/
echo $hi->greet[1] .' '. $hi->name;
For the sake of Keeping it Simple, I'd say it's okay. It's not too proper OOP though, nor is it particularly easy to understand code. Having working code is better than having no code at all though.
Let's go through your code:
1 class Greeting {
2
3 public $greet = array('Hi','Hello', 'Howzit', 'Ola', 'Whats up');
4
5 function __construct($name) {
6 $this->name = $name;
7 shuffle($this->greet);
8 }
9 }
Line 1: says this class represents the concept of a Greeting. What is a Greeting? I'd say something like "Hello John" or "Hi John" or "Howdy John" is a greeting. And in fact, you seem to agree because in …
Line 3: … you do have a list of similar greetings, just without a name. But that property warrants the question why your class is named Greeting, when it really encapsulates multiple greetings already. Shouldn't the class be called Greetings (mind the plural) then?
Line 3: Naming the property "greet" wasn't a too good idea either. It's a property, so dont give it the name of a verb. Verbs are for methods.
Line 3: Although there is people who will tell you different, making the property public is rarely a good idea. Properties are about internal state and that state should not be accessible directly, but only through methods.
Line 5: Your constructor then tells me a Greeting has to have a name. If I wouldn't be looking at the source code already, I'd falsely assume this to be the name of the Greeting. But you really mean a Person's name. The argument should reflect that and be named something more indicative, like $greetedPersonsName.
Line 6: Assigning properties on the fly is a boo boo. If I look at the class definition, I want to see the properties immediately. Discovering them inside some method makes the code hard to understand. This will also not getting picked up when generating API docs. Avoid it.
Line 7: The shuffle is another unexpected thing. It's a non-obvious side-effect. If I was to instantiate a new Greeting, I'd expect the greetings to appear in the order they are listed. It's against the Principle of Least Astonishement to shuffle them in the ctor. The shuffling should happen from a public method that does nothing but shuffling, e.g.
public function shuffleGreetings()
{
shuffle($this->greetings);
}
Assuming the idea of the class was really to be a single Greeting that just initializes itself with one of the default possible values, we can also add a Getter like this:
public function getGreeting()
{
return $this->_greetings[0] . ' ' . $this->name;
}
This is better than doing
echo $hi->greet[1] .' '. $hi->name;
because it hides the implementation details. I don't need to know that the Greeting object has an array of possible greetings. I just want to get the Greeting combined with the set name. It's still far from perfect though, because you still would use it like
$hi = new Greeting('John'); // A Greeting named John? Why $hi then?
$hi->shuffleGreetings(); // Shuffling Greetings in a Greeting?
echo $hi->getGreeting(); // Why is it "Hello John" all of a sudden?
As you can see, the API is still pretty much full of WTF. A developer will still have to look at your source code to understand what's going on.
More on Side-Effects
While it may be tempting to put the shuffle into getGreeting you should not do so. A method should return the same thing for the same input. When I call getGreeting twice in a row, I can expect it to return the same result. You would expect 1+1 to return 2 always, so make sure your methods do too.
Likewise, if you want to have a single method to return a random item from the greetings property, dont shuffle the greetings array. If you would use the shuffle method instead, you would also change the greetings property. That ripples to any function reading from the property, e.g. when you do
public function getRandomGreeting()
{
$this->shuffleGreetings();
return $this->getGreeting();
}
a developer will experience something like this:
$hi = new Greeting('John');
$hi->shuffleGreetings();
echo $hi->getGreeting(); // for example "Hello John"
echo $hi->getRandomGreeting(); // for example "Hi John"
echo $hi->getGreeting(); // for example "Howdy John" <-- WTF!!
Use an implementation that doesnt change the property, e.g.
public function getRandomGreeting()
{
$randomKey = array_rand($this->greetings);
return $this->greetings[$randomKey] . ' ' . $this->name;
}
That is free of side-effects:
$hi = new Greeting('John');
$hi->shuffleGreetings();
echo $hi->getGreeting(); // for example "Hello John"
echo $hi->getRandomGreeting(); // for example "Hi John"
echo $hi->getGreeting(); // still "Hello John". Expected!
The API is still far from pretty though. If I think about the properties of a Greeting, I just dont think "Person's name". Just saying "Hi" oder "Hello" is still a valid greeting. It doesn't require a name. How about
public function greetPerson($personName)
{
return $this->getGreeting() . ' ' . $personName;
}
and then we can do
$hi = new Greeting;
$hi->shuffleGreetings();
echo $hi->greetPerson('John');
And to finally hide that our Greeting contains an array that needs to be shuffled, let's move our shuffleGreetings method back to the ctor and rename the class to RandomGreeting.
class RandomGreeting …
public function __construct()
{
$this->shuffleGreetings();
}
This might seem counterintuitive at first, because I told you not to shuffle in the ctor. But with the class renamed to RandomGreeting, it is much more to be expected that there is something happening behind the scenes. We just don't need to know what exactly. To reflect that, we should also make the shuffleGreetings method protected now. We just hide it from the public interface completely. Now our code reads like this:
$hi = new RandomGreeting;
echo $hi->greetPerson('John'); // ex "Howdy John"
This doesn't give you any WTFs because your code clearly communicates you'll get a random greeting. The classname clearly communicates what it does.
This is a little bet better now and we could end here, but one could still argue that a Greeting should not be able to greet on it's own, but is rather something that is done by a Person instead.
Improving it
Our findings should lead us to the conclusion that a Greeting should rather be a dumb Type encapsulating the Greeting message and nothing else. All it should do is return that message. Since the Greeting doesn't have any real behavior next to storing the message string, the easiest would be to create a Value Object, e.g. an object that is equal to another object by value of a property:
class Greeting
{
protected $value;
public function __construct($value)
{
$this->value = $value;
}
public function getValue()
{
return $this->value;
}
}
The other way to do it would be to make the various available greetings into separate types. There is very little gain to do that when your objects don't have behavior. You only need that if you want to take advantage of Polymorphism. However, having concrete subtypes does draw a few additional things to consider later on, so let's just assume we need it.
The proper way to do that in OOP would be to define an interface
interface Greeting
{
public function getGreeting();
}
that defines a class that wants to behave like a Greeting has to have a getGreeting method. Since interfaces dont implement any logic, we also add an abstract type that contains the greeting property and the logic to return it:
abstract class GreetingType implements Greeting
{
protected $greeting;
public function getGreeting()
{
return $this->greeting;
}
}
When there is an abstract class, there also needs to be concrete classes derived from the abstract class. So let's use Inheritance to define our concrete Greeting types:
class HiGreeting extends GreetingType
{
protected $greeting = 'Hi';
}
class HelloGreeting extends GreetingType
{
protected $greeting = 'Hello';
}
class HowdyGreeting extends GreetingType
{
protected $greeting = 'Howdy';
}
It's not absolutely necessary to have an Interface and an Abstract implementing the interface. We could have made our concrete Greetings not extend from the GreetingType. But if we had just reimplemented the getGreeting method on all the various Greeting classes, we would be duplicating code and were much more prone to introducing errors and should we ever need to change something, we'd have to touch all these classes. With the GreetingType it's all centralized.
The other way round is true as well. You dont necessarily need an interface. We could have used just the abstract type. But then we would be limited to the GreetingType whereas with an interface, we could potentially add new Types with much more ease. I admit I can't think of any right now, so it is probably YAGNI. But it's so little to add that we can just as well keep it now.
We will also add a Null Object that returns an empty string. More on that later.
class NullGreeting extends GreetingType
{
protected $greeting = '';
}
Object creation
Because I do not want to litter new classname all over my consuming classes and introduce coupling, I will a use simple Factory instead to capsule object creation:
class GreetingFactory
{
public function createGreeting($typeName = NULL)
{
switch(strtolower($typeName)) {
case 'hi': return new HiGreeting;
case 'howdy': return new HowdyGreeting;
case 'hello': return new HelloGreeting;
default: return new NullGreeting;
}
}
}
The Factory is one of the few pieces of code where you actually can use a swich/case without having to check if you can Replace Conditional with Polymorphism.
Responsibility
With object creation out of the way, we can finally start to add our Greetings class:
class Greetings
{
protected $greetings;
protected $nullGreeting;
public function __construct(NullGreeting $nullGreeting)
{
$this->greetings = new ArrayObject;
$this->nullGreeting = $nullGreeting;
}
public function addGreeting(Greeting $greetingToAdd)
{
$this->greetings->append($greetingToAdd);
}
public function getRandomGreeting()
{
if ($this->hasGreetings()) {
return $this->_getRandomGreeting();
} else {
return $this->nullGreeting;
}
}
public function hasGreetings()
{
return count($this->greetings);
}
protected function _getRandomGreeting()
{
return $this->greetings->offsetGet(
rand(0, $this->greetings->count() - 1)
);
}
}
As you can see, Greetings is really just a wrapper for an ArrayObject. It makes sure that we cannot add anything else but objects implementing the Greeting interface to the collection. And it also allows us to pick a random Greeting from the collection. It also makes sure that you always get a Greeting from the call to getRandomGreeting by returning the NullGreeting. This is awesome, because without that you would have to do
$greeting = $greetings->getRandomGreeting();
if(NULL !== $greeting) {
echo $greeting->getMessage();
}
in order to avoid a "Fatal Error: Trying to call method on non-object" when the getRandomGreeting method did not return a Greeting object (when there is no Greeting in the Greetings class yet).
The class has no other responsibility than that. If you are unsure if your class is doing too much or has methods that should better be on some other object, look at the methods in that class. Do they work with a property of that class? If not, you should probably move that method.
Getting it done
Now to finally put all that code to use, we add our Person class now. Since we want to make sure we can call a getName method on it, we create an interface before doing so
interface Named
{
public function getName();
}
We could have named that interface IPerson or whatever but it only has one method getName and the most fitting name is Named then, because any class implementing that interface is a named thing, including, but not limited to our Person class:
class Person implements Named
{
protected $name;
protected $greeting;
public function __construct($name, Greeting $greeting)
{
$this->name = $name;
$this->greeting = $greeting;
}
public function getName()
{
return $this->name;
}
public function greet(Named $greetable)
{
return trim(sprintf(
'%s %s',
$this->greeting->getGreeting(),
$greetable->getName()
));
}
}
Our Person has a required name and we demand it to have a Greeting as well. All it can do besides returning it's name is greet another Named thing, likely another person. And that's it.
To put that all together now:
$greetings->addGreeting($greetingsFactory->createGreeting('Hi'));
$greetings->addGreeting($greetingsFactory->createGreeting('Howdy'));
$greetings->addGreeting($greetingsFactory->createGreeting('Hello'));
$john = new Person('John Doe', $greetings->getRandomGreeting());
$jane = new Person('Jane Doe', $greetings->getRandomGreeting());
echo $john->greet($jane),
PHP_EOL,
$jane->greet($john);
Live Demo on Codepad
Granted that's quite a lot of code for a very simple thing to do. Some will call it overengineered. But you asked for correct OOP and while I am sure there is still room for improvement, it's quite proper and SOLID in my book. And it's easy to maintain now, because the responsibilities are closer to where they should be.
Hmm, two things:
shuffling that array and accessing it from the outside, and having the outside call rely on the array being shuffled, doesn't feel right. It would be nicer to have a method that returns the result of an array shuffling, and maybe also the name straight away.
It would be good style to declare all object properties beforehand so it can be documented later. So if you use $this->name, you should declare it.
Both points implemented could look like this:
class greeting
{
protected $greet = array('Hi','Hello', 'Howzit', 'Ola', 'Whats up');
protected $name = null;
public function __construct($name)
{
$this->name = $name;
}
public function greet()
{
shuffle($this->greet);
return $this->greet[1]." ".$this->name;
}
}
from a beginners point of view it would be yes, but as this is a single object it cannot be orientated like you could with several objects.
True OOP is when you separate the individual entities of your application into objects / dependencies.
for example, a simple website would include the following:
Database
Error Handling
Sessions
Security
these are called entities and should not interact directly with each other, that's why there separate.
so if we wanted to interact Sessions and Security to make shore that the session is safe, we would add a method to the session object to return a PHP standard result such as array or string, this way many objects can interact with each other without relying on the actual object too much.
Looking at your attempt at a greeting class I would look at something like so:
class User
{
protected $data;
public function __construct(array $user_data)
{
$this->data = $user_data;
}
public function getUsername()
{
return $this->data['username'];
}
}
class Greeting
{
private $message = "welcome to mysite %s";
public function __construct(string $to_greet)
{
$this->message = sprintf($this->message,$to_greet);
}
public function getGreeting()
{
return $this->message;
}
}
the following would be used like so:
$User = new User(array(
'id' => 22,
'username' => 'Robert Pitt'
));
$Greeting = new Greeting($User->getUsername());
echo $Greeting->getGreeting();
now i have mentioned that objects do interact directly with each other but if they do that they should be encapsulated so that all the database objects such as Database,Result,DB_Error would only interact with each other.
this allows for code to be transportable to other projects without having to much of an issue, also known as libraries.
if the objects are closley related ina way that there all bundled together you could do something like this:
$User = new User(/*..From DB ..*/);
$Greeting = new Greeting($User);
echo $Greeting->getGreeting();
It would probably be better to have a greet method. The idea is that the user doesn't need to know that $this->greet is an array.
So:
class Greeting {
protected $greet = array('Hi','Hello', 'Howzit', 'Ola', 'Whats up');
protected $name='You';
function __construct($name) {
$this->name = $name;
}
function greet(){
shuffle($this->greet);
echo "{$this->greet[0]} {$this->name}!";
}
}
$hi = new Greeting('INSERTNAMEHERE');/*NAME OF PERSON GOES HERE*/
$hi->greet();
I have to disagree with [Edit: Some of] the other answers you've gotten. Making greet private and adding a getter does little to increase encapsulation.
Regardless of that, however, I think it's pretty poor OO design. An object should represent some thing (dare I say, some actual obect?) IMO, the "objects" here would really be the people (or whatever), one of whom is greeting the other. The greeting itself should be a message passed from one of those objects to the other. We might write a "greeting" class to hold the text of the greeting, but even if we do the greeting object itself should be independent of the source or target of the greeting.
It's a bit off the mark, actually. First of all, public variables are generally bad. You shouldn't be accessing class's variables directly from the code. You should try to encapsulate functionality provided by the class into the class itself.
First, let me show you how a good kind of OOP code could look like based on your example:
<?php
class greeting
{
private static $greets = array('Hi','Hello', 'Howzit', 'Ola', 'Whats up');
private $name;
function __construct ($name)
{
$this->name = $name;
}
function doGreeting ()
{
$i = array_rand(self::$greets);
return self::$greets[$i] . ' ' . $this->name;
}
}
$hi = new greeting('INSERTNAMEHERE');/*NAME OF PERSON GOES HERE*/
echo $hi->doGreeting();
Now, let's talk about the differences here.
First, the greets are stored in a static variable. Since these texts probably do not vary instance by instance, it's simply more efficient to store them in a static variable that is shared by the entire class, so every instance do not have their own copy of the array. You will also notice that it's private. This is encapsulation. The code outside does not need to know about the inner workings of the class, like the variable names. Outside code does not need to know about the array, since it should only be used within the class itself.
Another minor detail, is that the name is also declared there as private, since all class variables should be private in general for encapsulation. If they need to be accessed, that should be done via setter and getter functions, which can provide additional validation for values, if needed.
The code flow is also a bit different. Instead of using the class variables directly from the outside code, we get the class itself to produce the greeting and return it as a string. This way, the outside code does not need to know how the greeting texts are produced or where the name is stored. It jsut needs to know the API, i.e. the functions, their parameters and return values. How they actually work should be left for the class itself.
Additionally, since this is obviously functionality that is intended for the greeting class, it makes the code more reusable as the functionality is coded into the class. Part of the point of OOP is to create good reusable code that can be used where it is needed. When the class functionality is in the class itself, the same code does not needed to be coded elsewhere.
Remember encapsulation and reusability. These are two important points of OOP.
One of the basic ideas behind OOP is that you have objects that have responsibility over certain data structures in your code. what you have written above is really just a data structure, not really a full on object, it holds the data for the greeting, but doesn't really have responsibility over handling it and providing it for other objects.
A "better" object would look something like this:
class greeting {
protected $greet = array('Hi','Hello', 'Howzit', 'Ola', 'Whats up');
protected $name;
function __construct($name) {
$this->name = $name;
}
public function greet() {
return $this->greet[rand(0,5)] . ' ' . $this->name;
}
}
$hi = new greeting('INSERTNAMEHERE');/*NAME OF PERSON GOES HERE*/
echo $hi->greet();
Now your greet object is in total control of the greeting and your application code doesn't have to care about how that object is set up, it just has to care about the few functions it can use to get the greeting. If you wanted to eventually internationalize or change the greeting in some way, all you'd need to do is change that one object to do it.
Also, just to note, using objects does not make your code OOP. It needs to be object oriented, which means using objects to define discrete tasks that your application will need to perform and not making every other piece of the application have total access to all of it's data to do with what it will. Then, you're just building data structures.
its is not completely correct OOP because the $greet variable is not encapsulated.
to make it 'more correct' (whatever that means), you would have to make the $greet param private and create some get and set methods for it (same goes for the $name variable -- which also should be declared before it is used).
in php a get method is like so:
if i want to get the var:
$hi = new greeting('INSERTNAMEHERE');/*NAME OF PERSON GOES HERE*/
echo $hi->__get('greet') .' '. $hi->__get('name');
the get is created inside the greeting class:
function __get($var){
return $this->$var;
}
and set is the same:
function __set($var, $val){
$this->$var = $val;
}
I would probably use getters/setters for $greet, instead of making it public. I don't see why it wouldn't be considered OOP though.
http://en.wikipedia.org/wiki/Object-oriented_programming
Say I have a class which represents a person, a variable within that class would be $name.
Previously, In my scripts I would create an instance of the object then set the name by just using:
$object->name = "x";
However, I was told this was not best practice? That I should have a function set_name() or something similar like this:
function set_name($name)
{
$this->name=$name;
}
Is this correct?
If in this example I want to insert a new "person" record into the db, how do I pass all the information about the person ie $name, $age, $address, $phone etc to the class in order to insert it, should I do:
function set($data)
{
$this->name= $data['name'];
$this->age = $data['age'];
etc
etc
}
Then send it an array? Would this be best practice? or could someone please recommend best practice?
You should have setter/getter methods. They are a pain but you don't necessarily have to write them yourself. An IDE (for example Eclipse or Netbeans) can generate these for you automatically as long as you provide the class member. If, however, you don't want to deal with this at all and you're on PHP5 you can use its magic methods to address the issue:
protected $_data=array();
public function __call($method, $args) {
switch (substr($method, 0, 3)) {
case 'get' :
$key = strtolower(substr($method,3));
$data = $this->_data[$key];
return $data;
break;
case 'set' :
$key = strtolower(substr($method,3));
$this->_data[$key] = isset($args[0]) ? $args[0] : null;
return $this;
break;
default :
die("Fatal error: Call to undefined function " . $method);
}
}
This code will run every time you use a nonexistent method starting with set or get. So you can now set/get (and implicitly declare) variables like so:
$object->setName('Bob');
$object->setHairColor('green');
echo $object->getName(); //Outputs Bob
echo $object->getHairColor(); //Outputs Green
No need to declare members or setter/getter functions. If in the future you need to add functionality to a set/get method you simply declare it, essentially overriding the magic method.
Also since the setter method returns $this you can chain them like so:
$object->setName('Bob')
->setHairColor('green')
->setAddress('someplace');
which makes for code that is both easy to write and read.
The only downside to this approach is that it makes your class structure more difficult to discern. Since you're essentially declaring members and methods on run time, you have to dump the object during execution to see what it contains, rather than reading the class.
If your class needs to declare a clearly defined interface (because it's a library and/or you want phpdoc to generate the API documentation) I'd strongly advise declaring public facing set/get methods along with the above code.
Using explicit getters and setters for properties on the object (like the example you gave for set_name) instead of directly accessing them gives you (among others) the following advantages:
You can change the 'internal' implementation without having to modify any external calls. This way 'outside' code does not need change so often (because you provide a consistent means of access).
You provide very explicitly which properties are meant to be used / called from outside the class. This will prove very useful if other people start using your class.
The above reasons is why this could be considered best practice although it's not really necessary to do so (and could be considered overkill for some uses ; for example when your object is doing very little 'processing' but merely acts as a placeholder for 'data').
I perfectly agree with CristopheD (voted up). I'd just add a good practice when creating a new person.
Usually, a use a constructor which accept the mandatory fields and set the default values for the optional fields. Something like:
class Person
{
private $name;
private $surname;
private $sex;
// Male is the default sex, in this case
function Person($name, $surname, $sex='m'){
$this->name = $name;
$this->surname = $surname;
$this->sex = $sex;
}
// Getter for name
function getName()
{
return $this->name;
}
// Might be needed after a trip to Casablanca
function setSex($sex)
{
$this->sex = $sex;
}
}
Obviously, you could use the setter method in the constructor (note the duplicate code for the sex setter).
To go full OOP, you should do something similar to:
class User {
private $_username;
private $_email;
public function getUsername() {
return $this->_username;
}
public function setUsername($p) {
$this->_username = $p;
}
...
public function __construct() {
$this->setId(-1);
$this->setUsername("guest");
$this->setEmail("");
}
public function saveOrUpdate() {
System::getInstance()->saveOrUpdate($this);
}
}
If you want to save a user, you just create one, assign its values using Setters and do $user->saveOrUpdate(), and have another class to handle all the saving logic.
As a counterpoint to ChristopheD's answer, if your instance variable is strictly for private use, I wouldn't bother with writing a getter & setter, and just declare the instance variable private.
If other objects need to access the object, you can always add a getter. (This exposes another problem, in that other classes might be able to change the object returned by the getter. But your getter could always return a copy of the instance variable.)
In addition using a getter/setter also shields other parts of the same class from knowing about its own implementation, which I've found very useful on occasion!
From a more general point of view both direct access ($person->name) and accessor methods ($person->getName) are considered harmful. In OOP, objects should not share any knowledge about their internal structure, and only execute messages sent to them. Example:
// BAD
function drawPerson($person) {
echo $person->name; // or ->getName(), doesn't matter
}
$me = getPersonFromDB();
drawPerson($me);
// BETTER
class Person ....
function draw() {
echo $this->name;
}
$me = getPersonFromDB();
$me->draw();
more reading: http://www.javaworld.com/javaworld/jw-09-2003/jw-0905-toolbox.html
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');