ClassLoader

Gepost door Jasper Lammertink op 05-03-2009 20:33.

Een autoloader met caching.
Roep de ClassLoader aan aan het begin van elk script waarin je hem wilt gebruiken.

<?php
require_once 'pad/naar/je/ClassLoader.php';

// root van je applicatie
define('PATH_ROOT', realpath(dirname(__FILE__).'/../../..').'/');

// wel of geen caching gebruiken
ClassLoader::useCaching(true);

// overige instellingen die altijd nodig zijn
// ** het is denk ik wel duidelijk wat de methods vertellen aan de ClassLoader
ClassLoader::setCachePath(PATH_ROOT.'cache/cache.php');
ClassLoader::addClassPath(PATH_ROOT.'php/classes/');
ClassLoader::excludeFolder('/$lib^/');
ClassLoader::init();
?>

Opmerkingen/suggesties/bugs graag melden.

Bestanden van dit script

index.php

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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
<?php
class ClassLoader
{
    private static $use_caching;
    private static $cache_path;
    private static $class_paths             = array();
    private static $exclude_patterns        = array();
    private static $class_map               = array();
    private static $duplicates;


    public static function init()
    {
        self::getClassMap();

        if (self::$duplicates)
        {
            exit;
        }

        spl_autoload_register(array('ClassLoader', 'autoload'));
    }

    public static function autoload($class_name)
    {
        if (isset(self::$class_map[$class_name]))
        {
            require_once self::$class_map[$class_name];
        }
    }

    public static function useCaching($bool)
    {
        self::$use_caching = $bool;
    }

    public static function setCachePath($filename)
    {
        self::$cache_path = $filename;
    }

    public static function addClassPath($directory)
    {
        self::$class_paths[] = $directory;
    }

    public static function excludeFolder($regex)
    {
        self::$exclude_patterns[] = $regex;
    }

    private static function getClassMap()
    {
        if (self::$use_caching && file_exists(self::$cache_path))
        {
            self::$class_map = include self::$cache_path;
        }
        else
        {
            foreach (self::$class_paths as $class_path)
            {
                self::$class_map = array_merge(self::$class_map, self::scanDirectory($class_path));
            }

            if (self::$use_caching && !self::$duplicates)
            {
                self::writeCache();
            }
        }
    }

    private static function scanDirectory($directory)
    {
        $class_map = array();

        foreach (scandir($directory) as $filename)
        {
            if ($filename != '.' && $filename != '..')
            {
                if (is_dir($directory.$filename))
                {
                    $exclude = false;

                    foreach (self::$exclude_patterns as $exclude_pattern)
                    {
                        if (preg_match($exclude_pattern, $filename))
                        {
                            $exclude = true;
                        }
                    }

                    if (!$exclude)
                    {
                        $class_map = array_merge($class_map, self::scanDirectory($directory.$filename.'/'));
                    }
                }
                else
                {
                    $class_name = str_replace('.php', '', $filename);

                    if (preg_match('/[class|interface] '.$class_name.'/', file_get_contents($directory.$filename)))
                    {
                        if (!isset(self::$class_map[$class_name]) && !isset($class_map[$class_name]))
                        {
                            $class_map[$class_name] = $directory.$filename;
                        }
                        else
                        {
                            self::$duplicates = true;

                            echo 'ClassLoader : <font color="#FF0000">duplicate</font> : <font color="#009900">'.$class_name.'</font> ( <font color="#0000FF">'.$directory.$filename.'</font> )<br />';
                        }
                    }
                }
            }
        }

        return $class_map;
    }

    private static function writeCache()
    {
        ksort(self::$class_map);

        $contents = '<?php'."\n".'return array(';

        $i = 0;

        foreach (self::$class_map as $class_name => $filename)
        {
            if ($i > 0)
            {
                $contents .= ',';
            }

            $contents .= "\n".'    \''.$class_name.'\' => \''.$filename.'\'';

            $i ++;
        }

        $contents .= "\n".');'."\n".'?>';

        $handle = fopen(self::$cache_path, 'w');
        fwrite($handle, $contents);
        fclose($handle);
    }
}
?>

Commentaar

05-03-2009 19:38

Een exit als er al een autoloader gedefineerd is, is rond uit vies. Dat wil je niet.

Je kan nu ook niet makkelijk meerdere libraries tegelijk gebruiken + applicaties met Poor Man Namespacing zijn zo niet te gebruiken.

1
2
3
Post hier de source-code van je script. Alle informatie tussen <? ... ?> en <?php ... ?> zal automatisch worden getoond in color-coding. 

Let op! Het is niet de bedoeling om hier een link naar je website te plaatsen. Post hier gewoon de code, veel simpeler, sneller en meer kans dat het blijft staan.
05-03-2009 20:13

Ik kan even geen logica vinden dat alles static is en een functie (init) niet.

1
2
3
Post hier de source-code van je script. Alle informatie tussen <? ... ?> en <?php ... ?> zal automatisch worden getoond in color-coding. 

Let op! Het is niet de bedoeling om hier een link naar je website te plaatsen. Post hier gewoon de code, veel simpeler, sneller en meer kans dat het blijft staan.
05-03-2009 20:24

@Tom Janssen

Dat moet natuurlijk ook een static zijn (bugje)

@iltar van der Berg

De autoloader is nog helemaal niet gedefinieerd als de exit wordt uitgevoerd.
En al zou die gedefinieerd zijn voor de exit dan maakt dat nog niets uit.
Die exit wordt ook alleen uitgevoerd als er een error optreed (duplicates).

1
2
3
Post hier de source-code van je script. Alle informatie tussen <? ... ?> en <?php ... ?> zal automatisch worden getoond in color-coding. 

