PHPDevs

Projekt obiektowy z Composerem i Twigiem? Czytaj!

Tablice, stringi, pliki - kolejny projekt > Lekcja 4

Wyświetlanie zadań z pliku

Przyszła pora na wyświetlenie zadań zapisanych w pliku. Zaczniemy od tego, dalej pojawi się dodawanie czy usuwanie.

Jakby tu zapisać zadania w pliku... Możliwości tak naprawdę jest wiele. Masz prawo teraz ich nie znać (zakładając, że jesteś nowicjuszem), ale ja bym widział przynajmniej kilka sposobów:

Wykonajmy sobie dziś opcję trzecią, czyli dane będziemy przechowywali w pliku jako format JSON. Do tak prostego projektu, przechowującego tylko jedną daną (treść zadania) wystarczyłoby nam co prawda spokojnie rozwiązanie pierwsze, ale w razie gdybyś chciał bardziej rozbudować ten kod, będzie łatwiej. No i poznamy znów coś przydatnego i ciekawego. Nad samym JSONem nie będę się zbytnio rozwodził, doczytaj na przykład na Wikipedii. PHP posiada funkcje do operacji na tym formacie danych - skorzystamy z json_encode() i json_decode().

Jak to wygląda w praktyce? A proszę bardzo, nic trudnego:

<?php

$tasks = ['Task 1', 'Task 2', 'Task 3'];
$json = json_encode($tasks);
var_dump($json);

var_dump(json_decode($json, true));
string(28) "["Task 1","Task 2","Task 3"]"
array(3) {
  [0]=>
  string(6) "Task 1"
  [1]=>
  string(6) "Task 2"
  [2]=>
  string(6) "Task 3"
}

Funkcja z _encode tworzy i zwraca JSON (jako ciąg tekstowy) z podanej w argumencie tablicy. json_decode() działa odwrotnie, czyli jako pierwszy argument oczekuje stringa z JSONem. Drugi argument, w moim przypadku true, mówi czy dane mają zostać zwrócone jako tablica. Jeśli go nie podamy użyta zostanie wartość domyślna, którą jest false, i zwrócony zostanie obiekt (czego nie chcemy bo: po pierwsze nie potrzebujemy tutaj obiektu, po drugie przypuszczalnie nie znasz jeszcze obiektów, gdyż nie pojawiły się w kursie).

Pozostaje mi jeszcze wyjaśnić odczyt danych z pliku. Skorzystamy z funkcji file_get_contents(). Wystarczy, że jako argument przekażemy nazwę pliku do odczytania (ewentualnie ze ścieżką) i jako zwracaną wartość otrzymamy jego zawartość.

Ciekawostka

Warto wiedzieć, że istnieją też inne sposoby operowania na plikach, na przykład funkcje fopen() czy file(). Ta druga zwraca tablicę zawierającą wszystkie linie w pliku - idealnie byłoby jej użyć, gdybyśmy zdecydowali się na pierwszy sposób przechowywania zadań w pliku.

Ok, napiszmy funkcję readFromFile() odpowiadającą za odczytanie danych z pliku (które będą w formacie JSON) i zwrócenie gotowej tablicy, która przyda nam się do dalszych operacji. Tak jak mówiłem, funkcje zapisywał będę w pliku functions.php, który lekcję wcześniej dołączyliśmy do index.php.

functions.php<?php
function readFromFile(): array
{
    $data = file_get_contents('data.txt');
    if ($data) {
        return json_decode($data, true);
    }
    return [];
}

Większość już wcześniej omówiłem, więc mam nadzieję, że jest to zrozumiałe. Odczytujemy zawartość pliku do zmiennej $data, następnie, jeśli udało się coś odczytać, dekodujemy JSON na tablicę i zwracamy ją. Nazwa pliku jest właściwie dowolna. W sytuacji gdyby warunek się nie spełnił zwracamy na koniec pustą tablicę - elseif nie jest tu potrzebny, gdyż jak pewnie pamiętasz return kończy wykonywanie kodu wewnątrz danej funkcji.

