C/C++ week November Black Friday
Black Friday je tu! Využij jedinečnou příležitost a získej až 80 % znalostí navíc zdarma! Více zde
Pouze tento týden sleva až 80 % na e-learning týkající se C/C++

Diskuze: Nefungující uložení hodnot do JSON

Aktivity (2)
Avatar
Matěj Strnad:18. července 19:25

Ahoj,
nevíte proč nefunguje kód uvedený níže? Problém je v tom že když do něj dám 6 hodnot, uloží jen 1-2 poslední, což taky nechápu jelikož by to mělo být deterministické. (jsou to stejné hodnoty). Žádný error to nehází. Všechny hodnoty jsou datového typu string, jedná se primárně o přihlašovací údaje k DB. Pokud Vás napadne lepší řešení, tak to klidně mohu udělat podle vašeho řešení.

class Config {
  private $path = __DIR__ . "/config.json";
  function load () {
    $f = fopen ($this->path, "r");
    unset ($GLOBALS["_config"]);
    $GLOBALS["_config"] = json_decode (fread ($f, filesize ($this->path)), true);
    fclose ($f);
  }
  function __construct () {
    if (!isset($GLOBALS["_config"])) {
      $this->load ();
    }
  }
  function get ($name) {
    if (isset ($GLOBALS["_config"][$name])) {
      return $GLOBALS["_config"][$name];
    } else {
      return null;
    }
  }
  function set ($name, $content) {
    $d = $GLOBALS["_config"];
    $d[$name] = $content;
    $f = fopen ($this->path, "w");
    fwrite ($f, json_encode ($d));
    fclose ($f);
    $this->load ();
  }

}

Zkusil jsem: Googlit, zírat do kódu, zkoušet

Chci docílit: Uložení přihlašovacích údajů k DB.

 
Odpovědět
18. července 19:25
Avatar
Jan Kerhart
Člen
Avatar
Odpovídá na Matěj Strnad
Jan Kerhart:19. července 2:25

Ahoj,
nahraď funkci fread() za file_get_contents() a smaž řádek 4 a 7 a mělo by to fungovat :)

unset ($GLOBALS["_config"]);
$GLOBALS["_config"] = json_decode (file_get_contents($this->path), true);

Co se týče řešení obecně, tak

  • Vyvaruj se používání $GLOBALS a podobných nesmyslů, pokud k tomu nemáš dobrý důvod. Použij raději klasický privátní atribut. (A nenapadá mě žádný případ, kdy by bylo $GLOBALS nutno použít.)
  • U každé metody by měl být uveden modifikátor přístupu (public, private, protected)
  • Natvrdo napsat cestu k souboru do třídy není úplně ideálním řešením, třída potom není univerzální a nejde ji použít na jiném místě.
  • Pokud soubor neexistuje, vyhodí to warning.
  • Pokud byla mezi načtením souboru a zápisem hodnoty v souboru provedena nějaká změna, tak se smaže. Pozn: V mém řešení se naopak změna neprojeví ve stávající instanci. Pokud by toto bylo nežádoucí, je možné to jednoduše upravit.

Já osobně bych to řešil asi nějak takto:

namespace MatejStrnad\Settings;

use Exception;

class SettingsManager
{
    /**
     * @var array Stores current settings.
     */
    private $data;
    /**
     * @var string Path to settings file.
     */
    private $filePath;

    /**
     * SettingsManager constructor.
     * @param string $filePath Path to settings file.
     */
    public function __construct($filePath)
    {
        $this->filePath = $filePath;
        $this->load();
    }

    /**
     * Loads settings from file.
     */
    public function load()
    {
        if (file_exists($this->filePath)) {
            $this->data = json_decode(file_get_contents($this->filePath), true);
        } else {
            $file = fopen($this->filePath, 'w');
            fclose($file);
        }
    }

    /**
     * Gets setting value.
     * @param string $key Settings key to return.
     * @return string|null
     */
    public function getValue($key)
    {
        if (isset($this->data[$key])) {
            return $this->data[$key];
        } else {
            return null;
        }
    }

    /**
     * Saves value to settings file.
     * @param string $key Settings key to set.
     * @param string $value Value of the key.
     * @throws Exception
     */
    public function setValue($key, $value)
    {
        $fileContents = json_decode(file_get_contents($this->filePath), true);
        $fileContents[$key] = $value;
        $file = fopen($this->filePath, 'w');
        if (fwrite($file, json_encode($fileContents)) === false) {
            throw new Exception("Write error!");
        }
        fclose($file);
    }
}

Pokud to ale budeš používat pouze pro ukládání údajů od databáze, tak mi to přijde zbytečně složité. V tomto případě bych asi použil jen obyčejnou statickou třídu:

class Settings
{
    public static $database = array(
        'host' => "192.168.1.123",
        'user' => "root",
        'pass' => "12345",
        'db' => "system"
    );

    public static $projectName = "Jméno projektu";

}

A použiješ ji jednoduše takto:

echo(Settings::$projectName); //Vypíše název projektu
$ip = Settings::$database['host']; //Uloží adresu do proměnné

Nevýhoda tohoto řešení je, že nejde jednoduše nastavení měnit z aplikace, to ale u údajů od databáze většinou nepotřebujeme. Velkou výhodou je ale zase to, že kdyby se někomu podařilo nějak tento soubor načíst (např. chybou v jiné třídě), tak jeho obsah stejně uživatel neuvidí, protože se soubor jen načte v php a uživateli se jeho obsah neodešle...

Akceptované řešení
+20 Zkušeností
+1 bodů
Řešení problému
 
Nahoru Odpovědět
19. července 2:25
Avatar
Jan Kerhart
Člen
Avatar
Odpovídá na Jan Kerhart
Jan Kerhart:19. července 2:54

Pozn. Ještě mě napadlo, metoda setValue by se dala pěkně zjednodušit pomocí metody file_put_contents, ale funkce je stejná:

public function setValue($key, $value)
    {
        $fileContents = json_decode(file_get_contents($this->filePath), true);
        $fileContents[$key] = $value;
        if (file_put_contents($this->filePath, $fileContents) === false) {
            throw new Exception("Write error!");
        }
    }
Editováno 19. července 2:56
 
Nahoru Odpovědět
19. července 2:54
Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!
Avatar
Odpovídá na Jan Kerhart
Vladislav Ladicky:19. července 10:20

Mám otázku napríklad na túto metódu:

public function getValue ($key) {
  if (isset($this->data[$key])) {
    return $this->data[$key];
  } else {
    return null;
  }
}

Nešla by zapísať aj takto?

public function getValue ($key) {
  return $this->data[$key] ?? null;
}
 
Nahoru Odpovědět
19. července 10:20
Avatar
Jan Kerhart
Člen
Avatar
Odpovídá na Vladislav Ladicky
Jan Kerhart:19. července 13:02

Ano, určitě šla. Jen pozor na to, že tento tzv. "null coalescing operator" je podporován až od verze PHP 7 a mnoho (špatných) hostingů používá stále ještě PHP 5.x. Ale pokud máš kvalitní hosting, kde si můžeš vybrat a nebo mají PHP aktualizované, tak určitě. Na starším PHP by to šlo zapsat také třeba ternálním operátorem:

return isset($this->data[$key]) ? $this->data[$key] : null
 
Nahoru Odpovědět
19. července 13:02
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 5 zpráv z 5.