Let op! Het is niet de bedoeling om hier een link naar je website te plaatsen. Post hier gewoon de code, veel simpeler, sneller en meer kans dat het blijft staan.
06-03-2009 11:32

Het duurde even maar ik heb em aan de praat...

kort gezegd, het is wellicht wel leuk voor jouzelf, maar omdat het een bepaalde (in mijn ogen ongewenste) structuur en naamgeving afdwingt, vraag ik me af wat het toepassingsniveau ervan is.
Daarnaast ben je wat vergeten te vermelden...

in de functie scandirectory zit een pregmatch -zie (1)-, waardoor je een bepaalde naamgeving afdwingt. Misschien even vermelden, ik had het niet gezien en vroeg me af waarom er niks gebeurde...

Dan nog een bug:

Ik krijg duplicates waarschuwingen terwijl ik 100% zeker weet dat het geen duplicates zijn. Het zijn verschillende Exception classes in verschillende folders met een verschillende _class_name, maar dezelfde Filename (Exception.php).
Hieruit blijkt dat je niet de classname pakt, maar de bestandsnaam....
Wat dan wel weer raar is, is dat ik nog een aantal exceptions erin heb zitten, en dat die worden overgeslagen, die zijn namelijk gewoon overschreven (alleen de laatste Exception bestaat nog).

En idd. Poor Mans Namespacing is er niet bij deze class...

1
2
3
4
(1)
<?php
if (preg_match('/[class|interface] '.$class_name.'/', file_get_contents($directory.$filename)))
?>
11-03-2009 11:13

> De autoloader is nog helemaal niet gedefinieerd als de exit wordt uitgevoerd.
> En al zou die gedefinieerd zijn voor de exit dan maakt dat nog niets uit.
> Die exit wordt ook alleen uitgevoerd als er een error optreed (duplicates).

Dan moet je een error geven, niet een witte pagina.

1
2
3
Post hier de source-code van je script. Alle informatie tussen <? ... ?> en <?php ... ?> zal automatisch worden getoond in color-coding. 

Let op! Het is niet de bedoeling om hier een link naar je website te plaatsen. Post hier gewoon de code, veel simpeler, sneller en meer kans dat het blijft staan.
11-03-2009 11:30

>> De autoloader is nog helemaal niet gedefinieerd als de exit wordt uitgevoerd.
>> En al zou die gedefinieerd zijn voor de exit dan maakt dat nog niets uit.
>> Die exit wordt ook alleen uitgevoerd als er een error optreed (duplicates).

> Dan moet je een error geven, niet een witte pagina.

Als je even verder in de code kijkt zie je dat ie dat ook doet.
Als je een Exception wil gooien moet je dat zelf even aanpassen.
Hij geeft dus geen witte pagina :-)

1
2
3
Post hier de source-code van je script. Alle informatie tussen <? ... ?> en <?php ... ?> zal automatisch worden getoond in color-coding. 

Let op! Het is niet de bedoeling om hier een link naar je website te plaatsen. Post hier gewoon de code, veel simpeler, sneller en meer kans dat het blijft staan.
24-04-2009 18:46

Met dit script, kun je makkelijk de OS laten zien van de gebruiker die de website bezoekt.

Je kan het aanroepen via:

$client_os = client_os(); print 'Uw computer draait op ' . $client_os . '<br />';

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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
<?php 

function client_os() 
{ 
    if (eregi("(win|windows)[ ]*((nt)*[ /]*([0-9]+(.?[0-9]+))*)", $_SERVER["HTTP_USER_AGENT"])) 
    { 
        if (eregi("(win|windows)[ ](95)", $_SERVER["HTTP_USER_AGENT"])) 
        { 
            return "Windows 95"; 
        } 
        else if (eregi("(win|windows)[ ](98)", $_SERVER["HTTP_USER_AGENT"])) 
        { 
            return "Windows 98"; 
        } 
        else if (eregi("(win|windows)[ ](9x)[ ](4.90)", $_SERVER["HTTP_USER_AGENT"])) 
        { 
            return "Windows ME"; 
        } 
        else if (eregi("(win|windows)[ ](NT)", $_SERVER["HTTP_USER_AGENT"])) 
        { 
            if (eregi("(win|windows)[ ](NT)[ ](5.1)", $_SERVER["HTTP_USER_AGENT"])) 
            { 
                return "Windows XP"; 
            } 
            else if (eregi("(win|windows)[ ](NT)[ ](5.0)", $_SERVER["HTTP_USER_AGENT"])) 
            { 
                return "Windows 2000"; 
            } 
            else if (eregi("(win|windows)[ ](NT)", $_SERVER["HTTP_USER_AGENT"])) 
            { 
                return "Windows NT"; 
            } 
        } 
        else 
        { 
            return "Windows"; 
        } 
    } 
    else if (stristr($_SERVER["HTTP_USER_AGENT"], "linux")) 
    { 
        return "Linux"; 
    } 
    else if (stristr($_SERVER["HTTP_USER_AGENT"], "unix")) 
    { 
        return "Unix"; 
    } 
    else if (stristr($_SERVER["HTTP_USER_AGENT"], "mac")) 
    { 
        return "MacOS"; 
    } 
    else if (stristr($_SERVER["HTTP_USER_AGENT"], "ppc")) 
    { 
        return "MacOS"; 
    } 
    else if (stristr($_SERVER["HTTP_USER_AGENT"], "HP")) 
    { 
        return "HPuX"; 
    } 
    else if (stristr($_SERVER["HTTP_USER_AGENT"], "sunos")) 
    { 
        return "SunOS"; 
    } 
    else 
    { 
        return "Unknown"; 
    } 
} 

?>
Inloggen wachtwoord vergeten? Aanmelden