• Jetzt anmelden. Es dauert nur 2 Minuten und ist kostenlos!

Define Problem

Frucht

Mitglied
[GELÖST] Define Problem

Hallo,
ich habe ein Problem mit den Konstanten. Ich möchte die Werte aus der Datenbank laden, was ja an sich eig. auch funktionieren sollte, obwohl die Konstante definiert ist ist sie leer.

Zudem bekomme ich auch die Fehlermeldung:

Trying to get property of non-object in core.php on line 121



Core.php

PHP:
private function loadConstants() 
    {  
        define("tplThemeDir", $this->getSettings("tplThemeDir", "frontend"));
        define("tplExt", $this->getSettings("tplExt", "frontend"));
        define("baseLANG", $this->getSettings("language", "frontend"));
        define("baseURL", $this->getSettings("baseURL", "frontend"));
                
    }
PHP:
public function getSettings($settingName, $settingTyp) 
    {
        
        $sql = "SELECT value FROM ".DB_PRÄFIX."settings WHERE name='$settingName' and typ='$settingTyp'";
        $result = $this->_DB->query($sql);
            
        if($result == true) 
        {
            while($row = $result->fetch_array(MYSQLI_NUM)) 
            {
                $value = $row[0];   
            } 
            return $value;
        }
        
        
        
        if ($result->num_rows == 0) //LINE 121
        {
            throw new SystemException("Die gesuchte Einstellung wurde nicht gefunden", 1);        
        }
    }
Bootstrap

PHP:
Registry::set("core", new Core());
Index
PHP:
// REQUIRE START

require_once './core/bootstrap.inc.php';

// REQUIRE END




//SYSTEM START
 
ob_start();


use core\classes\Dispatcher as Dispatcher;

Dispatcher::dispatch();
 
Zuletzt bearbeitet:
Mehrere Dinge sind mir aufgefallen.
Warum benutzt du eine while-Schleife, wenn du nur das letzte Resultat benutzt?

Man muss nicht OOP benutzen nur um so viele Methoden wie möglich zu haben, das geht auch ganz einfach so:

PHP:
private function loadConstants() {
  $sql = 'select name, value from '.DB_PRÄFIX /* mit Umlauten würde ich wirklich aufpassen!*/."settings where name in('tplThemeDir','tplExt','language','baseURL') and typ='frontend'";
  $result = $this->_DB->query($sql);
  $count = $result->num_rows;
  while ($row = $result->fetch_row()) {
    switch($row[0]) {
      case 'tplThemeDir': {define('tplThemeDir',$row[1]);}break;
      case 'tplExt': {define('tplThemeDir',$row[1]);}break;
      case 'language': {define('baseLANG',$row[1]);}break;
      case 'baseURL': {define('baseURL',$row[1]);}break;
    }
  }
  $result->close();
  if ($count != 4) {
    throw new SystemException("Die gesuchten Einstellungen wurde nicht gefunden", 1);
  }
}
 
Hmm hab immer noch das Problem ....

Mit deiner kompakten Methode ist zwar alles auf kleinen Raum verfügbar aber nicht dynamisch
 
Was den Fehler angeht: Debuggen. Zum Beispiel: Hat $sql den erwarteten Wert? Auf was wird $result gesetzt? var_dump hilft.

Wie die Methoden angeordnet werden sollten, hängt stark davon ab, wie sie eingesetzt werden. Ziele sollten aber definitiv sein, die Anzahl der Queries gering zu halten und den benötigten Arbeitsspeicher ebenfalls nicht über Gebühr zu strapazieren.

  • Wenn tendenziell die meisten Einträge aus der settings-Tabelle während eines Script-Durchlaufs abgerufen werden, würde ich so in etwa eine init-Methode in Core schreiben, die zu Beginn der Ausführung mit einer Query alle Einträge aus settings holt und in einem Array zwischenspeichert. getSettings kann dann die Werte aus diesem Array auslesen und muss keine eigenen Queries mehr absenden.
  • Wenn nur wenige Einträge ausgelesen werden, können die individuellen Queries sicherlich auch beibehalten werden. Wenn jedoch manche dieser Einträge mehrfach gelesen werden, bietet es sich auch hier an, einmal ausgelesene Einträge in einem Array zwischenzuspeichern und nicht immer wieder neu aus der DB zu laden.

Beides sind Caching-Ansätze, um die Anzahl der Datenbankabfragen zu reduzieren.

@Frucht:

In diesem Zusammenhang stellt sich übrigens die Frage, wieso du die Werte noch einmal als Konstanten definierst. Davon würde ich absehen. Du kannst sie bereits über

