Fellipe Sanches' website

Author: F. Sanches

  • Factory Method

    Factory method provides an interface for creating objects in a superclass,
    allows subclasses to decide wich class to instantiate.

    //Concrete or direct instantiation. Client code with no factory.
    $myEmailNotification = new emailNotification;
    $mySmsNotification = new smsNotification;
    
    //Abstracted object creation. Client code with a factory-based instantiation.
    $myEmailNotification = NotificationFactory::create('email');
    $mySmsNotification = NotificationFactory::create('sms');

    Factories allow client code to operate on generalizations, this is called coding to an interface, not an implementation and is a fundamental principle in object-oriented programming that promotes flexibility, maintainability, and testability in software design. 

    It means that client code should interact with a system through an abstract interface (or abstract class) rather than create the object directly, without worrying about the details of object creation. 

    <?php
    // interface defines a contract — all notification classes must have a send() method.
    interface Notification
    {
        public function send(string $to, string $message): void;
    }
    
    // Concrete implementations of different notification types
    
    class EmailNotification implements Notification
    {
        public function send(string $to, string $message): void
        {
            echo "Sending EMAIL to {$to}: {$message}" . PHP_EOL;
        }
    }
    
    class SmsNotification implements Notification
    {
        public function send(string $to, string $message): void
        {
            echo "Sending SMS to {$to}: {$message}" . PHP_EOL;
        }
    }
    
    class PushNotification implements Notification
    {
        public function send(string $to, string $message): void
        {
            echo "Sending PUSH notification to {$to}: {$message}" . PHP_EOL;
        }
    }
    
    // The Factory class — decides which notification to create
    class NotificationFactory
    {
        public static function create(string $type): Notification
        {
            return match (strtolower($type)) {
                'email' => new EmailNotification(),
                'sms'   => new SmsNotification(),
                'push'  => new PushNotification(),
                default => throw new InvalidArgumentException("Unknown notification type: {$type}")
            };
        }
    }
    
    // Usage exemple
    try {
        $notification = NotificationFactory::create('email');
        $notification->send('user@example.com', 'Your order has been shipped.');
    
        $notification = NotificationFactory::create('sms');
        $notification->send('+5547999999999', 'Your code is 123456.');
    
        $notification = NotificationFactory::create('push');
        $notification->send('User123', 'You have a new message.');
    } catch (Exception $e) {
        echo "Error: " . $e->getMessage();
    }

  • Singleton

    Singleton – ensure that a class has only one instance,
    while providing a global access to this instance.

    <?php
    
    class Logger
    {
        private static ?Logger $uniqueInstance = null;
        private array $logs = [];
    
        // prevents direct instantiation
        private function __construct() {}
    
        // no one outside the class can duplicate the instance.
        private function __clone() {}
    
        /* __wakeup must be public (by PHP’s design), 
        since it’s automatically called during unserialize().*/
        public function __wakeup()
        {
            throw new \Exception("Cannot unserialize a singleton.");
        }
    
        /* Lazy construction / initialization - returns the single instance 
        of this class*/
        public static function getInstance(): Logger
        {
            if (self::$uniqueInstance === null) {
                self::$uniqueInstance = new Logger();
            }
            return self::$uniqueInstance;
        }
    
        // Methods
        public function addLog(string $message): void
        {
            $this->logs[] = $message;
        }
    
        public function showLogs(): void
        {
            foreach ($this->logs as $log) {
                echo $log . PHP_EOL;
            }
        }
    }
    
    // Usage exemple
    $logger1 = Logger::getInstance();
    $logger2 = Logger::getInstance();
    
    $logger1->addLog("First log entry.");
    $logger2->addLog("Second log entry.");
    
    $logger1->showLogs();
    
    //Checking the solid proof...
    
    if ($logger1 === $logger2) {
        echo "Same instance" . PHP_EOL;
    } else {
        echo "Different instances" . PHP_EOL;
    }
    
    echo "Logger1 ID: " . spl_object_id($logger1) . PHP_EOL;
    echo "Logger2 ID: " . spl_object_id($logger2) . PHP_EOL;
    
    /*
    Output:
    
    First log entry.
    Second log entry.
    Same instance
    Logger1 ID: 1
    Logger2 ID: 1
    */

    The code above works perfectly for our purpose, but it’s not inheritance-safe, meaning it always creates a Logger instance, even if called from a subclass. Therefore:

    class FileLogger extends Logger {}
    FileLogger::getInstance(); //still returns the instance of Logger, not a instance of FileLogger

    If we want that each subclass has its own singleton, we must change this behavior by modifying the getInstance() method, like this:

    public static function getInstance(): Logger 
    {
        $className = static::class;
        if (!isset(self::$uniqueInstance[$className])) {
            self::$uniqueInstance[$className] = new static();
        }
        return self::$uniqueInstance[$className];
    }

    Comparison:

    FeatureVersion
    self
    Version
    static::class
    Supports inheritance❌ No✅ Yes
    Each subclass has its own singleton❌ No✅ Yes
    Refers to who?Refer to the class where the code was originally defined.Refer to the class that was actually called at runtime.
    When use?You want a single, strict singleton for only the original class.You expect inheritance or extensions of your original class.

    When Singleton pattern is useful?

    • Logger – Keep a single instance that writes all logs from different parts of the app.
    • Configuration Manager – Store settings (like API keys, database credentials, etc.) in one place.
    • Database Connection – Maintain one connection to the database.
    • Cache Manager – Keep a single cache handler (like Redis, Memcached, or file cache)
    • Session Manager – Handle user session data globally.
    • Event Dispatcher or Queue Manager – Centralize how events or background tasks are managed.

  • All terms of Object-oriented programming (OOP)

    Four Pillars of Object-oriented programming

    A trick a trick I invented to memorize the 4 pillars of OOP:

    P Polymorphism
    I Inheritance
    L
    L
    A Abstraction
    R

    Where is the E for Encapsulation? It was encapsulated! (just kidding).

    Design Principles

    D Decomposition
    E Encapsulation
    S
    I
    G Generalization
    N

    Where is the A for Abstraction? It was omitted due to a poor abstraction.

  • Classes: comparison of the “is-a” vs “has-a” relationship

    Composition (“has-a”) or Inheritance (“is-a” ), how to choose the corret relationship?

    First of all, you have to know that, in the scenario of modern object-oriented design principles, there is a strong preference for Composition over Inheritance as better design principle.

    This happens because, once you extend a class (inherit from it), you become bound to its structure and behavior, making it difficult to change it later. Let’s see a brief about each relantionship below.

    “Is-a” → Inheritance
    Used when one class is a type of another class.

    Example:
    Car is-a Vehicleclass Car extends Vehicle


    “Has-a” → Composition / Aggregation
    Used when one class contains or uses another class.

    Example:
    Car has-a Engineclass Car { private Engine $engine; }


    How to choose?

    • Use is-a when you want to reuse behavior and the relationship is naturally hierarchical.
    • Use has-a when you want flexibility, replaceable components, and loose coupling.

    Code exemples

    IS-A (Inheritance) – Use when a class is a type of another class.

    <?php
    
    class Vehicle
    {
        public function move()
        {
            echo "The vehicle is moving\n";
        }
    }
    
    class Car extends Vehicle   // Car *is-a* Vehicle
    {
    }
    
    $car = new Car();
    $car->move(); // inherited

    HAS-A (Composition) – Use when a class contains another class.

    <?php
    
    class Engine
    {
        public function start()
        {
            echo "Engine started\n";
        }
    }
    
    class Car
    {
        private Engine $engine; // Car *has-a* Engine
    
        public function __construct()
        {
            $this->engine = new Engine();
        }
    
        public function turnOn()
        {
            $this->engine->start();
        }
    }
    
    $car = new Car();
    $car->turnOn();

    Now, let’s improve the HAS-A, with a more flexible and modern example using interfaces + dependency injection, allowing a car to use diesel, gasoline, ethanol (alcohol), electric, or any other engine.

    //Interface
    <?php
    
    interface EngineInterface
    {
        public function start(): void;
    }
    
    //Different engines
    class DieselEngine implements EngineInterface
    {
        public function start(): void
        {
            echo "Diesel engine roaring...\n";
        }
    }
    
    class GasEngine implements EngineInterface
    {
        public function start(): void
        {
            echo "Gas engine starting...\n";
        }
    }
    
    class AlcoholEngine implements EngineInterface
    {
        public function start(): void
        {
            echo "Alcohol engine warming up...\n";
        }
    }
    
    //Car uses composition + dependency injection
    class Car
    {
        private EngineInterface $engine; // Car *has-a* Engine
    
        public function __construct(EngineInterface $engine)
        {
            $this->engine = $engine;
        }
    
        public function turnOn(): void
        {
            $this->engine->start();
        }
    }
    
    //Using it...
    $RangeRover = new Car(new DieselEngine());
    $RangeRover->turnOn();
    
    $Civic = new Car(new GasEngine());
    $Civic->turnOn();
    
    $Fiat147 = new Car(new AlcoholEngine());
    $Fiat147->turnOn();
    
    /*
    Output:
    
    Diesel engine roaring...
    Gas engine starting...
    Alcohol engine warming up...
    */
  • Liskov Substitution Principle

    First of all, Liskov was a woman, okay? That being said, let’s continue; In object-oriented programming, classes are user-defined data structures that group related attributes and methods, allowing developers to model real-world objects or abstract ideas.

    These classes can relate to one another through inheritance, a key concept that lets subclasses acquire its properties and behaviors.

    Inheritance promotes code reuse and specialization, but it must be used carefully. The Liskov Substitution Principle (LSP) provides guidance: if a subclass is a subtype of a base class, it should be able to replace it without altering the program’s behavior.

    To satisfy the LSP, subclasses must not change the meaning of methods, weaken postconditions, or modify immutable attributes from the base class. They can, however, extend functionality or improve performance, as long as the expected results remain consistent.

    In short, inheritance should maintain consistency between base and derived classes, ensuring that substituting one for the other keeps the system stable and predictable.

  • Open/Closed Principle

    All design patterns follow a basic set of design principles, which address issues such as flexibility and reusability.

    One of these principles is called the Open/Closed Principle.

    The Open/Closed Principle is a concept that helps keep a system stable by closing classes to changes and allowing the system to open for extension through the use of inheritance or interfaces.

    You should consider a class as being “closed” to changes once it has been tested to be functioning properly.

    The class should be behaving as you would expect it to behave. All the attributes and behaviors are encapsulated and proven to be stable within your system.

    The class, or any instance of the class, should not stop your system from running or do any harm to it.

    The closed portion of the principle doesn’t mean that you can’t go back to a class to make changes to it during development. So, what do you do if you need to add more features to extend your systems? There are two different ways to do it.

    The first way is through inheritance of a superclass. The idea is that when you want to add more attributes and behaviors to a class that is considered closed, you can simply use inheritance to extend it. Now let’s an exemple that will clarify this concept:

    <?php
    // --- Base class (tested and considered stable) --- //
    class PaymentProcessor {
        public function process(float $amount): void {
            echo "Processing a payment of $$amount...\n";
        }
    }
    
    // --- Open for extension: Inheritance --- //
    // Instead of changing the original PaymentProcessor class,
    // we extend it to add new behavior (e.g., logging).
    class LoggedPaymentProcessor extends PaymentProcessor {
        public function process(float $amount): void {
            echo "[LOG] About to process payment.\n";
            parent::process($amount);
            echo "[LOG] Payment successfully processed.\n";
        }
    }
    
    // --- Closed for modification: Final class --- //
    // Once a class is stable and we don’t want further extension,
    // we can mark it as 'final' to prevent inheritance.
    final class SecurePaymentProcessor extends PaymentProcessor {
        public function process(float $amount): void {
            echo "Processing a secure payment of $$amount...\n";
        }
    }
    
    // --- Usage examples --- //
    echo "== Open for extension ==\n";
    $loggedProcessor = new LoggedPaymentProcessor();
    $loggedProcessor->process(100);
    
    echo "\n== Closed for extension ==\n";
    $secureProcessor = new SecurePaymentProcessor();
    $secureProcessor->process(200);

    This way helps preserve the integrity of the superclass but lets you still have extra features via subclasses.

    You also may reach a point where you no longer want a class to be extendable, in which case you can declare a class to be final, which will prevent further inheritance.

    The second way, a class can be considered open to extension, is if the class is abstract and enforces the Open/Closed Principle through polymorphism. Let see it below:

    <?php
    // --- Abstract class defining the base structure --- //
    abstract class PaymentProcessor {
        // Abstract method: subclasses must define this
        abstract public function process(float $amount): void;
    
        // Concrete method: shared logic
        protected function log(string $message): void {
            echo "[LOG] $message\n";
        }
    }
    
    // --- Concrete subclass 1 --- //
    class CreditCardProcessor extends PaymentProcessor {
        public function process(float $amount): void {
            $this->log("Processing credit card payment of $$amount...");
            echo "Credit card payment completed.\n";
        }
    }
    
    // --- Concrete subclass 2 --- //
    class PaypalProcessor extends PaymentProcessor {
        public function process(float $amount): void {
            $this->log("Processing PayPal payment of $$amount...");
            echo "PayPal payment completed.\n";
        }
    }
    
    // --- Usage --- //
    $processors = [
        new CreditCardProcessor(),
        new PaypalProcessor()
    ];
    
    foreach ($processors as $processor) {
        $processor->process(150);
    }

    An abstract class can declare abstract methods with just the method signatures. Each concrete subclass must provide their own implementation of these methods. The methods in the abstract superclass are preserved, and you can extend your system by providing different implementations for each method.

    This can be useful for behaviors that can be accomplished in different ways, like sorting and searching. You can also use an interface to enable polymorphism, but in this case you won’t be able to define a common set of attributes.

    The Open/Closed Principle is used to keep the stable parts of your system separate from the varying parts, it’s a principle you should use when designing and building your software solutions.

    Now you know how to add more features to your system without disrupting something that works. Use it!

  • Dicas para montar um layout que não quebra #1

    Neste artigo vou apresentar 10 dicas de construção para layouts que eu como desenvolvedor back-end gostaria de ter aprendido logo quando comecei a me aventurar no front-end!

    Porém, vou deixar tudo aqui, resgistrado para você não sofrer com o que eu sofri.

    Dicas para a construção de um layout web que não quebra:

    Algura e largura com vh e vw

    Para acomodar blocos de layout de forma que ocupem a totalidade da página, ao invés de %, use as unidades de medida vh (viewport height) e vw (viewport width).

    Um elemento HTML <div> com width de 25vw, vai ocupar 25% da largura da área disponível no navegador.

    A questão com a unidade % é que ela é relativa, e ajusta as dimenões dos elementos filhos com base em seu elemento pai, o que nos obriga muitas vezes a ter de definir um tamanho explicito ao elemento pai.

    Já trabalhar com vw e vh vai ajustar sempre seus itens de layout com base no tamanho do viewport, bastante você calcular quando da altura e largura disponíveis na tela do navegador quer dar aos seus objetos, sem se preocupar com hierarquias para isso.

    Largura de colunas com ch

    Eu simplesmente adoro usar a unidade ch (character unit) para definir a largura das colunas de uma tabela, especialmente as colunas estreitas e de tamanho máximo previsível, como as de id numérico.

    Então suponhamos que você sabe que sua tabela vai retornar no máximo 4 dígitos de registros (1 – 9999), você pode usar 4ch na coluna id, para delimitar a largura desta coluna exatamente a quatro caracteres.

    Ou melhor ainda, você pode ajustar com js o css width desta coluna para a largura do maior registro retornado. Ou seja, se seu maior registro retorna do foi o id 57 que tem dois digitos, defina dinamicamente 2ch, se for 500 que tem três dígitos defina 3ch, e assim por diante.

    Já no caso de colunas mais largas, como as de nome e endereço, as quais faria menos sentido prever um tamanho de largura ideal, você pode dividir a porcentagem de 100% entre elas. Ou seja, divida 100% de largura entre todas as outras colunas que não usem ch.

    A melhor forma de sobrescrever estilos css

    Muitas vezes precisamos sobrescrever estilos CSS. A melhor forma de fazer isso é inserir um arquivo de estilos como custom.css após a chamada do arquivo principal de CSS.

    Porém se você não puder fazer essa chamada no local correto, que seria dentro da seção <head>, prefira então usar ccs inline direto no HTML.

    De forma alguma abra tags <style> no <body>, isso funciona mas é incorreto, por isso não há garantias de que os navegadores vão tolerar isso em futuras versões, além de é claro deixar o código estrutural feio e confuso.

    Por fim, você também pode usar JS para alterar o estilo desejado. Só recomendo sempre, evitar misturar todas as técnicas disponíveis, procure escolher um padrão.

    Como organizar seu arquivo CSS

    Não é raro começar a adicionar código ao seu arquivo CSS e de repente se perder em sua organização. Por isso abaixo deixa uma ordem para manter as coisas:

    • Reset ou normalize (margin, padding, etc)
    • Variáveis / root
    • Layout geral (header, footer, main)
    • Componentes reutilizáveis (menus, botões, cards, formulários)
    • Helpers/utilitários (classes prontas para diversos usos)
    • Media queries (repita tudo o que fez para a versão desktop, para o mobile)

  • w2ui Themes


    The basic approach to using themes in w2ui is to include w2ui.css and then include some kind of w2ui-custom.css, where you can override the default styles based on your needs.

    This straightforward approach is the one recommended by the creator of w2ui.

    This shows us that sometimes insisting on complex solutions as the “right” ones is purely a matter of preference, not necessarily a fact.

    Let’s keep it simple!

  • Restringir menus para usuários do WordPress

    No WordPress pode ser útil restringir quais menus um usuário pode ter acesso. Não é difícil encontrarmos uma situação onde um usuário de um site deve ter acesso aos plugins WooCommerce, para gerenciar suas vendas e Easy Appoinments para gerenciar os agendamentos de seus clientes, mas não pode ter acesso aos menus Tools ou Settings, por exemplo.

    A questão é que o WordPress por padrão não faz esse tipo de gerenciamento de permissões, e assim sendo, nós temos duas formas de resolver isso, a primeira é usando algum plugin de terceiros, a segunda é criando nosso próprio plugin para gerenciar as permissões.

    Neste tutorial vamos desenvolver a segunda opção, eu a considero mais estável e segura, levando em conta que você terá total controle e conhecimento do que foi feito e do que está rodando no seu site.

    Mãos a massa!

    Antes de começarmos de fato, um alerta! É comum encontrar na internet instruções para pôr código personalizado no arquivo functions.php do seu tema ativo, porém isso é um equívoco, uma vez que o arquivo functions.php pode ser sobrescrito em uma atualização do seu tema, apagando assim qualquer código personalizado inserido nele.

    Mais uma vez então concluímos que uma melhor solução para inserir código personalizado em um site WordPress é criar seu próprio plugin, vamos fazer isso a seguir. E o melhor, é que isso é fácil de fazer!

    Dentro da pasta de plugins crie um diretório e um arquivo com o mesmo nome menu-filter/menu-filter.php

    Este diretório e arquivos não precisam ter o mesmo nome, porém para um plugin muito simples com somente um arquivo, como é neste caso, isso deixa as coisas mais claras.

    Adicione o código abaixo ao arquivo:

    <?php
    /**
     * Plugin Name: My Website Admin Menu Filter
     * Description: Show only Appointments, WooCommerce e Products menus
     * Version: 1.0
     * Author: Fellipe Sanches
     */
    
    function ocultar_menus_para_secovi_colaborador() {
      if (!is_user_logged_in()) return;
    
        $user = wp_get_current_user();
        $email = $user->user_email;
    
        $admins = array(
            "email1@provider.com", 
            "email2@provider.com"
            );
    
        if (!in_array($email, $admins, true)) {
           remove_menu_page('index.php');
           remove_menu_page('edit.php'); // Posts
           remove_menu_page('upload.php'); // Media
           remove_menu_page('link-manager.php'); // Links
           remove_menu_page('edit-comments.php'); // Comenetários
           remove_menu_page('edit.php?post_type=page'); // Pages
           remove_menu_page('plugins.php'); // Plugins
           remove_menu_page('themes.php'); // Appearance
           remove_menu_page('users.php'); // Users
           remove_menu_page('tools.php'); // Tools
           remove_menu_page('edit.php?post_type=project'); //Projetos
           remove_menu_page('options-general.php'); // Settings
           remove_menu_page('et_divi_options'); // Divi
        }
    }
    
    function ocultar_menu_novo_para_secovi_colaborador() {
      if (!is_user_logged_in()) return;
    
        $user = wp_get_current_user();
        $email = $user->user_email;
    
        if (!in_array($email, $admins, true)) {
            global $wp_admin_bar;
            $wp_admin_bar->remove_node( 'new-content' );
            $wp_admin_bar->remove_node( 'comments' );
            $wp_admin_bar->remove_node( 'woocommerce-site-visibility-badge' );
            $wp_admin_bar->remove_node( 'updates' );
            
        }
    }
    
    add_action( 'wp_before_admin_bar_render', 'ocultar_menu_novo_para_secovi_colaborador' );
    add_action( 'admin_init', 'ocultar_menus_para_secovi_colaborador' );
    

    O plugin irá aparecer no seu menu de plugins: