{"id":20881542,"url":"https://github.com/nahidulhasan/solid-principles","last_synced_at":"2025-04-07T17:07:44.952Z","repository":{"id":41899646,"uuid":"113126422","full_name":"nahidulhasan/solid-principles","owner":"nahidulhasan","description":"SOLID Principles - simple and easy explanation","archived":false,"fork":false,"pushed_at":"2022-07-11T03:11:59.000Z","size":64,"stargazers_count":300,"open_issues_count":1,"forks_count":82,"subscribers_count":15,"default_branch":"master","last_synced_at":"2025-03-31T16:14:18.287Z","etag":null,"topics":["code-standards","object-oriented-design","software-engineering","solid","solid-principles"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nahidulhasan.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-12-05T03:20:40.000Z","updated_at":"2025-03-12T22:17:19.000Z","dependencies_parsed_at":"2022-09-19T02:01:27.743Z","dependency_job_id":null,"html_url":"https://github.com/nahidulhasan/solid-principles","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nahidulhasan%2Fsolid-principles","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nahidulhasan%2Fsolid-principles/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nahidulhasan%2Fsolid-principles/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nahidulhasan%2Fsolid-principles/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nahidulhasan","download_url":"https://codeload.github.com/nahidulhasan/solid-principles/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247694875,"owners_count":20980733,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["code-standards","object-oriented-design","software-engineering","solid","solid-principles"],"created_at":"2024-11-18T07:25:15.679Z","updated_at":"2025-04-07T17:07:44.934Z","avatar_url":"https://github.com/nahidulhasan.png","language":"PHP","readme":"# SOLID Principles - simple and easy explanation\n\nSOLID Principles is a coding standard that all developers should have a clear \nconcept for developing software in a proper way to avoid a bad design. \nIt was promoted by Robert C Martin and is used across the object-oriented design spectrum.\nWhen applied properly it makes your code more extendable, logical and easier to read.\n\nWhen the developer builds a software follow the bad design, the code can become \ninflexible and more brittle, small changes in the software can result in bugs. \nFor these reasons, we should follow SOLID Principles.\n\nIt takes some time to understand, but if you write code following the principles \nit will improve code quality and will help to understand the most well-designed software.\n\nTo understand SOLID principles, you have to know the use of the interface clearly.\nIf your concept is not clear about interface then you can read this [doc](https://medium.com/@NahidulHasan/understanding-use-of-interface-and-abstract-class-9a82f5f15837).\n\nI'm going to try to explain SOLID Principles in simplest way so that it's easy \nfor beginners to understand. Let's go through each principle one by one:\n\n\n## Single Responsibility Principle :\n\n\u003eA class should have one, and only one, reason to change.\n\nOne class should only serve one purpose, this does not imply that each class should have only one method but they should all relate directly to the responsibility of the class. All the methods and properties should all work towards the same goal. When a class serves multiple purposes or responsibility then it should be made into a new class.\n\nPlease look at the following code :\n\n```php\nnamespace Demo;\nuse DB;\nclass OrdersReport\n{\n    public function getOrdersInfo($startDate, $endDate)\n    {\n        $orders = $this-\u003equeryDBForOrders($startDate, $endDate);\n        return $this-\u003eformat($orders);\n    }\n    protected function queryDBForOrders($startDate, $endDate)\n    {   // If we would update our persistence layer in the future,\n        // we would have to do changes here too. \u003c=\u003e reason to change!\n        return DB::table('orders')-\u003ewhereBetween('created_at', [$startDate, $endDate])-\u003eget();\n    }\n    protected function format($orders)\n    {   // If we changed the way we want to format the output,\n        // we would have to make changes here. \u003c=\u003e reason to change!\n        return '\u003ch1\u003eOrders: ' . $orders . '\u003c/h1\u003e';\n    }\n}\n```\n\nAbove class violates single responsibility principle. Why should this class retrieve data from database? It is related to the \npersistence layer. The persistence layer deals with persisting (storing and retrieving) data from a data store (such as a database, for example).So it is not the responsibility of this class.\n\nNext method format is also not the responsibility of this class. Because we may need different format data such as XML, JSON, HTML etc.\n\nSo finally the refactored code will be described as below :\n\n```php\nnamespace Report;\nuse Report\\Repositories\\OrdersRepository;\nclass OrdersReport\n{\n    protected $repo;\n    protected $formatter;\n    public function __construct(OrdersRepository $repo, OrdersOutPutInterface $formatter)\n    {\n        $this-\u003erepo = $repo;\n        $this-\u003eformatter = $formatter;\n    }\n    public function getOrdersInfo($startDate, $endDate)\n    {\n        $orders = $this-\u003erepo-\u003egetOrdersWithDate($startDate, $endDate);\n        return $this-\u003eformatter-\u003eoutput($orders);\n    }\n}\n\nnamespace Report;\ninterface OrdersOutPutInterface\n{\n\tpublic function output($orders);\n}\nnamespace Report;\nclass HtmlOutput implements OrdersOutPutInterface\n{\n    public function output($orders)\n    {\n        return '\u003ch1\u003eOrders: ' . $orders . '\u003c/h1\u003e';\n    }\n}\n\nnamespace Report\\Repositories;\nuse DB;\nclass OrdersRepository\n{\n    public function getOrdersWithDate($startDate, $endDate)\n    {\n        return DB::table('orders')-\u003ewhereBetween('created_at', [$startDate, $endDate])-\u003eget();\n    }\n}\n```\n\n## Open-closed Principle :\n\n\u003eEntities should be open for extension, but closed for modification.\n\nSoftware entities (classes, modules, functions, etc.) be extendable without actually changing the contents of the class you're extending. If we could follow this principle strongly enough, it is possible to then modify the behavior of our code without ever touching a piece of original code.\n\nPlease look at the following code :\n\n```php\nclass Rectangle\n{\n    public $width;\n    public $height;\n    public function __construct($width, $height)\n    {\n        $this-\u003ewidth = $width;\n        $this-\u003eheight = $height;\n    }\n}\n\nclass Circle\n{\n    public $radius;\n    public function __construct($radius)\n    {\n        $this-\u003eradius = $radius;\n    }\n}\n\nclass CostManager\n{\n    public function calculate($shape)\n    {\n        $costPerUnit = 1.5;\n        if ($shape instanceof Rectangle) {\n            $area = $shape-\u003ewidth * $shape-\u003eheight;\n        } else {\n            $area = $shape-\u003eradius * $shape-\u003eradius * pi();\n        }\n        \n        return $costPerUnit * $area;\n    }\n}\n$circle = new Circle(5);\n$rect = new Rectangle(8,5);\n$obj = new CostManager();\necho $obj-\u003ecalculate($circle);\n```\n\nIf we want to calculate the area for Square we have to modify calculate method in\n CostManager class. It breaks the open-closed principle. According to this principle, \n we can not modify we can extend. So How we can fix this problem, please see the following code :\n\n\n```php\ninterface AreaInterface\n{\n    public  function calculateArea();\n}\n\nclass Rectangle implements AreaInterface\n{\n    public $width;\n    public $height;\n    public function __construct($width, $height)\n    {\n        $this-\u003ewidth = $width;\n        $this-\u003eheight = $height;\n    }\n    public  function calculateArea(){\n        $area = $this-\u003eheight *  $this-\u003ewidth;\n        return $area;\n    }\n}\n  \nclass Circle implements  AreaInterface\n{\n    public  $radius;\n    public function __construct($radius)\n    {\n        $this-\u003eradius = $radius;\n    }\n    public  function calculateArea(){\n        $area = $this-\u003eradius * $this-\u003eradius * pi();\n        return $area;\n    }\n}\n\nclass CostManager\n{\n    public function calculate(AreaInterface $shape)\n    {\n        $costPerUnit = 1.5;\n        $totalCost = $costPerUnit * $shape-\u003ecalculateArea();\n        return $totalCost;\n    }\n}\n$circle = new Circle(5);\n$obj = new CostManager();\necho $obj-\u003ecalculate($circle);\n```\n\nNow we can find square's area without modifying CostManager class.\n\n\n## Liskov Substitution Principle :\n\nThe Liskov Substitution principle was introduced by Barbara Liskov in her conference \nkeynote \"Data abstraction\" in 1987.Barbara Liskov and Jeannette Wing formulated \nthe principle succinctly in a 1994 paper as follows:\n\n\u003eLet φ(x) be a property provable about objects x of type T. Then φ(y) should be true for objects y of type S where S is a subtype of T.\n\n\nThe human-readable version repeats pretty much everything that Bertrand Meyer \nalready has said, but it relies totally on a type-system:\n\n\n\u003e1. Preconditions cannot be strengthened in a subtype.\n\u003e2. Postconditions cannot be weakened in a subtype.\n\u003e3. Invariants of the supertype must be preserved in a subtype.\n\nRobert Martin made the definition sound more smoothly and concisely in 1996 :\n\n\u003eFunctions that use pointers of references to base classes must be able to use objects of derived classes without knowing it.\n\nOr simply : Subclass/derived class should be substitutable for their base/parent class.\n\nIt states that any implementation of an abstraction (interface) should be \nsubstitutable in any place that the abstraction is accepted. Basically, \nit takes care that while coding using interfaces in our code, \nwe not only have a contract of input that the interface receives but also the \noutput returned by different Classes implementing that interface; they should be \nof the same type.\n\nA code snippet to show how violates LSP and how we can fix it :\n\n```php\ninterface LessonRepositoryInterface\n{\n    /**\n     * Fetch all records.\n     *\n     * @return array\n     */\n    public function getAll();\n}\n\nclass FileLessonRepository implements LessonRepositoryInterface\n{\n    public function getAll()\n    {\n        // return through file system\n        return [];\n    }\n}\n\nclass DbLessonRepository implements LessonRepositoryInterface\n{\n    public function getAll()\n    {\n        /*\n            Violates LSP because:\n              - the return type is different\n              - the consumer of this subclass and FileLessonRepository won't work identically\n         */\n        // return Lesson::all();\n        // to fix this\n        return Lesson::all()-\u003etoArray();\n    }\n}\n```\n\n\n## Interface Segregation Principle :\n\n\u003eA Client should not be forced to implement an interface that it doesn't use.\n\nThis rule means that we should break our interfaces in many smaller ones, \nso they better satisfy the exact needs of our clients.\n\nSimilar to the Single Responsibility Principle, the goal of the Interface Segregation Principle is to minimize the side consequences and repetition by dividing the software into multiple, independent parts.\n\nLet’s see an example :\n\n```php\ninterface workerInterface\n{\n    public  function work();\n    public  function  sleep();\n}\n\nclass HumanWorker implements workerInterface\n{\n    public  function work()\n    {\n        var_dump('works');\n    }\n\n    public  function  sleep()\n    {\n        var_dump('sleep');\n    }\n\n}\n\nclass RobotWorker implements workerInterface\n{\n    public  function work()\n    {\n        var_dump('works');\n    }\n\n    public  function sleep()\n    {\n        // No need\n    }\n}\n```\n\nIn the above code, RobotWorker no needs sleep, but the class has to implement the sleep method because we know that all methods are abstract in the interface. It breaks the Interface segregation law. How we can fix it please see the following code :\n\n```php\ninterface WorkAbleInterface\n{\n    public  function work();\n}\n\ninterface SleepAbleInterface\n{\n    public  function  sleep();\n}\n\nclass HumanWorker implements WorkAbleInterface, SleepAbleInterface\n{\n    public  function work()\n    {\n        var_dump('works');\n    }\n    public  function  sleep()\n    {\n        var_dump('sleep');\n    }\n}\n\nclass RobotWorker implements WorkAbleInterface\n{\n    public  function work()\n    {\n        var_dump('works');\n    }\n}\n```\n\n\n## Dependency Inversion Principle :\n\n\u003e High-level modules should not depend on low-level modules. Both should depend on abstractions.\n\n\u003e Abstractions should not depend on details. Details should depend on abstractions.\n\nOr simply : Depend on Abstractions not on concretions\n\nBy applying the Dependency Inversion the modules can be easily changed by other modules just \nchanging the dependency module and High-level module will not be affected by any changes to \nthe Low-level module.\n\nPlease look at the following code :\n\n```php\nclass MySQLConnection\n{\n   /**\n    * db connection\n    */\n    public function connect()\n    {\n      var_dump('MYSQL Connection');\n    }\n}\n\nclass PasswordReminder\n{    \n    /**\n     * @var MySQLConnection\n     */\n     private $dbConnection;\n     \n     public function __construct(MySQLConnection $dbConnection) \n    {\n      $this-\u003edbConnection = $dbConnection;\n    }\n}\n```\n\nThere's a common misunderstanding that dependency inversion is simply another way to say dependency injection. However, the two are not the same.\n\nIn the above code In spite of Injecting MySQLConnection class in PasswordReminder class but it depends on MySQLConnection.\n\nHigh-level module PasswordReminder should not depend on low-level module MySQLConnection.\n\nIf we want to change the connection from MySQLConnection to MongoDBConnection, we have to change hard-coded constructor injection in PasswordReminder class.\n\nPasswordReminder class should depend upon on Abstractions, not on concretions. But How can we do it? Please see the following example :\n\n```php\ninterface ConnectionInterface\n{\n   public function connect();\n}\n\nclass DbConnection implements ConnectionInterface\n{\n   /**\n    * db connection\n    */\n    public function connect()\n    {\n     var_dump('MYSQL Connection');\n    }\n}\n\nclass PasswordReminder\n{\n   /**\n    * @var DBConnection\n    */\n    private $dbConnection;\n    \n    public function __construct(ConnectionInterface $dbConnection)\n    {\n      $this-\u003edbConnection = $dbConnection;\n    }\n}\n```\n\nIn the above code, we want to change the connection from MySQLConnection to MongoDBConnection, we no need to change constructor injection in PasswordReminder class. Because here PasswordReminder class depends upon on Abstractions, not on concretions.\n\nThe Publication Better Programming has published this article. if you’d like to read from the Better Programming blog site, please go to this [link](https://medium.com/better-programming/solid-principles-simple-and-easy-explanation-f57d86c47a7f).\n\nThanks for reading.\n\n\n### License\n\nOpen-sourced software licensed under the [MIT license](http://opensource.org/licenses/MIT)\n\n\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnahidulhasan%2Fsolid-principles","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnahidulhasan%2Fsolid-principles","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnahidulhasan%2Fsolid-principles/lists"}