Fatal eror query in functions - utilizarea unei variabile definite în afara funcției

Poti crea o propozitie SQL doar pentru a prelua randurile unei anumite coloane.

“SELECT column FROM setari_cotos WHRE id = 1” unde column este ceea ce vrei tu sa preiei.

“SELECT Nume_Site FROM setari_cotos WHERE id = 1”

function cotos_setari(PDO $pdo, $setare = null) { 
    if ($setare) {
        $cotos_setari = $pdo->query("SELECT {$setare} FROM cotos_setari WHERE id = '1'");
    } else {
       $cotos_setari = $pdo->query("SELECT * FROM cotos_setari WHERE id = '1'");
    }

    return $cotos_setari->fetch(PDO::FETCH_ASSOC);
}

Acum poti introduce/sau nu o valoare pentru parametrul $setare.

$cotos_setari = cotos_setari($pdo, 'Nume_Site');

if ($cotos_setari) {
    echo $cotos_setari['Nume_Site'];
}

Mai sunt si alte variante.

1 Like

L-am facut asa

//preluare texte din tabela cotos_setari si redate pe site
function cotos_setari(PDO $pdo, $setarea) {


  // Selectare date din MySQL
  $sql_setari = "SELECT $setarea FROM cotos_setari WHERE id='1'";
  $exec_setari = $pdo->query($sql_setari);

  // Se parcurg datele
  while($row = $exec_setari->fetch(PDO::FETCH_NUM)) {
    echo $row[0]. '<br />';      // Afiseaza datele din prima si a doua coloana
  
}
}

Am pus in footer

<?php cotos_setari($pdo, 'Cod_Statistici'); ?>

Si imi afiseaza

Fatal error: Uncaught TypeError: Argument 1 passed to cotos_setari() must be an instance of PDO, null given, called in C:\xampp\htdocs\footer.php on line 25 and defined in C:\xampp\htdocs\core.php:29 Stack trace: #0 C:\xampp\htdocs\footer.php(25): cotos_setari(NULL, 'Cod_Statistici') #1 C:\xampp\htdocs\index.php(182): include('C:\\xampp\\htdocs...') #2 {main} thrown in C:\xampp\htdocs\core.php on line 29

Codul functioneaza daca ii adaug connectarea $pdo in core.php

Am copiat acelas sistem ca cel de l-am rezolvat mai sus…
Acela merge in continuare acesta imi da cu virgula :frowning:

Pai este nevoie ca parametrul $pdo sa contina obiectul PDO, astfel functia ta nu va functiona.Nu inteleg, de ce trebuie sa “parcurgi datele” acolo?

function cotos_setari(PDO $pdo, $setarea) {
  $sql_setari = "SELECT $setarea FROM cotos_setari WHERE id='1'";
  $exec_setari = $pdo->query($sql_setari);

  return $exec_setari->fetch(PDO::FETCH_ASSOC)[$setare];
}

In footer vei face ceva de genul:

<?php echo cotos_setari($pdo, 'Cod_Statistici'); ?>

Nu este cel mai bun exemplu, dar eu vreau sa-ti spun ca nu ai nevoie de acea structura while.

Nu se recomanda sa faci echo din functii, mai bine returnezi ceva din functii!

1 Like

Nu merge nici asa :frowning:

Ce eroare primesti?

Fatal error: Uncaught TypeError: Argument 1 passed to cotos_setari() must be an instance of PDO, null given, called in C:\xampp\htdocs\footer.php on line 26 and defined in C:\xampp\htdocs\core.php:29 Stack trace: #0 C:\xampp\htdocs\footer.php(26): cotos_setari(NULL, 'Cod_Statistici') #1 C:\xampp\htdocs\index.php(182): include('C:\\xampp\\htdocs...') #2 {main} thrown in C:\xampp\htdocs\core.php on line 29

pff din cauza ca folosesc

include core.php in config.php
si include config.php in index.php
si in index.php include footer.php …
Si nu mai depisteaza core.php probabil

Incerca sa-ti organizezi codul mult mai bine, pot sa spun ca ceea ce ai tu acolo este un “haos” :slight_smile:

Sa organizez codul mai bine ar fi mai ok sa iau ceea ce contine (footer.php) (header.php)

Sa le bag intr-o singura pagina adica core.php unde am toate functiile

si acolo sa fac cate o functie pentru footer si una pt header si sa le afisez pe index.php cu footer();

Gen WordPress ?

Pai hai sa ne gandim la o structura cat de cat buna pentru ceea ce vrei sa faci tu.Eu iti voi da un exemplu, de aici tu mergi mai departe.

Aceasta este strucutra unui proiect imaginar:

config
-config.php
functions
-database.php
-functions.php
views
-home.php
init.php
index.php

Fisierul config.php din folderul config poate fi cam asa:

config.php

<?php

return [
    'mysql' = > [
        'hostname' => '127.0.0.1',
        'username' => 'root',
        'password' => 'root',
        'dbname' = > 'test',
    ],
];

Fisierul database.php din folderul functions poate avea:

<?php

