First of all, when you're developing strong-OO classes, you should be exposing as little of the internal semantics of your class as possible (obviously without affecting functionality).
Some variables are only valuable inside the context of the class itself, and would make no sense to a developer using the class. Making the variable public allows anyone using the class to change such a variable at will, despite the fact that they may not know what it's used for. In PHP this can be a particular problem when you don't even have type safety to at least mitigate the damage that can be done.
Consider this: You have a class which wraps around some I/O operations. Let's call it FileReader
class FileReader {
public $_handle;
public function __construct($filepath) {
$this->_handle = fopen($filepath, 'r');
if ($this->_handle === NULL) {
throw new Exception("Unable to open the file for reading");
}
}
// ... the rest of the class
}
Now you can see that the class opens up a handle to a file. By making the $_handle
variable public, you've exposed it to any and all people working on your class. They don't need to know about the raw file handle you have open, they just want to use your nice class to perform some read operation. However, it IS public; not only can they see it, but they can change it. This is bad, especially when your other code assumes that the $_handle
variable is valid.
$reader = new FileReader();
$reader->_handle = "I hope this doesn't break anything. /trololol";
$reader->someOperation(); // oh no! Our file handle has just been changed to something completely wrong, this is now going to the break the class.
Such ridiculous scenarios can be avoided entirely by making the variable private in the first place. For more (and better) example of what each access modifier does, and when to apply them see this answer.
Now, onto getters and setters. In your question, you seem to assume that all getters and setters are written the following way:
class Foo {
private $_bar;
public function getBar() {
return $this->_bar;
}
public function setBar($newBar) {
$this->_bar = $newBar
}
}
In which case, you're absolutely right there is no difference between that and changing the $_bar
variable to be public in the first place.
However, getter and setter methods give you control over how your variables are being set by an external developer, so you can instantly detect when they're going to make a boo-boo and avoid undefined behaviour later on. For example:
class Foo {
private $_bar;
public function getBar() {
return $this->_bar;
}
public function setBar($newBar) {
// Now we're going to ensure that $newBar is always an integer
if (!is_int($newBar)) {
// not an integer, throw out an exception to let the developer know that somewhere is setting invalid input
throw new Exception("Expected an integer value for 'Bar'");
}
$this->_bar = $newBar;
}
}
This is not only making your class far more robust, but also making the life of the developer using your class a hell of a lot easier. Rather than having to debug an extremely weird issue somewhere later on when the class attempts to use the corrupt value of $_bar
, they can easily tell from a stack trace where the corrupt value was set from and fix it at the source.
There is plenty of documentation about variable access and getter/setter methods out there, and it applies to a whole range of languages so don't be afraid to look up articles that were based on C++/C#/VB.NET, they all roughly translate to the same material.