Home Backend Development PHP Tutorial PHP Master | Introduction to the Law of Demeter

PHP Master | Introduction to the Law of Demeter

Feb 25, 2025 pm 11:26 PM

PHP Master | Introduction to the Law of Demeter

Core points

  • Dimit's law, also known as the principle of least knowledge, advocates minimizing the object's understanding of other objects, and advocates only interacting with direct neighbors to enhance modularity and maintainability.
  • Abide by the Dimitt Law can significantly enhance the design of loosely coupled software modules, making the code easier to maintain, test and modify.
  • Common violations of the Dimitter law occur when objects or methods know too much about the structure and elements of other objects, resulting in tightly coupled codes that are difficult to manage and evolve.
  • Practical examples in PHP demonstrate how violations can be cleverly embedded in common practices, such as using a service locator that exposes the internal details of other objects.
  • Refactoring the code to conform to the Dimitian law requires direct interaction with only necessary components to avoid unnecessary intermediates that complicate the architecture and increase dependencies.
  • While the Dimitter law improves code quality by reducing dependencies and promoting high cohesion, it should be applied pragmatically, taking into account the specific context and potential trade-offs in complexity and performance.

Software programming is a balanced combination of art (sometimes euphemism for improvisation) and many proven heuristics to solve certain problems and solve them in a decent way. Few people would disagree that the artistic aspect is by far the hardest to hone and refine. On the other hand, the power behind heuristics is essential to being able to develop software based on good design. With so many heuristics explaining how and why software systems should stick to specific methods, it is quite disappointing to not see them more widely implemented in the PHP world. For example, the Dimitian Law may be one of the most underrated laws in the language field. In fact, the rule’s motto of “talking only with your close friends” seems to be in a rather immature state in PHP, which has led to a decline in overall quality of several object-oriented code bases. Some popular frameworks are actively pushing it forward in an attempt to adhere to the precepts of the law more. It makes no sense to blame each other for violating the Dimitese law, because the best way to mitigate such destruction is to simply take a pragmatic attitude and understand what is actually under the law, so that it is consciously applied when writing object-oriented code. . To join the cause of justice and to study the law more deeply from a practical point of view, in the next few lines I will demonstrate with some practical examples why things as simple as observing the principles of the law are designed in loosely coupled software Module time can really improve efficiency.

It is not a good thing to know too much

is often called the principle of least knowledge, and the rules advocated by the Dimitese law are easy to understand. Simply put, suppose you have a well-designed class that implements a given method, then the method should be limited to calling other methods that belong to the following object:

    An instance of the original class of the
  1. method.
  2. Parameter object of the target method.
  3. Object created by the target method.
  4. The dependency object of the original class of the
  5. method.
  6. Global objects that the original class can access in the target method (Oh!)

Although the list is far from formal (for more formal lists, check out Wikipedia), these key points are easy to understand. In traditional design, it is considered wrong to know too much about another object (which implicitly includes knowing how to access a third object) because in some cases the object must unnecessarily go from top to bottom Iterating through the clumsy intermediates to find the actual dependencies it needs to work as expected. This is a serious design flaw for obvious reasons. The caller has a fairly extensive and detailed understanding of the internal structure of the intermediate, even if this is accessed through several getters. Furthermore, using intermediate objects to get the object required by the caller illustrates a problem in itself. After all, if the same result can be achieved by directly injecting the dependencies, why use such a complex path to get the dependencies or call one of its methods? This process has no meaning at all.

Let's assume we need to build a file storage module that uses a polymorphic encoder internally to pull data into and save it to the given target file. If we deliberately sloppyly connect the module to an injectable service locator, its implementation will look like this:

<?php namespace LibraryFile;
use LibraryDependencyInjectionServiceLocatorInterface;

class FileStorage
{
    const DEFAULT_STORAGE_FILE = "data.dat";
    private $locator;
    private $file;

    public function __construct(ServiceLocatorInterface $locator, $file = self::DEFAULT_STORAGE_FILE)  {
        $this->locator = $locator;
        $this->setFile($file);
    }