function getConnection($config = []) {
    try {
        $pdo = new PDO("mysql:host={$config['hostname']};dbname={$config['dbname']}", $config['username'], $config['password']);
        // ne asiguram ca obiectul PDO foloseste emiterea de exceptii ca metoda de a transmite "erorile"
       $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

       return $pdo;
    } catch (PDOException $e) {
        die($e->getMessage());
   }
}

In fisierul init.php ( ce nu se afla in vreun folder vom avea ) Acest fisier este folosit pentru a initliza si incarca totul.

<?php
// aici pornim si sistem de sesiuni
session_start();

// includem fisierul de functii pentru lucru cu baza de date
require_once 'functions/database.php';

// includem fisierul de functii generale
require_once 'functions/functions.php';

// variabila $config va stoca matricea din fisierul conf.php
$config = require_once 'config/config.php';

// ne conectam la baza de date si stocam obiectul PDO in variabila $conn
$conn = getConnection($config['mysql']);

In continuare, vom pune partea de prezentare a datelor ( HTML-ul ) din fisierul home.php din folderul views.

home.php

<h1>Welcome here <?php echo $name; ?>

Apoi includem acest fisier in fisiere precum index.php, login.php etc.

index.php

<?php

// includem fisierul de initializare
require_once 'init.php';

// aici scriem ce cod avem nevoie pentru acest fisier.
$name = 'Catalin';

// includem partea de prezentare a datelor, HTML-ul
require_once 'views/home.php';

Eu ti-am dat doar un exemplu, de tine depinde sa mergi mai departe! :smiley:

Mai mult decat atat, pot crea un folder, sa zicem models, aici vei pune toate fisierele ce contin functii pentru lucru cu baza de date, fiecare fisier va reprezenta numele unui tabel din baza de date, la singular, de exemplu

user.php

<?php

function createUser(PDO $conn, $data = []) {}

function deleteUser(PDO $conn, $id) {}

function getUserById(PDO $conn, $id) {}

Incluzi asttfel de fisiere unde ai nevoie sa lucrezi cu baza de date.

Sa prespunem ca ai nevoie de acest fisier, user.php in fisierul index.php, putem modifica fisierul index.php astfel…

index.php

<?php // includem fisierul de initializare require_once 'init.php'; // includem fisierul users.php pentru lucru cu baza de date, respectiv cu tabelu users require_once 'models/user.php'; // aici scriem ce cod avem nevoie pentru acest fisier. $name = 'Catalin'; // includem partea de prezentare a datelor, HTML-ul require_once 'views/home.php'; ```
2 Likes

Eu cred ca problema mea cea mai mare este in

// Afiseaza mesaj daca s-a reusit conectarea, altfel, retine eventuala eroare
try {
$dsn = "mysql:host=$host;dbname=$db;charset=$charset";
$opt = [
    PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
    PDO::ATTR_EMULATE_PREPARES   => false,
];
$pdo = new PDO($dsn, $user, $pass, $opt);
}

catch(PDOException $e) {
  echo $e->getMessage();
}

conexiunea din config.php

ca am observat daca in footer langa codul care l-am facut noi mai sus pun

$pdo = new PDO($dsn, $user, $pass, $opt);

Functioneaza perfect

Mulțumesc de lămurire.

Înseamnă că de asta use este menționat doar la closures. :smiley:

1 Like

Apropo, ca tot vorbim de closures si de use, trebuie sa lamuresc ceva, variabilele introduse folosind use nu devin un fel de alias, mai precis, sa vedem acest lucru pe baza unui exemplu:

<?php

$name = 'Catalin';

$myName = function () use ($name) {
    $name = 'Cata';
};

$myName();

echo $name; // se afiseaza Catalin

Cu alte cuvinte, aceste variabile se comporta ca si cum au fost introduse ca parametrii functiei, se citeste doar valoarea, atata tot.

Presupun ca use este folosit pentru a evidentia mai clar ce variabile din contextul global folosete “functia”.

1 Like

Sfatul cu variabilele globale primit de la ceilalți membri este ok, dar poți duce totul un pic mai departe. Ce-ar fi dacă n-ar trebui să ai o variabilă globală $pdo, $conn sau cum s-o numi ea, pe care s-o tot pasezi dintr-o parte în alta? Poți realiza asta folosind o singură funcție ce folosește concepte înrudite cu tehnica memoization și pattern-ul singleton.

function db() {
    static $connection = NULL;

    if (!$connection) {
        // inițializezi $dsn, $user, $pass, $opt
        $connection = new PDO($dsn, $user, $pass, $opt);
    }

    return $connection;
}

apoi, în codul tău, oriunde ai nevoie de conexiunea la baza de date, nu mai este necesar să transmiți variabila $pdo ca parametru:

// Exemplu:
function cotos_setari($setarea) { // a fost eliminat parametrul $pdo
    $sql_setari = "SELECT $setarea FROM cotos_setari WHERE id='1'";
    $exec_setari = db()->query($sql_setari); // în loc de $pdo, apelezi funcția db()

    return $exec_setari->fetch(PDO::FETCH_ASSOC)[$setare];
}

