If you are not yet planning to create an application with OO principles, use PHP's object-oriented (OO) language features, which will help you get started with the conversion between process programming and OO programming. 7
In the early days of PHP programming, PHP code was inherently limited to process-oriented. Procedural code is characterized by the use of procedures to build application blocks. Procedures provide some level of reuse by allowing calls between processes.
However, without object-oriented language constructs, programmers can still introduce OO features into PHP code. This is a bit difficult and makes the code difficult to read because it is a mixed example (procedural language with pseudo OO design). Using OO constructs in PHP code-such as the ability to define and use classes, the ability to build relationships between classes that use inheritance, and the ability to define interfaces-makes it easier to build code that conforms to good OO practices.
While the pure process design without too much modularity works well, the benefits of OO design are maintained. Because most of the life cycle of a typical application is spent on maintenance, code maintenance is an important part of the application life cycle. And in the development process, code maintenance can easily be forgotten. If there is competition in application development and deployment, long-term maintainability may be placed in a relatively minor position.
Modularity-One of the main features of excellent OO design-can help with such maintenance. Modularity will help encapsulate changes, which makes it easier to extend and modify applications over time.
In general, although the habit of building OO software is more than 7, but following the 7 habits here can make the code conform to the basic OO design standards. They will provide you with a more solid foundation on which to build more OO habits and build software that can be easily maintained and extended. These habits focus on several key features of modularity. For more information on the benefits of language-independent OO design, see resources.
7 Excellent PHP OO habits include:
Remain humble.
Be a good neighbor.
Avoid seeing Medusa.
Take advantage of the weakest link.
You are the eraser; I am the glue.
Limit the spread.
Consider usage patterns.
Remain humble
Maintaining modesty means avoiding exposing yourself in class implementations and function implementations. Hiding your information is a basic habit. If you can't develop a habit of hiding the details, it's hard to get into any other habit. Information hiding is also known as encapsulation.
There are many reasons for exposing public fields directly as a bad habit, and the most important reason is that you do not have the choices you should have in implementing the changes. Use OO concepts to isolate changes, and encapsulation plays an integral role in ensuring that changes are not inherently viral (viral) changes. A viral change is a small change at the beginning-such as changing an array that holds three elements to an array that contains only two elements. Suddenly, you find that you need to change more and more code to accommodate changes that should be very trivial.
An easy way to start hiding information is to keep the fields private and expose them in public access, just like windows in your home. Instead of opening the entire wall to the outside, open only one or two windows (I'll cover more information on the access method in "Good habits: using Public access Methods").
In addition to allowing your implementation to hide behind changes, using public access methods instead of directly exposing the fields will allow you to build on the base implementation by overwriting the implementation of the access method to perform a slightly different behavior than the parent method. It also allows you to build an abstract implementation that delegates the actual implementation to a class that overrides the base implementation.
Bad habits: Exposing public fields
In the bad code example in Listing 1, the field of the person object is exposed directly to the public field instead of using the access method. While this behavior is tempting, especially for lightweight data objects, it will limit you.
Listing 1. The bad habit of exposing public fields
Copy CodeThe code is as follows:
Class Person
{
Public $prefix;
Public $givenName;
Public $familyName;
Public $suffix;
}
$person = new Person ();
$person->prefix = "Mr.";
$person->givenname = "John";
Echo ($person->prefix);
Echo ($person->givenname);
?>
If the object has any changes, all code that uses the object also needs to be changed. For example, if someone's first name, last name, and other names are encapsulated in a PersonName object, you need to modify all the code to accommodate the changes.
Good habits: using public access methods
By using good OO habits (see Listing 2), the same object now has a private field instead of a public field, and a private field is carefully exposed to the outside world through the get and set public methods called access methods. These access methods now provide a common way to get information from a PHP class, so the need to change all code that uses the class is likely to be smaller when the implementation changes.
Listing 2. Good habits of using public access methods
Copy CodeThe code is as follows:
Class Person
{
Private $prefix;
Private $givenName;
Private $familyName;
Private $suffix;
Public Function Setprefix ($prefix)
{
$this->prefix = $prefix;
}
Public Function Getprefix ()
{
return $this->prefix;
}
Public Function Setgivenname ($GN)
{
$this->givenname = $gn;
}
Public Function Getgivenname ()
{
return $this->givenname;
}
Public Function Setfamilyname ($FN)
{
$this->familyname = $FN;
}
Public Function Getfamilyname ()
{
return $this->familyname;
}
Public Function Setsuffix ($suffix)
{
$this->suffix = $suffix;
}
Public Function Getsuffix ()
{
return $suffix;
}
}
$person = new Person ();
$person->setprefix ("Mr.");
$person->setgivenname ("John");
Echo ($person->getprefix ());
Echo ($person->getgivenname ());
?>
At first glance, this code might do a lot of work, and it might actually be more work on the front end. However, in the long run, using good OO habits is often a cost-effective way, because future changes will be greatly consolidated.
In the code version shown in Listing 3, I have changed the internal implementation to use the associative array of the name part. Ideally, I would like to have error handling and check the existence of the element more closely, but the purpose of this example is to show that the code that uses my class does not have to be changed-the code does not perceive that the class has changed. Keep in mind that the reason to adopt OO habits is to carefully encapsulate changes so that the code is more extensible and easier to maintain.
Listing 3. Another example that uses different internal implementations
Copy CodeThe code is as follows:
Class Person
{
Private $personName = Array ();
Public Function Setprefix ($prefix)
{
$this->personname[' prefix ') = $prefix;
}
Public Function Getprefix ()
{
return $this->personname[' prefix '];
}
Public Function Setgivenname ($GN)
{
$this->personname[' givenName ') = $GN;
}
Public Function Getgivenname ()
{
return $this->personname[' GivenName '];
}
/* Etc ... */
}
/*
* Even though the internal implementation changed, the code here stays exactly
* the same. The change have been encapsulated only to the person class.
*/
$person = new Person ();
$person->setprefix ("Mr.");
$person->setgivenname ("John");
Echo ($person->getprefix ());
Echo ($person->getgivenname ());
?>
Be a good neighbor.
When building a class, it should handle its own errors correctly. If the class does not know how to handle the error, the error should be encapsulated in a format that its callers understand. Also, avoid returning objects that are empty or that have invalid states. Many times, this can be achieved simply by verifying the parameters and throwing a specific exception to explain why the supplied parameter is invalid. When you develop this habit, it can help you-and people who maintain code or use objects-save a lot of time.
Bad habits: do not handle errors
Consider the example shown in Listing 4, which takes some parameters and returns a person object populated with some values. However, in the Parsepersonname () method, there is no validation of whether the supplied $val variable is empty, whether it is a 0-length string, or whether the string uses a format that cannot be resolved. The Parsepersonname () method does not return a person object, but returns null. Administrators or programmers who use this method may find it cumbersome-at least they now need to start setting breakpoints and debugging PHP scripts.
Listing 4. Bad habit of not throwing or handling errors
Copy CodeThe code is as follows:
Class Personutils
{
public static function Parsepersonname ($format, $val)
{
if (Strpos (",", $val) > 0) {
$person = new Person ();
$parts = Split (",", $val); Assume the value is last, first
$person->setgivenname ($parts [1]);
$person->setfamilyname ($parts [0]);
}
return $person;
}
}
The Parsepersonname () method in Listing 4 can be modified to initialize the person object outside the if condition, ensuring that a valid person object is always obtained. However, you get a person who does not have a set attribute, which still does not improve your predicament well.
Good habit: Each module handles its own errors
Do not let the caller guess, but the parameters are pre-validated. If a variable that is not set cannot produce a valid result, check the variable and throw invalidargumentexception. If the string cannot be empty or must be in a specific format, check the format and throw an exception. Listing 5 explains how to create an exception and some new conditions in the Parseperson () method that demonstrates some basic validation.
Listing 5. A good habit of throwing wrong
Copy CodeThe code is as follows:
Class Invalidpersonnameformatexception extends Logicexception {}
Class Personutils
{
public static function Parsepersonname ($format, $val)
{
if (! $format) {
throw new Invalidpersonnameformatexception ("Invalid personname format.");
}
if ((! isset ($val)) | | strlen ($val) = = 0) {
throw new InvalidArgumentException ("must supply a Non-null value to parse.");
}
}
}
?>
The ultimate goal is to want people to be able to use your class without having to understand how it works. If they are using a method that is incorrect or not used in the desired way, there is no need to guess the reason for not working. As a good neighbor, you need to know that the person who reuses your class has no supernatural powers, so you need to solve the guessing problem.
Avoid seeing Medusa
When I first learned about OO concepts, I was very skeptical about whether the interface was really helpful. My colleague gave me an analogy, saying that it was like seeing Medusa's head without using an interface. In Greek mythology, Medusa is a female monster with a serpent hair. Anyone who looked at her would turn into a stone. Pearl Hughes, who killed Medusa, was able to confront her by observing her shadow on the shield and avoiding turning into a stone.
The interface is a mirror against Medusa. When you use a specific implementation, the code must also change as the implementation code changes. Direct use of the implementation will limit your choice, because you have essentially turned the class into a "stone".
Bad habit: Do not use interfaces
Listing 6 shows an example of a person object loaded from a database. It gets the name of the person and returns the matching people object in the database.
Listing 6. Bad habit of not using interfaces
Copy CodeThe code is as follows:
Class Dbpersonprovider
{
Public Function Getperson ($givenName, $familyName)
{
/* Go to the database, get the person ... */
$person = new Person ();
$person->setprefix ("Mr.");
$person->setgivenname ("John");
return $person;
}
}
/* I need to get the person data ... */
$provider = new Dbpersonprovider ();
$person = $provider->getperson ("John", "Doe");
Echo ($person->getprefix ());
Echo ($person->getgivenname ());
?>
Code that loads a person from a database can run correctly before the environment changes. For example, loading a person from a database might work for the first version of the application, but for the second version, you might want to add the ability to load people from a WEB service. In fact, the class has become "stone" because it is using the implementation class directly and can now make changes very limited.
Good habit: Using interfaces
Listing 7 shows a code example that has not been changed since the new method of loading the user has been implemented. The example shows an interface named Personprovider that declares a single method. If any code uses Personprovider, the code prohibits direct use of the implementation class. Instead, it uses personprovider as if it were an actual object.
Listing 7. Good habit of using interfaces
Copy CodeThe code is as follows:
Interface Personprovider
{
Public Function Getperson ($givenName, $familyName);
}
Class Dbpersonprovider implements Personprovider
{
Public Function Getperson ($givenName, $familyName)
{
/* Pretend to go to the database, get the person ... */
$person = new Person ();
$person->setprefix ("Mr.");
$person->setgivenname ("John");
return $person;
}
}
Class Personproviderfactory
{
public static function Createprovider ($type)
{
if ($type = = ' database ')
{
return new Dbpersonprovider ();
} else {
return new Nullprovider ();
}
}
}
$config = ' database ';
/* I need to get the person data ... */
$provider = Personproviderfactory::createprovider ($config);
$person = $provider->getperson ("John", "Doe");
Echo ($person->getprefix ());
Echo ($person->getgivenname ());
?>
When using an interface, try to avoid directly referencing the implementation class. Conversely, using content outside of an object can provide the correct implementation. If your class will mount an implementation based on some logic, it still needs to get the definition of all the implementation classes, and that does not make any effect.
You can use the Factory mode to create an instance of an implementation class that implements an interface. By convention, the factory method begins with create and returns the interface. It can obtain the necessary parameters for your factory to calculate which implementation class should be returned.
In Listing 7, the Createprovider () method just gets $type. If the $type is set to database, the factory returns an instance of Dbpersonprovider. Any new implementations of people loaded from the database do not require any changes in the classes that use factories and interfaces. Dbpersonprovider will implement the Personprovider interface and have the actual implementation of the Getperson () method.
Take advantage of the weakest link
Loosely coupling the modules together is a good thing; it is one of the properties that allows you to encapsulate changes. The other two habits-"stay cautious" and "avoid Medusa"-can help you build loosely coupled modules. To implement loosely coupled classes, it is possible to develop a habit of reducing class dependencies.
Bad habits: tight coupling
In Listing 8, reducing dependencies does not have to reduce the dependency of the client using the object. Instead, the example demonstrates how to reduce the dependency on the correct class and minimize the dependency.
Listing 8. The bad habit of tight coupling in Address
Copy CodeThe code is as follows:
Require_once "./addressformatters.php";
Class Address
{
Private $addressLine 1;
Private $addressLine 2;
Private $city;
Private $state; Or province ...
Private $postalCode;
Private $country;
Public Function SetAddressLine1 ($line 1)
{
$this->addressline1 = $line 1;
}
/* accessors, etc ... */
Public Function Getcountry ()
{
return $this->country;
}
Public function Format ($type)
{
if ($type = = "inline") {
$formatter = new Inlineaddressformatter ();
} else if ($type = = "Multiline") {
$formatter = new Multilineaddressformatter ();
} else {
$formatter = new Nulladdressformatter ();
}
Return $formatter->format ($this->getaddressline1 (),
$this->getaddressline2 (),
$this->getcity (), $this->getstate (), $this->getpostalcode (),
$this->getcountry ());
}
}
$ADDR = new Address ();
$addr->setaddressline1 ("123 any St.");
$addr->setaddressline2 ("Ste 200");
$addr->setcity ("Anytown");
$addr->setstate ("AY");
$addr->setpostalcode ("55555-0000");
$addr->setcountry ("US");
Echo ($addr->format ("Multiline"));
Echo ("\ n");
Echo ($addr->format ("inline"));
Echo ("\ n");
?>
The code that calls the format () method on the Address object might look great-what this code does is use the address class, call format (), and finish. Instead, the Address class is less fortunate. It needs to understand the various formatting methods used for proper formatting, which may make it impossible for the Address object to be reused by others, especially if other people are not interested in using the Format method class in the format () method. Although the code that uses address does not have many dependencies, the address class has a lot of code, which may be just a simple data object.
The address class is tightly coupled to the implementation class that knows how to format the Address object.
Good habit: loose coupling between objects
When building an excellent OO design, you must consider the concept of separation of concerns (separation of CONCERNS,SOC). A SoC is an attempt to decouple objects by actually focusing on the content, thereby reducing the degree of coupling. In the original Address class, it had to focus on how to format it. This may not be a good design. However, the address class should consider the parts of address, and some formatting methods should focus on how to properly format addresses.
In Listing 9, the code that formats the address is moved to the interface, the implementation class, and the factory-the habit of "using interfaces". Now, the Addressformatutils class is responsible for creating a format method and formatting the Address. Any other object can now use Address without worrying about the need to get the definition of the formatting method.
Listing 9. A good habit of loosely coupling between objects
Copy CodeThe code is as follows:
Interface Addressformatter
{
Public function Format ($addressLine 1, $addressLine 2, $city, $state,
$postalCode, $country);
}
Class Multilineaddressformatter implements Addressformatter
{
Public function Format ($addressLine 1, $addressLine 2, $city, $state,
$postalCode, $country)
{
Return sprintf ("%s\n%s\n%s,%s%s\n%s",
$addressLine 1, $addressLine 2, $city, $state, $postalCode, $country);
}
}
Class Inlineaddressformatter implements Addressformatter
{
Public function Format ($addressLine 1, $addressLine 2, $city, $state,
$postalCode, $country)
{
Return sprintf ("%s%s,%s,%s%s%s",
$addressLine 1, $addressLine 2, $city, $state, $postalCode, $country);
}
}
Class Addressformatutils
{
public static function Formataddress ($type, $address)
{
$formatter = Addressformatutils::createaddressformatter ($type);
Return $formatter->format ($address->getaddressline1 (),
$address->getaddressline2 (),
$address->getcity (), $address->getstate (),
$address->getpostalcode (),
$address->getcountry ());
}
private static function Createaddressformatter ($type)
{
if ($type = = "inline") {
$formatter = new Inlineaddressformatter ();
} else if ($type = = "Multiline") {
$formatter = new Multilineaddressformatter ();
} else {
$formatter = new Nulladdressformatter ();
}
return $formatter;
}
}
$ADDR = new Address ();
$addr->setaddressline1 ("123 any St.");
$addr->setaddressline2 ("Ste 200");
$addr->setcity ("Anytown");
$addr->setstate ("AY");
$addr->setpostalcode ("55555-0000");
$addr->setcountry ("US");
Echo (Addressformatutils::formataddress ("Multiline", $addr));
Echo ("\ n");
Echo (addressformatutils::formataddress ("inline", $addr));
Echo ("\ n");
?>
The disadvantage, of course, is that as long as the pattern is used, the number of artifacts (classes, files) is usually increased. However, by reducing maintenance in each class, you can compensate for this disadvantage, and even reduce the amount of artifacts when you get the right reusability.
You are the eraser; I'm the glue.
The highly cohesive OO design is centralized and organized into the relevant modules. Understanding "Focus" is important for deciding how to connect functions and classes closely.
Bad habits: lower cohesion
When the cohesion of the design is low, it is not able to organize classes and methods well. Spaghetti codes (spaghetti Code) are commonly used to describe classes and methods that are bundled together and have low cohesion. Listing 10 provides an example of spaghetti-style code. The relatively common Utils class will use many different objects and have many dependencies. It does a lot of work, so it's hard to reuse.
Listing 10. A bad habit of reducing cohesion
Copy CodeThe code is as follows:
Class Utils
{
public static function Formataddress ($formatType, $address 1,
$address 2, $city, $state)
{
Return "some address string";
}
public static function Formatpersonname ($formatType, $givenName,
$familyName)
{
Return "some person name";
}
public static function Parseaddress ($formatType, $val)
{
Real implementation would set values, etc ...
Return to New Address ();
}
public static function Parsetelephonenumber ($formatType, $val)
{
Real implementation would set values, etc ...
return new telephonenumber ();
}
}
?>
Good habit: Using high cohesion
High cohesion refers to grouping interrelated classes and methods together. If both methods and classes have a high degree of cohesion, it is easy to decompose the entire group without affecting the design. The design with high cohesion will provide an opportunity to reduce coupling. Listing 11 shows the two methods that are better organized into classes. The Addressutils class will contain methods for working with the address class, showing a high degree of cohesion between addresses-related methods. Similarly, personutils will contain methods that specialize in handling person objects. The coupling of the two new classes with a highly cohesive approach is very low, because they can be used completely independently.
Listing 11. A good habit of high cohesion
Copy CodeThe code is as follows:
Class Addressutils
{
public static function Formataddress ($formatType, $address 1,
$address 2, $city, $state)
{
Return "some address string";
}
public static function Parseaddress ($formatType, $val)
{
Real implementation would set values, etc ...
Return to New Address ();
}
}
Class Personutils
{
public static function Formatpersonname ($formatType, $givenName,
$familyName)
{
Return "some person name";
}
public static function Parsepersonname ($formatType, $val)
{
Real implementation would set values, etc ...
return new PersonName ();
}
}
?>
Restricting communication
I often mention to the members of my software team (where I am a technical director or architect) that the most common enemy of OO language is copy and paste operations. When used in the absence of a pre-OO design, no action can be as destructive as copying code between classes. Whenever you want to copy code from one class to the next, stop and consider how you can use the class hierarchy to take advantage of similar or identical functionality. In most cases, with good design, you will find it completely unnecessary to copy the code.
Bad habits: Do not use class hierarchies
Listing 12 shows a simple example of a partial class. They start with repeating fields and methods-in the long run, they are detrimental to the application making changes. If there is a flaw in the person class, it is also likely that there is a flaw in the Employee class because it appears that the implementation was replicated between two classes.
Listing 12. Bad habits that don't use hierarchies
Copy CodeThe code is as follows:
Class Person
{
Private $givenName;
Private $familyName;
}
Class Employee
{
Private $givenName;
Private $familyName;
}
?>
Inheritance is a difficult habit to start with, because it usually takes a lot of time to build an analysis of the correct inheritance model. Conversely, it takes only a few seconds to build a new implementation using CTRL + C key combination and CTRL + V combinations. But this part of the time that is saved is usually quickly offset during the maintenance phase, because the application will actually spend a lot of maintenance.
Good habits: Using inheritance
In Listing 13, the new Employee class expands the person class. It will now inherit all the common methods and do not re-implement these methods. In addition, listing 13 shows the use of abstract methods, shows how to put basic functionality into a base class, and how to block implementation classes from using specific functions.
Listing 13. Take advantage of the good habits of inheritance
Copy CodeThe code is as follows:
Abstract class Person
{
Private $givenName;
Private $familyName;
Public Function Setgivenname ($GN)
{
$this->givenname = $gn;
}
Public Function Getgivenname ()
{
return $this->givenname;
}
Public Function Setfamilyname ($FN)
{
$this->familyname = $FN;
}
Public Function Getfamilyname ()
{
return $this->familyname;
}
Public Function SayHello ()
{
Echo ("Hello, I AM");
$this->introduceself ();
}
Abstract public Function introduceself ();
}
Class Employee extends Person
{
Private $role;
Public Function Setrole ($r)
{
$this->role = $r;
}
Public Function Getrole ()
{
return $this->role;
}
Public Function introduceself ()
{
Echo ($this->getrole (). " " . $this->getgivenname (). " " .
$this->getfamilyname ());
}
}
?>
Consider usage patterns
Design patterns refer to common interactions between objects and methods, and time proves that it solves certain problems. When you consider using design patterns, you need to understand how classes interact with each other. It is a simple way to build classes and their interactions without repeating the mistakes of others and benefiting from proven designs.
Bad habits: Consider an object at a time
There is actually no appropriate code sample to demonstrate how to consider usage patterns (although there are plenty of good examples to show the pattern implementation). However, in general, you know that only one object can be considered at a time when the following conditions are met:
Object models are not designed in advance.
Start writing implementations of a single method without removing most of the models.
Do not use design pattern names in conversations rather than talk about implementations.
Good habit: Adding objects formed in a pattern at the same time
Generally, you are considering usage patterns when you do the following:
Build classes and their interactions in advance.
The class is applied according to the pattern.
Use schema names, such as Factory, Singleton, and facade.
Remove most of the models and start adding implementations.
Conclusion
Developing good OO habits in PHP will help you build applications that are more stable, easier to maintain, and easier to scale. Remember:
Stay cautious.
Be a good neighbor.
Avoid seeing Medusa.
Take advantage of the weakest link.
You are the eraser, I am the glue.
Limit the spread.
Consider usage patterns.
As you develop and apply these habits, you are likely to be surprised to see the quality of the application leap.
http://www.bkjia.com/PHPjc/321168.html www.bkjia.com true http://www.bkjia.com/PHPjc/321168.html techarticle If you are not yet planning to create an application with OO principles, use PHP's object-oriented (OO) language features, which will help you get started between process programming and OO programming ... 7 .