Przetestujmy, dodając wywołanie napisanej funkcji i var_dumpa w odpowiednim miejscu switcha w pliku index.php.

index.php<?php
// switch ...
    case null:
        $tasks = readFromFile();
        var_dump($tasks);
        break;

Ups, coś chyba poszło nie tak. Komunikat błędu mówi: "no such file or directory". Czyli nie ma pliku o podanej nazwie, stąd to ostrzeżenie. W zasadzie to moglibyśmy po prostu go stworzyć i problemu by nie było, ale i tak wypadałoby jakoś zabezpieczyć się przed przypadkowym brakiem pliku. Proponuję sprawdzać czy plik istnieje przy użyciu funkcji file_exists() - jeśli tak wykonać odczyt i json_decode(), jeśli nie zwrócić pustą tablicę.

functions.php<?php
function readFromFile(): array
{
    if (file_exists(FILENAME)) {
        $data = file_get_contents(FILENAME);
        if ($data) {
            return json_decode($data, true);
        }
    }
    return [];
}

Dodałem też stałą FILENAME, w której przechowywana będzie nazwa pliku - skoro będziemy używali jej w kilku miejscach (na razie dwóch, ale już niedługo pojawi się zapis zadań do pliku) to zamiast powtarzać wszędzie to samo, lepiej podstawić zmienną czy stałą. Dzięki temu w razie konieczności poprawy zrobimy to raz, w jednym miejscu. Zadeklarowałem ją na samym początku pliku index.php.

Teraz już błędu nie będzie, ale jako że nie mamy jeszcze dodawania zadań nie za bardzo jak mamy przetestować działanie. Podaję więc poniżej przykładową zawartość pliku data.txt, możesz zrobić takowy u siebie, wkleić to i spróbować.

["Task 1","Task 2","Task 3"]

Jak to się mówi... u mnie działa ;)

Powszechny problem

Gdyby zdarzyło się, że otrzymasz błąd typu "Permission denied" oznacza to, że nie masz uprawnień do danego pliku (w przykładzie data.txt). Należy wtedy odpowiednio je zmienić, w systemach Linux na przykład korzystając z chmod lub chown (albo trybu graficznego).

Pozostaje jeszcze tylko dopisać jakieś normalne wyświetlanie zadań. Przy każdym potrzebujemy wyświetlić jego numer (żeby było łatwiej będzie to indeks z tablicy) oraz treść. Użyję do tego prostej pętli foreach. Na koniec tej lekcji plik index będzie prezentował się tak:

index.php<?php

define('FILENAME', 'data.txt');
require_once 'functions.php';

$data = array_fill(0, 3, null);
$argv = array_replace($data, $argv);
list($filename, $command, $content) = $argv;

switch ($command) {
    case 'add':
        echo 'Add TODO';
        break;
    case 'remove':
        echo 'Remove TODO';
        break;
    case null:
        $tasks = readFromFile();
        foreach ($tasks as $number => $task) {
            echo ($number + 1) . ' | ' . $task . PHP_EOL;
        }
        echo '-----' . PHP_EOL . 'All tasks: ' . count($tasks);
        break;
    default:
        echo 'Sorry, invalid command!';
        break;
}
echo PHP_EOL;

Dodałem też na koniec informację o ilości wszystkich zadań, którą można uzyskać dzięki count() (zliczenie elementów w tablicy). Zwiększanie wartości $number (czyli indeksu) o jeden robię, aby zadania numerowane były od 1, a nie 0. Nie jest to rzecz jasna konieczne, taki dodatek. Te numerki posłużą nam później do usuwania zadań z listy - będziemy usuwać element o danym indeksie z tablicy.

Poprzednia lekcja Następna lekcja

Udostępnij

  • Facebook
  • Twitter
  • Google+

Komentarze