PHP:
Registry::get('core')->getSettings('tplThemeDir', 'frontend');
    // besser: getSetting (kein Plural)

abrufen. (Zum Caching siehe oben.) Das hat den zusätzlichen Vorteil, dass deine Exception greift, wenn eine nicht vorhandene Einstellung abgefragt wird. Bei undefinierten Konstanten gibt es nur:

Code:
Notice: Use of undefined constant XYZ - assumed 'XYZ' in xy.php on line 123
 
Wenn tendenziell die meisten Einträge aus der settings-Tabelle während eines Script-Durchlaufs abgerufen werden, würde ich so in etwa eine init-Methode in Core schreiben, die zu Beginn der Ausführung mit einer Query alle Einträge aus settings holt und in einem Array zwischenspeichert. getSettings kann dann die Werte aus diesem Array auslesen und muss keine eigenen Queries mehr absenden.
was wäre denn am performantesten das mehrdimensionale Array dann zu durchsuchen?
 
Zuletzt bearbeitet:
Nunja ich speichere jetzt alle Settings in einem Array und getSetting muss diese ja auslesen bzw. im array suchen nun frage ich mich wie ich das am besten lösen könnte bei einem mehrdimensionalen array ..... vl array_search ?
 
Einfach als Hashmap. Hier ein Beispiel für die zweite Methode, die ich vorgestellt habe (ungetestet, aus dem Kopf):

PHP:
protected $settingsCache       = array();
protected $settingsCacheErrors = array();

/**
 *
 */
public function getSettings($settingName, $settingTyp) 
    {
		/* Setting wurde bereits nachgefragt, aber nicht in der DB
		   gefunden -> Exception */
		if (isset(
			$this->settingsCacheErrors[$settingName][$settingTyp]
		)) {
			throw new SystemException('');
		}
    
		/* Setting wurde noch nicht nachgefragt */
		if (!isset($this->settingsCache[$settingName][$settingTyp])) {
			$value = null;
		
			/* Versuch, Setting aus DB auszulesen */
			try {
				$value = $this->getSettingFromDb($settingName,
						                         $settingTyp);
			} catch (Exception $e) {
				/* Setting nicht in DB vorhanden */
				
				/* Fehler für nächste Anfrage speichern */
				$this->settingsCacheErrors[$settingName][$settingTyp]
				        = true;				
				
				throw new SystemException('');
			}
			
			/* Setting wurde ausgelesen */
			$this->settingsCache[$settingName][$settingTyp] = $value;
		}
		
		return $this->settingsCache[$settingName][$settingTyp];
    }

/**
 *
 */    
protected function getSettingFromDb($settingName, $settingTyp)
    {       
		$value = null;
    
        $sql = "
			SELECT value
			FROM ".DB_PRÄFIX."settings
			WHERE name='$settingName'
			AND typ='$settingTyp'";
			
        $result = $this->_DB->query($sql);
            
        if ($result === false || $result->num_rows === 0) {
            throw new Exception(
                    "Die gesuchte Einstellung wurde nicht gefunden", 1);
        }
        
        while ($row = $result->fetch_array(MYSQLI_NUM)) {
            $value = $row[0];
        }        
        
        return $value;
    }
 
danke für deine hilfe : )

ich habe ein mehrdimensionales array

z.b.