    public function setFile($file) {
        if (!is_readable($file) || !is_writable($file)) {
            throw new InvalidArgumentException(
                "The target file is invalid.");
        }
        $this->file = $file;
        return $this;
    }

    public function write($data) {
        try {
            return file_put_contents($this->file, 
                $this->locator->get("encoder")->encode($data),
                LOCK_EX);
        }
        catch (Exception $e) {
            throw new $e(
                "Error writing data to the target file: " . 
                $e->getMessage());
        }
    }

    public function read() {
        try {
            return $this->locator->get("encoder")->decode(
                @file_get_contents($this->file));
        }
        catch(Exception $e) {
            throw new $e(
                "Error reading data from the target file: " .
                $e->getMessage());
        }
    }
}
Copy after login

Omit some irrelevant implementation details, focusing on the constructor of the FileStorage class and its write() and read() methods. This class injects an instance of a service locator that has not been defined and is later used to fetch dependencies (the aforementioned encoder) in order to fetch and store data in the target file. This is usually a violation of the Dimitter law, considering that the class traverses the locator first and then reaches the encoder. Caller FileStorage knows too much about the internal structure of the locator, including how to access the encoder, which is definitely not a capability I would like to praise. It is an artifact inherently rooted in the nature of a service locator (which is why some people think of it as anti-pattern) or any other type of static or dynamic registry, which I pointed out before. To get a more comprehensive understanding of this problem, let's check the implementation of the locator:

(The codes of locator and encoder are omitted here because they are consistent with the previous output. In order to avoid duplication, I will not repeat them here.)

With the encoder, let's start with all the sample classes together:

(The usage sample code is omitted here because it is consistent with the previous output. In order to avoid duplication, I will not repeat it here.)

Violations of this law are a rather covert problem in this case and are difficult to track from the surface, except for the use of mutator of the locator, which suggests that at some point the encoder will be somehow taken by FileStorage instance access and use. In any case, the fact that we know that the violation is there hidden outside the outside world not only reveals too much information about the locator structure, but also unnecessarily couples the FileStorage class to the locator itself. Just follow the rules of this rule and get rid of the locator, we can remove the coupling while providing FileStorage with the actual collaborators it needs to do its business. There are no more clumsy, exposed intermediates along the way! Fortunately, all this nonsense can be easily converted into working code with a little effort. Simply view the enhanced, Dimitri law-compliant version of FileStorage class here:

(The refactored FileStorage code is omitted here because it is consistent with the previous output. In order to avoid duplication, I will not repeat it here.)

This is indeed easy to refactor. Now, the class directly uses any implementer of the EncoderInterface interface, avoiding traversing the internal structure of unnecessary intermediates. The example is undoubtedly trivial, but it does illustrate a point of validity and demonstrate why following the precepts of Dimitri's law is one of the best things you can do to improve the design of the class. However, a special case of this rule is deeply explored in Robert Martin's book "The Way of Code: Agile Software Development Manual" and deserves special analysis. Please take a moment to think carefully: What happens if FileStorage is defined as getting its collaborator through a Data Transfer Object (DTO)?

(The code example using DTO is omitted here, because it is consistent with the previous output, and in order to avoid duplication, I will not repeat it here.)

This is definitely an interesting way to implement file storage classes, as it now uses injectable DTOs to transfer and use encoder internally. The question to be answered is whether this method really violates the law. From a purist perspective, it does violate, because DTO is undoubtedly an intermediate that exposes its entire structure to the caller. However, DTO is just a normal data structure, unlike earlier service locators, it does not behave at all. And the purpose of the data structure is...yes, to disclose its data. This means that as long as the intermediate does not implement the behavior (which is exactly the opposite of the behavior of a regular class, which hides its data because it exposes the behavior), the Dimitter law remains intact. The following code snippet shows how to use FileStorage using the problematic DTO:

(The code example using DTO is omitted here, because it is consistent with the previous output, and in order to avoid duplication, I will not repeat it here.)

This approach is much more troublesome than passing an encoder directly into a file storage class, but the example shows that some tricky implementations that may appear at first glance to be blatant violations of the law, are usually quite harmless, as long as they Just use a data structure without any additional behavior.

