نویسنده: مهدی

  • اصول OOP به صورت خلاصه همراه با کد

    منبع: chatgpt

    اصول برنامه‌نویسی شیءگرا (OOP) چهار اصل اساسی دارد: Encapsulation, Abstraction, Inheritance, و Polymorphism. این اصول به توسعه‌ی نرم‌افزارهای پیچیده به روشی ساده‌تر و قابل مدیریت کمک می‌کنند.

    1. Encapsulation (کپسوله‌سازی)

    Encapsulation به معنای مخفی کردن جزئیات پیاده‌سازی یک شیء است و فقط متدها و ویژگی‌هایی که برای کار با شیء ضروری هستند، به بیرون نمایش داده می‌شوند. این کار با استفاده از دسترسی‌دهنده‌ها مانند private و public انجام می‌شود.

    مثال:

    class User {
        private $name;
    
        public function setName($name) {
            $this->name = $name;
        }
    
        public function getName() {
            return $this->name;
        }
    }
    
    $user = new User();
    $user->setName("John");
    echo $user->getName(); // خروجی: John
    

    در اینجا خاصیت $name مخفی شده و فقط از طریق متدهای setName و getName قابل دسترسی است.


    2. Abstraction (انتزاع)

    Abstraction به معنای مخفی کردن پیچیدگی‌های داخلی و نمایش فقط جزئیات ضروری است. این اصل از طریق تعریف اینترفیس‌ها یا کلاس‌های abstract پیاده‌سازی می‌شود.

    مثال:

    abstract class Animal {
        abstract public function sound();
    }
    
    class Dog extends Animal {
        public function sound() {
            return "Bark";
        }
    }
    
    class Cat extends Animal {
        public function sound() {
            return "Meow";
        }
    }
    
    $dog = new Dog();
    echo $dog->sound(); // خروجی: Bark
    

    در اینجا جزئیات صدای هر حیوان در کلاس‌های فرزند پیاده‌سازی شده و پیچیدگی‌های دیگر پنهان مانده است.


    3. Inheritance (وراثت)

    Inheritance به معنای استفاده مجدد از کد با به ارث بردن ویژگی‌ها و متدهای یک کلاس در کلاس دیگری است. این امر به کاهش تکرار کد کمک می‌کند.

    مثال:

    class Animal {
        public function eat() {
            return "Eating...";
        }
    }
    
    class Dog extends Animal {
        public function bark() {
            return "Barking...";
        }
    }
    
    $dog = new Dog();
    echo $dog->eat(); // خروجی: Eating...
    echo $dog->bark(); // خروجی: Barking...
    

    کلاس Dog ویژگی‌ها و رفتارهای کلاس Animal را به ارث برده است و می‌تواند از متد eat استفاده کند.


    4. Polymorphism (چندریختی)

    Polymorphism به این معناست که یک متد می‌تواند در کلاس‌های مختلف به روش‌های متفاوت پیاده‌سازی شود. این اصل امکان ایجاد انعطاف‌پذیری در کد را فراهم می‌کند.

    مثال:

    interface Shape {
        public function area();
    }
    
    class Circle implements Shape {
        private $radius;
    
        public function __construct($radius) {
            $this->radius = $radius;
        }
    
        public function area() {
            return pi() * pow($this->radius, 2);
        }
    }
    
    class Rectangle implements Shape {
        private $width, $height;
    
        public function __construct($width, $height) {
            $this->width = $width;
            $this->height = $height;
        }
    
        public function area() {
            return $this->width * $this->height;
        }
    }
    
    $circle = new Circle(5);
    echo $circle->area(); // خروجی: مساحت دایره
    
    $rectangle = new Rectangle(4, 5);
    echo $rectangle->area(); // خروجی: مساحت مستطیل
    

    هر کلاس پیاده‌سازی خود را از متد area دارد، که به صورت متفاوت برای دایره و مستطیل محاسبه می‌شود.


    این چهار اصل به توسعه‌ی نرم‌افزارهایی کمک می‌کنند که قابل نگهداری و توسعه‌پذیرتر هستند.

  • اصول SOLID به صورت کوتاه همراه نمونه کد

    منبع: chatgpt

    اصول SOLID یک مجموعه از پنج اصل طراحی شیءگرا است که به بهبود ساختار و انعطاف‌پذیری کد کمک می‌کند. این اصول به توسعه کدی منجر می‌شوند که قابل نگهداری، توسعه‌پذیر و تغییرپذیر باشد.

    1. Single Responsibility Principle (SRP)

    هر کلاس باید یک وظیفه‌ی واحد داشته باشد و تنها یک دلیل برای تغییر آن وجود داشته باشد.

    قبل از پیاده‌سازی SRP:

    class User {
        public function save($userData) {
            // ذخیره کاربر در پایگاه‌داده
        }
        
        public function sendEmail($emailContent) {
            // ارسال ایمیل به کاربر
        }
    }
    

    بعد از پیاده‌سازی SRP:

    class User {
        public function save($userData) {
            // ذخیره کاربر در پایگاه‌داده
        }
    }
    
    class EmailService {
        public function sendEmail($emailContent) {
            // ارسال ایمیل به کاربر
        }
    }
    

    در اینجا وظایف جدا شده‌اند. کلاس User فقط مسئول ذخیره‌سازی است و کلاس EmailService مسئول ارسال ایمیل.


    2. Open/Closed Principle (OCP)

    کلاس‌ها باید برای گسترش باز و برای تغییر بسته باشند. یعنی بتوانیم کلاس را توسعه دهیم بدون آن‌که نیاز به تغییر کلاس موجود باشد.

    قبل از پیاده‌سازی OCP:

    class Report {
        public function generatePDF() {
            // تولید گزارش PDF
        }
    
        public function generateExcel() {
            // تولید گزارش Excel
        }
    }
    

    بعد از پیاده‌سازی OCP:

    interface ReportGenerator {
        public function generate();
    }
    
    class PDFReport implements ReportGenerator {
        public function generate() {
            // تولید گزارش PDF
        }
    }
    
    class ExcelReport implements ReportGenerator {
        public function generate() {
            // تولید گزارش Excel
        }
    }
    

    در اینجا اگر نوع جدیدی از گزارش نیاز باشد، می‌توانیم یک کلاس جدید ایجاد کنیم بدون تغییر کلاس‌های قبلی.


    3. Liskov Substitution Principle (LSP)

    کلاس‌های مشتق‌شده باید بتوانند جایگزین کلاس‌های پایه شوند بدون اینکه رفتار برنامه تغییر کند.

    قبل از پیاده‌سازی LSP:

    class Bird {
        public function fly() {
            // پرواز
        }
    }
    
    class Penguin extends Bird {
        public function fly() {
            throw new Exception("پنگوئن نمی‌تواند پرواز کند!");
        }
    }
    

    بعد از پیاده‌سازی LSP:

    class Bird {
        // کلاس پایه بدون متد پرواز
    }
    
    class FlyingBird extends Bird {
        public function fly() {
            // پرواز
        }
    }
    
    class Penguin extends Bird {
        // بدون متد fly زیرا پنگوئن پرواز نمی‌کند
    }
    

    در اینجا پنگوئن جایگزین کلاس پایه نمی‌شود زیرا ویژگی مشترک پرواز را ندارد.


    4. Interface Segregation Principle (ISP)

    کلاس‌ها نباید مجبور شوند متدهایی را که نیاز ندارند پیاده‌سازی کنند. اینترفیس‌ها باید کوچک و مختص به نیاز باشند.

    قبل از پیاده‌سازی ISP:

    interface Worker {
        public function work();
        public function eat();
    }
    
    class HumanWorker implements Worker {
        public function work() {
            // کار کردن
        }
    
        public function eat() {
            // غذا خوردن
        }
    }
    
    class RobotWorker implements Worker {
        public function work() {
            // کار کردن
        }
    
        public function eat() {
            // ربات غذا نمی‌خورد!
        }
    }
    

    بعد از پیاده‌سازی ISP:

    interface Workable {
        public function work();
    }
    
    interface Eatable {
        public function eat();
    }
    
    class HumanWorker implements Workable, Eatable {
        public function work() {
            // کار کردن
        }
    
        public function eat() {
            // غذا خوردن
        }
    }
    
    class RobotWorker implements Workable {
        public function work() {
            // کار کردن
        }
    }
    

    در اینجا متدهای اضافی از اینترفیس اصلی جدا شده‌اند.


    5. Dependency Inversion Principle (DIP)

    ماژول‌های سطح بالا نباید به ماژول‌های سطح پایین وابسته باشند. هر دو باید به اینترفیس‌ها وابسته باشند.

    قبل از پیاده‌سازی DIP:

    class MySQLConnection {
        public function connect() {
            // اتصال به MySQL
        }
    }
    
    class User {
        private $db;
    
        public function __construct() {
            $this->db = new MySQLConnection();
        }
    
        public function getUserData() {
            $this->db->connect();
            // دریافت اطلاعات کاربر
        }
    }
    

    بعد از پیاده‌سازی DIP:

    interface DBConnection {
        public function connect();
    }
    
    class MySQLConnection implements DBConnection {
        public function connect() {
            // اتصال به MySQL
        }
    }
    
    class User {
        private $db;
    
        public function __construct(DBConnection $db) {
            $this->db = $db;
        }
    
        public function getUserData() {
            $this->db->connect();
            // دریافت اطلاعات کاربر
        }
    }
    

    در اینجا کلاس User به اینترفیس DBConnection وابسته است، نه به یک کلاس خاص مانند MySQLConnection.

  • کجا از interface و کجا از abstract کلاس استفاده میکنیم؟

    منبع: chatgpt

    انتخاب بین Interface و Abstract Class بستگی به نیازهای پروژه و شرایط خاصی دارد که باید به آن توجه شود. این دو مفهوم در PHP به منظور تعریف یک قرارداد یا یک ساختار پایه برای کلاس‌ها استفاده می‌شوند، اما کاربردهای متفاوتی دارند. در زیر توضیح داده می‌شود که چه زمانی از اینترفیس و چه زمانی از کلاس انتزاعی استفاده کنیم:

    زمانی که از Interface استفاده می‌کنیم:

    1. قرارداد بدون پیاده‌سازی: وقتی می‌خواهید صرفاً یک قرارداد تعریف کنید بدون اینکه پیاده‌سازی‌ای ارائه دهید. اینترفیس‌ها هیچ پیاده‌سازی در متدهای خود ندارند و کلاس‌ها موظف هستند تمام متدهای تعریف‌شده در اینترفیس را پیاده‌سازی کنند.
    2. پیاده‌سازی چندگانه: PHP از چندگانگی در اینترفیس‌ها پشتیبانی می‌کند. یعنی یک کلاس می‌تواند چندین اینترفیس را پیاده‌سازی کند، اما نمی‌تواند از چندین کلاس به ارث ببرد. بنابراین، وقتی به چندین قرارداد نیاز دارید که کلاس‌ها باید آنها را پیاده‌سازی کنند، از اینترفیس استفاده کنید.
    3. عدم وجود منطق مشترک: اگر نیازی به ارائه منطق مشترک بین کلاس‌ها ندارید و فقط می‌خواهید مشخص کنید که کلاس‌های مختلف باید متدهای خاصی را داشته باشند، اینترفیس گزینه بهتری است.
    4. تغییرات کمتر: اگر نیاز دارید که قرارداد کلی‌ای داشته باشید که احتمالاً در آینده تغییر نکند، از اینترفیس استفاده کنید. چرا که با تغییر دادن یک اینترفیس ممکن است به کلاس‌های متعددی آسیب بزنید که آن را پیاده‌سازی کرده‌اند.

    مثال برای اینترفیس:

    interface Logger {
        public function log($message);
    }
    
    class FileLogger implements Logger {
        public function log($message) {
            // پیاده‌سازی برای نوشتن در فایل
            file_put_contents('log.txt', $message, FILE_APPEND);
        }
    }
    
    class DatabaseLogger implements Logger {
        public function log($message) {
            // پیاده‌سازی برای ذخیره‌سازی در پایگاه‌داده
        }
    }
    

    زمانی که از Abstract Class استفاده می‌کنیم:

    1. پیاده‌سازی جزئی و منطق مشترک: اگر می‌خواهید متدهایی را در کلاس پایه پیاده‌سازی کنید که تمامی کلاس‌های فرزند از آنها استفاده کنند، کلاس انتزاعی مناسب است. کلاس‌های انتزاعی می‌توانند متدهای پیاده‌سازی‌شده داشته باشند که نیازی نیست در کلاس‌های فرزند مجدداً تعریف شوند.
    2. ارث‌بری از یک منبع مشترک: اگر یک رابطه «is-a» بین کلاس‌ها وجود دارد و کلاس‌های فرزند باید ویژگی‌ها و رفتارهای مشترکی از کلاس والد به ارث ببرند، از کلاس انتزاعی استفاده کنید. برای مثال، اگر تمامی موجودات (مثل مستطیل، دایره، و …) باید از کلاس شکل (Shape) ارث ببرند و برخی از متدها و ویژگی‌ها مشترک باشد.
    3. نیاز به متدهای انتزاعی و پیاده‌سازی‌شده: وقتی برخی از متدها باید در کلاس والد پیاده‌سازی شوند و برخی دیگر فقط تعریف شوند (و توسط کلاس‌های فرزند پیاده‌سازی شوند)، کلاس انتزاعی مناسب است.
    4. یکپارچگی: کلاس‌های انتزاعی به شما اجازه می‌دهند که کلاس‌های فرزند را به یک ساختار پایه ملزم کنید و در عین حال کدی را بین کلاس‌ها به اشتراک بگذارید. بنابراین اگر هم نیاز به اشتراک‌گذاری کد بین کلاس‌ها دارید و هم می‌خواهید برخی از متدها انتزاعی باشند، از کلاس انتزاعی استفاده کنید.

    مثال برای کلاس انتزاعی:

    abstract class Animal {
        protected $name;
    
        public function __construct($name) {
            $this->name = $name;
        }
    
        // متد انتزاعی
        abstract public function makeSound();
    
        // متد معمولی
        public function getName() {
            return $this->name;
        }
    }
    
    class Dog extends Animal {
        public function makeSound() {
            return "Bark";
        }
    }
    
    class Cat extends Animal {
        public function makeSound() {
            return "Meow";
        }
    }
    

    خلاصه تفاوت‌ها:

    • Interface:
      • فقط شامل تعریف متدهاست (بدون پیاده‌سازی).
      • کلاس‌ها می‌توانند چندین اینترفیس را پیاده‌سازی کنند.
      • مناسب برای زمانی که می‌خواهید قراردادی بدون هیچ منطق اجرایی تعریف کنید.
    • Abstract Class:
      • می‌تواند هم متدهای تعریف‌شده و هم متدهای پیاده‌سازی‌شده داشته باشد.
      • کلاس‌ها فقط از یک کلاس انتزاعی ارث‌بری می‌کنند.
      • مناسب برای زمانی که می‌خواهید منطق مشترکی را بین کلاس‌های فرزند به اشتراک بگذارید.

    در نتیجه، اگر به اشتراک‌گذاری کد و تعریف یک پایه برای کلاس‌ها نیاز دارید، از کلاس انتزاعی استفاده کنید. اما اگر به چندگانگی در پیاده‌سازی و تعریف یک قرارداد محض بدون پیاده‌سازی نیاز دارید، از اینترفیس استفاده کنید.