PHP:
Array (     [0] => Array         (             [name] => tplThemeDir             [value] => xy/             [typ] => frontend         )      [1] => Array         (             [name] => tplExt             [value] => .htm             [typ] => frontend         )      [2] => Array
soll ich das zunächst zählen... und dann mit einer schleife alles durchgehen? performance?
 
Ja, eine Hashmap ist in PHP eine Variante eines Arrays.

Immer, wenn ein Eintrag direkt anhand eines Keys angewählt werden kann (test1), beträgt die Lookupzeit O(1), ist also unabhängig von der Anzahl der Elemente des Arrays.

Wenn du erst das Array linear durchsuchen musst, bis du den gewünschten Eintrag gefunden hast (test2), müssen im Schnitt die Hälfte der Elemente des Arrays durchlaufen werden. Wenn n die Anzahl der Elemente ist, wäre die durchschnittliche Lookupzeit O(n/2) beziehungsweise O(n), weil für solcherlei Betrachtungen konstante Faktoren zu vernachlässigen sind. (Die Laufzeit verdoppelt sich ungeachtet aller Faktoren bei Verdopplung des n, hängt also letztlich nur von n ab.)

- Landau-Symbole

PHP:
<?php

/**
 * Hashmap
 *
 * Array
 * (
 *     [a] => 1
 *     [b] => 2
 *     [c] => 3
 *     ...
 */
function test1()
{
    $a = array_combine(range('a', 'z'), range(1, 26));

    $start = microtime(true);

    for ($i = 0; $i < 10000; $i++) {
        $tmp = $a['m'];
    }

    return microtime(true) - $start;
}

/**
 * Liste
 *
 * Array
 * (
 *     [0] => Array
 *         (
 *             [key] => a
 *             [value] => 1
 *         )
 *
 *     [1] => Array
 *         (
 *             [key] => b
 *             [value] => 2
 *         )
 *     ...
 */
function test2()
{
    $a = array_combine(range('a', 'z'), range(1, 26));
    $b = array();

    foreach ($a as $key => $value) {
        $b[] = array('key' => $key, 'value' => $value);
    }

    $start = microtime(true);

    for ($i = 0; $i < 10000; $i++) {
        foreach ($b as $entry) {
            if ($entry['key'] === 'm') {
                $tmp = $entry['value'];
                break;
            }
        }
    }

    return microtime(true) - $start;
}



echo 'test1: ', test1(), '<br>';
echo 'test2: ', test2(), '<br>';
echo 'test1: ', test1(), '<br>';
echo 'test2: ', test2(), '<br>';
echo 'test1: ', test1(), '<br>';
echo 'test2: ', test2(), '<br>';
echo 'test1: ', test1(), '<br>';
echo 'test2: ', test2(), '<br>';
echo 'test1: ', test1(), '<br>';
 
Zuletzt bearbeitet:
Ich muss das Array also in eine => Hashmap "umformen"?

Wenn ja, wie und wie suche ich darin?

Sorry wenn ich es grad nicht verstanden hab : (
 
Zuletzt bearbeitet:
Na ja, was heißt, du musst. Das wäre eben effizient, wenn du mit einem Cache für die Datenbankabfragen arbeiten möchtest. In #9 habe ich ein relativ komplettes Beispiel beschrieben, inklusive Suche.

Die Suche beschränkt sich darauf, abzufragen, ob ein bestimmter Index im Array gesetzt ist.

PHP:
<?php

$settings = array(
    'tplThemeDir' => './templates',
    'tplExt'      => 'phtml',
    'language'    => 'de-de',
    'baseURL'     => 'http://www.example.org/'
);



$search = 'baseURL';

if (isset($settings[$search])) {
    echo 'Setting found: ' . $settings[$search];
} else {
    echo 'Setting not found';
}



$search = 'pageTitle';

if (isset($settings[$search])) {
    echo 'Setting found: ' . $settings[$search];
} else {
    echo 'Setting not found';
}

Da du zusätzlich zum Setting-Namen auch immer den Setting-Typ abzufragen scheinst, habe ich in #9 den Typ als weitere Dimension zur Hashmap hinzugefügt.

Das ergibt wahrscheinlich nur dann Sinn, wenn zwei Settings mit gleichem Namen aber unterschiedlichem Typ existieren können. Das weißt aber nur du. Falls das nicht der Fall ist, solltest du den Typ als Parameter für die getSettings-Funktion weglassen.
 
Okay, den Großteil hab ich jetzt verstanden

das einzige was mir noch nicht klar ist... ich verwende ja Methode 1(alle settings aus der Datebank laden und in einem Array speichern), nun wie mache ich jetzt ein assoziatives Array bzw. ein Hashtable daraus? Ich habe bereits gegoogelt und bin auf ArrayAccess und auf SplObjectStorage gestoßen wobei diese in Beispielen keine mehrdimensionalen Arrays verwenden... vl sitze ich jetzt auch ein bisschen zu lange an diesem Problem und verliere langsam den Faden^^
 
PHP:
// SELECT name, typ, value FROM ...

while ($row = $result->fetch_assoc()) {
    $this->settingsCache[$row['name']][$row['typ']] = $row['value'];
    // Oder eben: $this->settingsCache[$row['name']] = $row['value'];
}

Oder sogar:

PHP:
while ($row = $result->fetch_assoc()) {
    switch ($row['typ']) {
        case 'integer':
            $this->settingsCache[$row['name']] = (int) $row['value'];
            break;
        case 'array':
            $this->settingsCache[$row['name']] = unserialize($row['value']);
            break;
        case 'usw...':
            // ...
    }
}
 
danke für eure Hilfe : )

die schwierigste Lösung ist immer die einfachste

Ich hab schon eine Hashtable Klasse(implement ArrayAccess) gemacht um das so zu lösen^^ Über Google bin ich auch auf SplObjectStorage gestoßen
 
Zurück
Oben