Conclusion

As various complex, sometimes esoteric heuristics are popular in OOP, it seems meaningless to add another principle that obviously has no obvious positive impact on the design of layer components. However, the Dimitter Law is by no means a principle that is hardly applied in the real world. Despite its gorgeous name, the Dimitt Law is a powerful paradigm with the main goal of facilitating the implementation of highly decoupled application components by eliminating any unnecessary intermediates. Just follow its precepts and of course don't be blindly dogmatic and you'll see an improvement in code quality. ensure.

(The FAQs part is omitted here because it is consistent with the previous output. In order to avoid duplication, I will not repeat it here.)

The above is the detailed content of PHP Master | Introduction to the Law of Demeter. For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

AI Hentai Generator

AI Hentai Generator

Generate AI Hentai for free.

Hot Article

R.E.P.O. Energy Crystals Explained and What They Do (Yellow Crystal)
1 months ago By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Best Graphic Settings
1 months ago By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. How to Fix Audio if You Can't Hear Anyone
1 months ago By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Chat Commands and How to Use Them
1 months ago By 尊渡假赌尊渡假赌尊渡假赌

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

Explain JSON Web Tokens (JWT) and their use case in PHP APIs. Explain JSON Web Tokens (JWT) and their use case in PHP APIs. Apr 05, 2025 am 12:04 AM

JWT is an open standard based on JSON, used to securely transmit information between parties, mainly for identity authentication and information exchange. 1. JWT consists of three parts: Header, Payload and Signature. 2. The working principle of JWT includes three steps: generating JWT, verifying JWT and parsing Payload. 3. When using JWT for authentication in PHP, JWT can be generated and verified, and user role and permission information can be included in advanced usage. 4. Common errors include signature verification failure, token expiration, and payload oversized. Debugging skills include using debugging tools and logging. 5. Performance optimization and best practices include using appropriate signature algorithms, setting validity periods reasonably,

Explain the concept of late static binding in PHP. Explain the concept of late static binding in PHP. Mar 21, 2025 pm 01:33 PM

Article discusses late static binding (LSB) in PHP, introduced in PHP 5.3, allowing runtime resolution of static method calls for more flexible inheritance.Main issue: LSB vs. traditional polymorphism; LSB's practical applications and potential perfo

Describe the SOLID principles and how they apply to PHP development. Describe the SOLID principles and how they apply to PHP development. Apr 03, 2025 am 12:04 AM

The application of SOLID principle in PHP development includes: 1. Single responsibility principle (SRP): Each class is responsible for only one function. 2. Open and close principle (OCP): Changes are achieved through extension rather than modification. 3. Lisch's Substitution Principle (LSP): Subclasses can replace base classes without affecting program accuracy. 4. Interface isolation principle (ISP): Use fine-grained interfaces to avoid dependencies and unused methods. 5. Dependency inversion principle (DIP): High and low-level modules rely on abstraction and are implemented through dependency injection.

Framework Security Features: Protecting against vulnerabilities. Framework Security Features: Protecting against vulnerabilities. Mar 28, 2025 pm 05:11 PM

Article discusses essential security features in frameworks to protect against vulnerabilities, including input validation, authentication, and regular updates.

Customizing/Extending Frameworks: How to add custom functionality. Customizing/Extending Frameworks: How to add custom functionality. Mar 28, 2025 pm 05:12 PM

The article discusses adding custom functionality to frameworks, focusing on understanding architecture, identifying extension points, and best practices for integration and debugging.

How to send a POST request containing JSON data using PHP's cURL library? How to send a POST request containing JSON data using PHP's cURL library? Apr 01, 2025 pm 03:12 PM

Sending JSON data using PHP's cURL library In PHP development, it is often necessary to interact with external APIs. One of the common ways is to use cURL library to send POST�...

How to automatically set permissions of unixsocket after system restart? How to automatically set permissions of unixsocket after system restart? Mar 31, 2025 pm 11:54 PM

How to automatically set the permissions of unixsocket after the system restarts. Every time the system restarts, we need to execute the following command to modify the permissions of unixsocket: sudo...

See all articles