Ves al contingut principal

Exemple Calendari. OOP

Calendari, utilitzant la potència dels objectes DateTimeImmutable i DateInterval. Aquesta aproximació manté el codi dins del bloc PHP principal, però utilitza l'OOP per a la manipulació de dates, la qual cosa el fa més segur i menys propens a errors de fus horari.

A continuació, tens el codi utilitzant només objectes de data.

PHP

<?php
// index.php

// ----------------------------------------------------
// 1. Configuració i Inicialització de Dades
// ----------------------------------------------------

// Configuració del fus horari (CRÍTIC per a la fiabilitat de dates)
date_default_timezone_set('Europe/Madrid');

// Data d'avui i objectes base (Immutables per seguretat)
$dataAvui = new DateTimeImmutable('today');

// Primer dia del mes que volem mostrar (Setembre 2025)
$dataMesActual = new DateTimeImmutable('first day of this month');
// Últim dia del mes
$darrerDiaMes = new DateTimeImmutable('last day of this month');


// ----------------------------------------------------
// 2. Càlcul de la Data d'Inici (Primer Dilluns Visible)
// ----------------------------------------------------

// Dia de la setmana del 1r dia del mes (N: 1=Dl, 7=Dg)
$diaSetmanaPrimerDia = (int)$dataMesActual->format('N');

// Dies a restar per arribar al Dilluns anterior (o el mateix Dilluns)
$diesARestar = $diaSetmanaPrimerDia - 1; 
$dataIteracio = $dataMesActual->modify("-$diesARestar days");


// ----------------------------------------------------
// 3. Càlcul de la Data de Finalització (Últim Diumenge Visible)
// ----------------------------------------------------

// Dia de la setmana de l'últim dia del mes (N: 1=Dl, 7=Dg)
$diaSetmanaDarrerDia = (int)$darrerDiaMes->format('N');

// Dies a sumar per arribar al diumenge (dia 7)
// Si acaba en Diumenge (7), sumem 0 dies. Si acaba en Dissabte (6), sumem 1 dia.
$diesASumar = 7 - $diaSetmanaDarrerDia;

// Data de finalització de la graella (l'últim diumenge de la setmana del mes)
$dataFiGraella = $darrerDiaMes->modify("+$diesASumar days");

// Interval per avançar dia a dia dins del bucle
$intervalDia = new DateInterval('P1D'); 
?>

<!DOCTYPE html>
<html lang="ca">
<head>
    <meta charset="UTF-8">
    <title>Calendari Ajustat: <?php echo $dataMesActual->format("F - Y"); ?></title>
    <style>
        .calendari-taula {
            border-collapse: collapse;
            width: 400px;
            text-align: center;
        }
        .calendari-taula th, .calendari-taula td {
            padding: 8px;
            border: 1px solid #ccc;
        }
        .altre-mes {
            color: #aaa;
            background-color: #f7f7f7;
        }
        .avui {
            background-color: #ffe0b2;
            font-weight: bold;
        }
    </style>
</head>
<body>
    <h3> Calendari Ajustat: <?php echo $dataMesActual->format("F - Y"); ?></h3>
    <table class="calendari-taula" cellspacing="0" cellpadding="0">
        <tr>
            <th>Dl</th><th>Dm</th><th>Dc</th><th>Dj</th><th>Dv</th><th>Ds</th><th>Dg</th>
        </tr>
        
        <?php
        // ----------------------------------------------------
        // 4. Bucle d'Iteració
        // ----------------------------------------------------
        while ($dataIteracio < $dataFiGraella) {
            
            // Comença una nova fila cada dilluns (N=1)
            if ($dataIteracio->format('N') == 1) {
                echo "<tr>";
            }
            
            // --------------------------------------
            // Determinació d'Estils
            // --------------------------------------
            $classe = '';
            
            // A) És el dia actual?
            if ($dataIteracio->format('Y-m-d') === $dataAvui->format('Y-m-d')) {
                $classe = 'avui';
            }
            // B) És del mes que estem mostrant?
            elseif ($dataIteracio->format('m') !== $dataMesActual->format('m')) {
                $classe = 'altre-mes';
            }

            // Pintar la cel·la (j: dia del mes sense zero inicial)
            echo "<td class='$classe'>";
            echo $dataIteracio->format('j');
            echo "</td>";
            
            // Tanca la fila cada diumenge (N=7)
            if ($dataIteracio->format('N') == 7) {
                echo "</tr>";
            }
            
            // Avançar al dia següent
            $dataIteracio = $dataIteracio->add($intervalDia);
        }
        ?>
    </table>
</body>
</html>

Explicació OOP

  1. Fiabilitat amb DateTimeImmutable: En lloc d'utilitzar múltiples crides a date() i la funció ambigua strtotime(), ara tens un objecte $dataMesActual que representa el mes, i un objecte $dataIteracio que es modifica utilitzant el mètode ->modify() o ->add() juntament amb DateInterval.

  2. Càlculs Clars: El càlcul del primer dilluns ($dataIteracio = $dataMesActual->modify("-$diesARestar days")) és molt més explícit i fiable que les manipulacions de strings de l'exemple inicial.

  3. Iteració Sencilla: El bucle while avança dia a dia utilitzant $dataIteracio = $dataIteracio->add($intervalDia), aprofitant la lògica de dates de PHP per gestionar canvis de mes i anys automàticament.

  4. Consistència: Es calcula la $dataFiGraella per garantir que la taula del calendari sempre tingui sis setmanes completes (6 * 7 dies), evitant que la taula es redimensioni segons el dia de la setmana en què acabi el mes.