Același procedeu îl poți folosi și pentru configurări sau setări, eliminând astfel orice variabilă globală. Urmând structura lui @PocsanJr, ai putea avea totul structurat cam așa:

[config]
    config.php
[functions]
    database.php
    general.php
[views]
    [parts]
        footer.html.php
        header.html.php
    _site-offline.html.php
    contact.html.php
    home.html.php
_init.php
index.php
contact.php 
<?php
// _init.php

define('APP_ROOT', __DIR__);

require_once 'functions/general.php';
require_once 'functions/database.php';

try {
    db(config('mysql'));
} catch (PDOException $e) {
    echo render('_site-offline');
    die();
}

?>
<?php
// config/config.php

return [
    'mysql' => [
        'hostname' => 'tmp.fail',
        'username' => 'root',
        'password' => 'root',
        'dbname'   => 'test',
        'charset'  => 'utf8',
    ],

    'settingsTable' => 'cotos_setari'
];
?>
<?php
// functions/general.php

function config($key = NULL) {
    static $config = [];

    if (!$config) {
        $config = require_once APP_ROOT . '/config/config.php';
    }

    if (!$key) {
        return $config;
    }

    if (array_key_exists($key, $config)) {
        return $config[$key];
    }

    return NULL;
}

function settings($key = NULL) {
    static $settings = [];

    if (!$settings) {
        $table = config('settingsTable');
        $data = db()->query("SELECT * FROM `{$table}` WHERE `id`=1");
        if ($data) {
            $settings = $data->fetch(PDO::FETCH_ASSOC);
        }
    }

    if (!$key) {
        return $settings;
    }

    if (array_key_exists($key, $settings)) {
        return $settings[$key];
    }

    return NULL;
}

/**
 * Funcție pentru afișarea template-urilor HTML (...sau alte tipuri).
 *
 * Ex:
 * render('page', ['title' => 'My page title']);
 * va afișa template-ul `views/page.html.php` în care va fi accesibilă variabila `$title`.
 *
 * render('latest-news', ['news' => ['news1', 'news2', 'etc']], ['type' => 'xml']);
 * va afișa template-ul `views/latest-news.xml.php` în care va fi accesibilă variabila `$news`.
 *
 * render('sales-report', ['yearly' => [], 'monthly' => []], ['type' => 'csv']);
 * va afișa template-ul `views/sales-report.csv.php` în care vor fi accesibile variabilele `$yearly` și `$monthly`.
 *
 * Pe lângă variabilele trimise ca parametru în `data`, în template-uri mai sunt accesibile funcțiile de ajutor
 * `$h($textValue)` - aplică `htmlentities()` la valoarea dată ca parametru
 * `$render($viewName)` - afișează un alt `view` în `view`-ul curent, pastrând variabilele
 */
function render($view, $data = [], $params = []) {
    $params += [
        'type' => 'html'
    ];

    $data += ['page' => $view];

    $type = $params['type'];
    $path = APP_ROOT . "/views/{$view}.{$type}.php";

    $isolate = function($__context__) {
        $h = function($str) {
            return htmlentities($str, ENT_QUOTES, 'utf-8');
        };

        $render = function($view) use ($__context__) {
            return render($view, $__context__['data'], $__context__['params']);
        };

        ob_start();
        extract($__context__['data']);
        include $__context__['path'];
        return ob_get_clean();
    };

    return $isolate(compact('path', 'data', 'params'));
}

?>
<?php
// functions/database.php

function db($config = []) {
    static $connection = NULL;

    if (!$connection) {
        $defaults = [
            'hostname' => '127.0.0.1',
            'username' => 'root',
            'password' => 'root',
            'dbname'   => '',
            'charset'  => 'utf8'
        ];
        $config += $defaults;

        $dsn = "mysql:host={$config['hostname']};dbname={$config['dbname']};charset={$config['charset']}";
        $opt = [
            PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
            PDO::ATTR_EMULATE_PREPARES   => false,
        ];
        $connection = new PDO($dsn, $config['username'], $config['password'], $opt);
    }

    return $connection;
}

?>
<?php
// contact.php

require_once __DIR__ . '/_init.php';

echo render('contact', [
    'pageTitle' => 'Send me a message!',
    'contactOptions' => [
        'Twitter' => 'ionut.botizan',
        'Github' => 'prafuitu'
    ]
]);

?>
<!-- views/contact.html.php -->
<?=$render('parts/header')?>

<h1>Contact</h1>

<p>Contact me on:</p>
<ul>
    <?php foreach ($contactOptions as $name => $handle) : ?>
    <li><strong><?=$h($name)?>:</strong> <?=$h($handle)?></li>
    <?php endforeach; ?>
</ul>

<?=$render('parts/footer')?>

Și așa mai departe! Am adăugat o arhivă cu codul complet (și funcțional).

framework.zip (4.0 KB)

Mare atenție la funcția render(), folosită la afișarea template-urilor! :slight_smile:

6 Likes

Cum pot face SEO LINK (url)
pe acel framework ?

De exemplu index.php cu acasa.html
sau categoria.php cu Actiune/