Overschrijf variable in autoloader

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

Niels Veer

Niels Veer

01/05/2015 09:20:19
Quote Anchor link
Hallo allemaal,

Ik heb vraag omtrent het gebruik van de __autloader functie.
Dit is een stukje uit mijn script:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
function __autoload($class)
{
    strtolower($class);
    
    if (file_exists(PAF_FRAMEWORK_ROOT . '\class.' . $class . '.php'))
    {
        require_once PAF_FRAMEWORK_ROOT . '\class.' . $class . '.php';
    }
    
    $request = str_replace("com_", "", $_GET['component']);
    $filename = str_replace($request, "", $class);
    strtolower($filename);
    
    if (file_exists(APPLICATION_ROOT . '\components\com_' . $request . '/' . $filename . '.php'))
    {
        require_once APPLICATION_ROOT . '\components\com_' . $request . '/' . $filename . '.php';
    }
}

$login = 0;

if($login == 0)
{
    $model = new loginModel();
    $controller = new loginController($model);
    $view = new loginView($controller, $model);
}

if($login == 1)
{
    // Convert GET
    $request = str_replace("com_", "", $_GET['component']);
    
    // Set mvc vars
    $componentModel = $request . 'Model';
    $componentController = $request . 'Controller';
    $componentView = $request . 'View';

    // Include classes
    $model = new $componentModel();
    $controller = new $componentController($model);
    $view = new $componentView($controller, $model);    

    if (isset($_GET['action']) && !empty($_GET['action']))
    {
        $controller->{$_GET['action']}();
    }
}


Het probleem is dat het $request variable in de __autloader functie, de $_GET['component'] uit mijn URL gebruikt. Deze wil ik overschrijven als de gebruiker niet in ingelogd. Op dit moment krijg ik namelijk nog een 'Class 'loginModel' not found' error omdat de $_GET['component'] nog op een andere component staat. Hierdoor zoekt de autloader de bestanden voor het login formulier in de foute map.
Weet iemand een methode dit voor elkaar te krijgen?

Alvast bedankt!

Groeten,
Niels
Gewijzigd op 01/05/2015 09:29:07 door Niels Veer
 
PHP hulp

PHP hulp

21/06/2024 18:56:33
 
Frank Nietbelangrijk

Frank Nietbelangrijk

01/05/2015 11:44:37
Quote Anchor link
Oei, hier gaat iets fout.

Een autoloader is enkel bedoeld om classes / libraries (die in een eigen .php bestand staan) automatisch te includen zodat je niet elke keer een include regel hoeft toe te voegen. Daarnaast gaat een autoloader hand in hand met namespaces. Ik stel dan meteen voor om de psr0 standaard te gebruiken. Leesvoer: http://www.sitepoint.com/autoloading-and-the-psr-0-standard/
Gewijzigd op 01/05/2015 11:49:20 door Frank Nietbelangrijk
 
Thomas van den Heuvel

Thomas van den Heuvel

01/05/2015 12:29:58
Quote Anchor link
Daarnaast nog wat aantekeningen over autoloaders in het algemeen:
- er wordt afgeraden __autoload() te gebruiken, gebruik in plaats hiervan spl_autoload_register()
- alle diskoperaties (zoals file_exists) zijn relatief duur, daarnaast moet je er van uit kunnen gaan dat de bestanden bestaan, en anders moet je dit met foutafhandeling ondervangen, maar vermijd het gebruik van disk operaties in je autoloader!
- de volgorde van het zoeken naar classes kun je beinvloeden door de volgorde van de uitgangspaden-voor-invoegen te veranderen via set_include_path();

Ik weet niet of dit in het bovenstaande geval de beste / juiste oplossing is maar stel bijvoorbeeld dat je een opensource product hebt waarin je dingen wilt aanpassen. Je hebt dan wel meteen een probleem als er een upgrade uitkomt als je in de core hebt lopen hacken, mogelijk krijg je dan conflicten. Wat je zou kunnen doen is classes met aanpassingen (als het een OOP systeem is) in een aparte directory zetten die eerst geinspecteerd wordt. Zo kun je dus code overriden zonder de core-bestanden aan te passen.

Een super simpele autoloader ziet er bijvoorbeeld als volgt uit:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
// shorthands
define('__DS', DIRECTORY_SEPARATOR);
define('__PS', PATH_SEPARATOR);

// stel volgorde van laden in - eerst custom, dan core, dan de rest
set_include_path(MY_CUSTOM_PATH.__PS.MY_CORE_PATH.__PS.get_include_path());

// autoloader
function my_autoloader($class) {
    spl_autoload(strtr($class, '_', __DS));
}

// vanaf PHP 5.3.0 kun je ook een anonieme functie gebruiken
spl_autoload_register('my_autoloader');
?>

Bovenstaand voorbeeld werkt overigens met underscores, niet met namespaces.

Maar goed, als je autoloader te lang wordt en/of je allerlei disk operatie achtige functies aan het uitvoeren bent is dit een redelijk indicatie dat je verkeerd bezig bent :). Autoloaders zouden simpel moeten zijn.
 
Niels Veer

Niels Veer

01/05/2015 13:41:56
Quote Anchor link
Ik ben nog maar pas begonnen met het daadwerkelijke OOP. Dit is eigenlijk mijn eerste poging tot het schrijven van zo een systeem. Erg leerzaam tot nu, alleen lastig omdat ik dus niet weet of ik het enig zins goed doe.

