Why would I use OOP to hide information?
Why would I use PHP to Hide Information?
<?php
function foo($bar) {
echo $bar;
}
foo('foobar');
?>
VERSUS开发者_JAVA技巧
<?php
class foo {
private $bar;
function __construct($b){
$this->bar = $b;
}
function display() {
echo $this->bar;
}
}
$foobar = new foo('bar');
$foobar->display();
?>
Whatever you publish becomes your public contract. Other people start to depend on your public methods, use them and expect them to be there and work the same. 'Other people' maybe yourself half a year later.
So be extremely conservative in what to make public. It gives you the freedom to evolve your code and fix bugs in it without breaking the public interface.
Information hiding (encapsulation) is a good thing since it reduces the possibility of clients using "undocumented" information.
The whole point of encapsulation is to minimise the interface to your code so that you can change the non-published bits whenever you want without affecting clients of it.
For example, let's say you have a dictionary class which maps one string to another. Let's further say that you implemented this as a quick and dirty two-array solution because you were behind schedule - apparently this happens sometimes :-) And that you didn't encapsulate the array and methods that use it.
So, it's been in the field for a while and millions of customers have bought it. Half of them are complaining about the speed since their dictionaries have a hundred thousand entries.
The other half are using it by going behind your back and directly using your internal, but unhidden data structures.
What do you do? If you do nothing, half a million of your customers will not renew their contracts and they will bad-mouth your product.
If you change your code to use a balanced tree or hashing, the other half million customers will moan about your decision.
Here's what you end up doing. You end up maintaining two versions, one for the large-data people, the other for the sneaky people. This increases your costs and effort considerably.
If you had properly encapsulated your data and methods, you could have replaced the internals wholesale with absolutely no impact on any of your customers.
You would do this to encapsulate the functionality and protect the using code from change. Take this example:
class Person
{
protected $legs;
public function setLegs($number){
$this->legs = $number;
}
}
Lets presume we now have some code that uses this class...
if ($_POST['legs'])
{
$person = new Person;
$person->setLegs($_POST['legs']);
}
Ofcours you could do this with the following class
class Person
{
public $legs;
}
$person = new Person; $person->legs = $_POST['legs'];
The problem comes if you need to provide any validation to legs or if you want to make changes later. Let's say you have to make a change to the rules about a person (for example the maximum amount of legs a person can have is ten) - if you havent encapsulated the logic you now need to go all over your app finding its uses...
class Person
{
protected $legs;
public function setLegs($number){
if ( ! is_int($number) || $number > 10){
throw new Exception('incorrect user input');
}
$this->legs = $number;
}
}
Encapsulation is important for the following reasons:
- It allows application logic to be reused
- It makes it possible to make changes easier later
Your example doesn't seem to clearly demonstrate what it sounds like you're asking. Are you wondering why people would use various protection qualifiers on class members rather than just make everything public?
It's the concept of encapsulation, essentially. Think of the externally visible "footprint" of a class as its "contract." The class, as defined and externally visible, provides some set of functionality. Exactly how that class achieves the functionality, internally, is of no concern to anything outside of that class. Not only does it not need to be known outside of the class, it explicitly shouldn't be known.
This leads to further concepts key to Object Oriented Design called separation of concerns, dependency inversion, the open/closed principle, etc. If other classes/objects/etc. had direct access to all of the internals of that particular class, one could write code to use those internals. Private members, private methods, etc.
This creates a dependency between that external code and the internal logic of the class which shouldn't be exposing that internal logic. This makes it more difficult to re-implement that class, swap it out with another which implements the same "contract" (albeit with different internal functionality), transparently add additional internal functionality without altering the "contract," etc.
Edit: You may additionally be wondering why people would create a private member variable and then expose a public getter and setter to manipulate that variable. Why go through that extra hassle when you could just make the variable public in the first place, right?
Well, in some cases that may be fine. But keep in mind that concept of encapsulation and maintaining a contract. What if you wanted to change some internal implementation of the class and the variable is affected? Maybe you need to change its type slightly? If the variable is publicly exposed, especially in statically typed environments (not PHP, but you get the idea), any such change would be a "breaking change" for the contract.
If instead there are public getter/setter methods, you can alter the private variable as needed and do whatever conversion or logic is necessary in the methods, essentially keeping the change transparent.
Or perhaps you want to audit changes to that variable... Just do it in the setter method (log it, raise an event, whatever you need to do) as opposed to everywhere in the code that the public variable is accessed (including code that hasn't been written yet).
The habit of making variables private and wrapping them in public getters/setters (when necessary... not every private member variable needs public access) is a good habit to maintain in general. It's entirely possible, even likely, that the vast majority of your class members will never go beyond that simple logic. But on the comparatively rare occasions where it happens, it'll be a lot easier with the getters/setters in place.
Basically, it's a design that adds essentially very little up-front code (a one-time creation of a getter/setter, as opposed to on-going maintenance of member variable access) to allow you the freedom to make changes to the class without breaking the binary compatibility of the object and breaking its "contract."
Edit: @mario made a good point in his comment, and I'd like to clarify something. It's definitely not a good habit to always write getters/setters for all private members. The idea is to use getters/setters for members which logically should be public. For example, if the class defines a piece of text in a display and the members being modified by the getters/setters are the font face, size, weight, etc. There you would logically see access methods (which are treated differently in different languages) to set those properties of the class.
Those properties may internally be maintained by a single private member each, or by a combination or members, or by some other means, etc. That's the part that shouldn't be exposed outside of the class. All anything outside of the class knows is "I'm telling this object to change its font weight." Not "I'm telling this object to set its _font
variable to this value."
Note also that externally what is seen as a member by means of accessors might not be accessing a private member at all, or at least not in the same way. A good example of this would be read-only accessors (getters) which represent some given state of the object. IsValid
for example may perform all kinds of business validation logic internally on the model and return a bool
representing the state of the object. It's not returning the contents of some private bool
member.
When developing a library, for example, you might want to make the internals of your class hidden to users of your API so that if you decide to change how your class works, you don't have to worry about breaking everyone's programs because they've been accessing members that they shouldn't. You only make visible an interface that you know won't change, and this way you can safely modify how these functions work.
精彩评论