@Frank bedankt voor de link, als ik tijd heb zal ik het eens aandachtig doorlezen.
Zie alleen nu al dat mijn file structuur totaal niet zo is opgebouwd. Dus ik heb nog wat te doen denk ik zo.
Wat ik nu heb is zo:
components
- com_page
-- controller.php
-- model.php
-- view.php
-- output.php
layout
- layout.php
- libraries
-- paf
--- class.databaseconnection.php
--- class.error.php
--- class.layout.php
config.php
index.php

@Thomas oke, het is me nu veel duidelijker hoe een autloader zou moeten werken. Nu is het in dit geval niet van belang dat bepaalde bestand overschreven kunnen worden, meer dat er eerst gezocht wordt in de libraries map en daarna in de components map. Zou in wezen hetzelfde principe moeten zijn toch?

Over je code had ik ook nog een vraagje, werkt spl_autoload() in weze hetzelfde als een include_once of iets dergelijks?
 
Thomas van den Heuvel

Thomas van den Heuvel

01/05/2015 14:09:40
Quote Anchor link
Hm, het is denk ik meer een voorschrift van een "mapping" van een klassenaam naar een fysieke locatie.

spl_autoload() "include" zelf niets, maar als je ergens in je code een object van een klasse X aanmaakt dan worden je geregistreerde functies doorlopen en daarmee wordt getracht om met behulp van je "mapping" het correcte bestand te vinden (als ik het allemaal goed begrepen heb :)).

Je klasses worden hiermee ook pas "geinclude" als je ze gebruikt, je include dus precies wat je gebruikt. Niet teveel, en niet te weinig.
 
Frank Nietbelangrijk

Frank Nietbelangrijk

01/05/2015 18:04:22
Quote Anchor link
Niels van der Veer op 01/05/2015 13:41:56:
Zie alleen nu al dat mijn file structuur totaal niet zo is opgebouwd. Dus ik heb nog wat te doen denk ik zo.


Met namespaces en autoloading is eigenlijk elke mappenstructuur mogelijk.

Jouw controller class zit in de components map.

Je namespace kan dan Components zijn.
Stel dat je controller class gebruik wil maken van de model class dan krijg je zoiets:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
<?php

namespace Components;

use Components\Model;

class Controller {
    function
__construct() {
        $this->model = new Model();
    }
}


?>

Persoonlijk zou ik je wel willen aanraden om:
- class namen met een hoofdletter te laten beginnen
- de .php bestanden dezelfde naam te geven als de classes, inclusief de hoofdletter
Bijv:
- BaseController
- Validator
- EmailValidator
etc

variabelen begin je altijd met een kleine letter.
Bijv:
- $controller
- $validator
- $emailValidator
 
Niels Veer

Niels Veer

01/05/2015 20:53:52
Quote Anchor link
Bedankt voor de info!
Na wat puzzelen en proberen ben ik op het volgende uitgekomen. Is dat een beetje wat het idee is?
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
// shorthands
define('__DS', DIRECTORY_SEPARATOR);
define('__PS', PATH_SEPARATOR);
define('APPLICATION_ROOT', __DIR__);

// stel volgorde van laden in - eerst custom, dan core, dan de rest
set_include_path(APPLICATION_ROOT . "\components" . __DS . __PS . APPLICATION_ROOT . "\libraries\paf" . __DS);

// autoloader
function my_autoloader($class) {
    spl_autoload($class);
}

// vanaf PHP 5.3.0 kun je ook een anonieme functie gebruiken
spl_autoload_register('my_autoloader');

echo get_include_path();

$page = new Components\Page\PageModal::display();
echo $page->display();
?>


Ik zie zelf alleen een nadeel hieraan.
Naar mijn idee is het nu niet helemaal zoals het zou moeten zijn, met mij vorige manier kon ik namelijk het volgende:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
<?php
$db
= new DatabaseConnection;
$db->query("SELECT * FROM users");
$result = $db->excecute();
?>

Om dit nu te kunnen zou ik veel langere classes krijgen...
Of zie ik dat fout?
Gewijzigd op 01/05/2015 20:54:12 door Niels Veer
 
Frank Nietbelangrijk

Frank Nietbelangrijk

01/05/2015 21:04:43
Quote Anchor link
Langere class namen bedoel je? Ja dat klopt maar dat zorgt er dan wel voor dat in een groot project niet stuk loopt. je kunt gewoon meerdere klassen met dezelfde naam hebben dankzij de namespaces.

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
<?php
$db
= new DatabaseConnection;
$db->query("SELECT * FROM users");
$result = $db->excecute();
?>


wordt dan dit:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
<?php

namespace ....;

use Components\DatabaseConnection;

$db = new DatabaseConnection;
$db->query("SELECT * FROM users");
$result = $db->excecute();
?>


of:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
<?php

namespace ....;

$db = new \Components\DatabaseConnection;
$db->query("SELECT * FROM users");
$result = $db->excecute();
?>


even oppassen met standaard PHP classen trouwens:

$date = DateTime();

moet nu worden:

$date = \DateTime();
 



Overzicht Reageren

 
 

Om de gebruiksvriendelijkheid van onze website en diensten te optimaliseren maken wij gebruik van cookies. Deze cookies gebruiken wij voor functionaliteiten, analytische gegevens en marketing doeleinden. U vindt meer informatie in onze privacy statement.