Gathering of Tweakers

Quicksearch
Hallo,

Ik ben nu bezig mijn site opnieuw op te bouwen, en ga daarvoor gebruik maken van OOP. Ik heb in mijn design plannen 6 classes staan die functies bevatten voor verschillende delen van de site.
Nu ik klaar ben met de tekeningen en programma structuur diagrammen, ben ik begonnen met het programmeren van de eerste paar testjes. Maar vrijwel direct liep ik tegen design problemen aan.

Ik heb in mijn voorbeeld 2 classes:
- scenes
- database

In de test staat deze code:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
    include 'mysqli_extended.php';
    include 'database.php';
    include 'scene.php';

        $odatabase = new database;
    $oscenenew scene;
        $db = new mysqli_extended;

    $list = $oscene->details(1);
    foreach ($list as $value)
    {
        echo $value."<br />";
    }
?>

Dan heb ik in database.php
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
<?php
class database
{
        public function column_list($type)
    {
        if ($type == 'scene')
        {
            return "
                scene_id,scene_alive,scene_ip,scene_filename,scene_size,
                scene_title,scene_author,scene_description,scene_password,
                scene_datetime,scene_rating,scene_nr_downloads,scene_nr_views,
                scene_nr_comments,scene_nr_ratings,scene_response_to,scene_last_edit,
                scene_last_edit_by 
                "
;
        }
    }
    public function fetch_details($type,$id)
    {
        if ($type='scene')
        {
            $query = $db->prepare("SELECT ".$this->column_list('scene')." FROM box_scenes WHERE scene_id = ?");
            $query->bind_param('i'$id);
            $query->execute(); 
            $query->store_result();
            $line = $query->fetch_assoc();
        }
        $query->close();
          echo "fetch flawless.";
    return $line;
    }
}
?>

En in scene.php het volgende:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
class scene
{
    public function details($scene_id)
    {
          echo "start of function details() <br />";
        $scene_array = $odatabase->fetch_details('scene',$scene_id);
                 echo "database linked in function details() <br />";
        if ($scene_array['scene_alive'] == true)
        {
            return $scene_array;
        }
        else
        {
            return false;
        }
    }
}
?>

Sorry als het een beetje op een code-dump lijkt, maar ik heb het idee dat het allemaal al zo minimaal mogelijk is nu.
Anyway, dit werkt niet, en logisch ook.


Maar wat is nu de beste manier om in elke class en elke functie toegang te geven tot de verschillende classes?

Globals moet ik ontwijken heb ik gehoord. Maar ik snap die singletons niet helemaal. Ik heb het geprobeerd maar daar kwamen ook nog steeds errors van. En daarnaast moest ik het in iedere functie opnieuw doen? Ik wil gewoon een keer in de constructor alle classes binnen slepen, maar niet meerdere objecten van dezelfde class hebben.

Ik wil bijvoorbeeld niet dadelijk 7x een db object openen.

Kan iemand me uitleggen hoe ik hier alles op orde krijg?

offtopic:
Ik weet niet zeker of dit taal-afhankelijk is, maar ik meen ooit eens gelezen te hebben dat PHP niet volledig OOP is.

A closed mind is like a closed book; just a block of wood

Laat maar, heb het probleem opgelost door rond te klooien met dubbele dubbele punten. Maar kan iemand me zeggen of de volgende oplossing goed is?

programma:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
    include 'mysqli_extended.php';
    include 'database.php';
    include 'scene.php';

    $scene =& scene::getInstance();
    $database =& database::getInstance();
    $list = $scene->details(1);
    foreach ($list as $value)
    {
        echo $value."<br />";
    }
?>

scene.php:
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
<?php
class scene
{
    // object instance
    private static $instance;
    private static $database;

    public static function getInstance() 
    {
        if (!scene::$instance instanceof self
        {
            scene::$instance = new self();
            scene::$database =& database::getInstance();
        }
        return scene::$instance;
    }
    public function details($scene_id)
    {
        echo "start of function details() <br />";
        $scene_array = scene::$database->fetch_details('scene',$scene_id);
        echo "database linked in function details() <br />";
        if ($scene_array['scene_alive'] == true)
        {
            return $scene_array;
        }
        else
        {
            return false;
        }
    }
}
?>

database.php:
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
<?php
class database
{
    // object instance
    private static $instance;
    private static $db;

    public static function getInstance() 
    {
        if (!database::$instance instanceof self
        {
            database::$instance = new self();
            database::$db = new mysqli_Extended('localhost','deb10784_phunbox','desk270jet','deb10784_phunbox'); 
        }
        return database::$instance;
    }
    public function column_list($type)
    {
        if ($type == 'scene')
        {
            return "
                scene_id,scene_alive,scene_ip,scene_filename,scene_size,
                scene_title,scene_author,scene_description,scene_password,
                scene_datetime,scene_rating,scene_nr_downloads,scene_nr_views,
                scene_nr_comments,scene_nr_ratings,scene_response_to,scene_last_edit,
                scene_last_edit_by 
                "
;
        }
    }
    public function fetch_details($type,$id)
    {
        if ($type='scene')
        {
            $query = database::$db->prepare("SELECT ".database::$instance->column_list('scene')." FROM pbox_scenes WHERE scene_id = ?");
            $query->bind_param('i'$id);
            $query->execute(); 
            $query->store_result();
            $line = $query->fetch_assoc();
            return $line;
        }
        $query->close();
        echo "fetch flawless.";
        return $line;
    }
}
?>

Het lijkt mij best proper, maar ik hoor het graag als het beter kan! Ben van plan deze zomer eens goed in PHP te duiken :)

A closed mind is like a closed book; just a block of wood

Database.php, regel 19, moet dubbele = zijn ;)

Bezoek mijn blogje eens ;)
<Jungian> M'n Acer heeft eindelijk 2 GB RAM!
<Jungian> Nu kan ik Starcraft spelen zonder dat Vista begint te swappen

Lágrimas negras

Waarom maak je $database een static property van scene? Waarom vind ik maar één keer $this in je hele source code? Dat lijkt me niet echt een goed teken. Het geheel is gewoon slecht ontworpen. Dat blijkt alleen al uit het feit dat je drie classes zonder parameters instantieert.

De scene class zou sowieso ofwel een constructor moeten hebben waaraan je $database meegeeft, of een losse functie waarmee je $database doorgeeft. Die scene class moet dan voor instanties die database class in een property opslaan. En dan dus géén static property, maar bijvoorbeeld $this->database.

En gebruik hoofdletters voor je klassenamen. Waarom doe je dat niet? Is dat een gevalletje "ik vind dat niet zo mooi staan"?

Als je echt object geörienteerd wilt leren programmeren doe je er beter aan bijvoorbeeld Visual C# 2008 Express Edition te installeren en daarmee aan de gang te gaan. Daarmee heb je meteen een heel aantal basisclasses waar je veel beter mee leert programmeren dan met zelfgebakken classes vanaf scratch.

Volgens mij is dit weer typisch een voorbeeld van eigenlijk nog niet toe zijn aan het bouwen van applicaties. Je mist simpelweg de basics, maar wilt al wel meteen iets compleet werkends maken.

Over troubled waters memories soar endlessly, searching night and day.
The moonlight caresses a lonely hill with the calmness of a whisper

#cheatah: Wat bedoel je met
quote:
Dat blijkt alleen al uit het feit dat je drie classes zonder parameters instantieert.
? Als ik geen parameters nodig heb dan heb ik die toch niet nodig? Er komt nog veel meer bij, dus een constructor komt er nog wel, met parameters. Maar eerst moet ik een basis hebben staan.

Inderdaad vind ik zaken zoals dit
code:
1
database::$db->prepare(....)

Vervelend, maar hoe zorg ik er dan voor dat het weer gewoon "$db" word, of "$this->$db"?

A closed mind is like a closed book; just a block of wood

quote:
link0007 schreef op donderdag 24 juli 2008 @ 21:33:
#cheatah: Wat bedoel je met

[...]

? Als ik geen parameters nodig heb dan heb ik die toch niet nodig? Er komt nog veel meer bij, dus een constructor komt er nog wel, met parameters. Maar eerst moet ik een basis hebben staan.

Inderdaad vind ik zaken zoals dit
code:
1
database::$db->prepare(....)

Vervelend, maar hoe zorg ik er dan voor dat het weer gewoon "$db" word, of "$this->$db"?

PHP:

1
2
3
4
5
6
7
<?php
class Scene {
    protected $db;

    public function __construct(Database $db) {
        $this->db = $db;
    }
}
?>

Oftewel lees je even in in de programmeertaal die je gebruikt... Waarom zou je van al die classes maar 1 instance willen hebben trouwens? Volgens mij moet je je toch echt beter inlezen in OO design en programmeren.

If I can't fix it, it ain't broken.

Berichten: 198
Reg. datum: 28 augustus 2006

Wat je nu doet is nog procedureel programmeren, alleen dan met de procedures in classes gestopt en daarna om 'beperkingen' van die vorm heen werken (singletons gebruiken als een verkapte global maar dan binnen een class zelf). Dat maakt het geen OOP.

Het gebruiken van een singleton voor een database connectie vind ik dan nog geen slecht idee, als je als doel hebt om ook maar 1 open connectie naar je database toe te staan (maar doet die mysqli_extended class dat al niet?).

Als advies: je moet eens goed nadenken over wat jouw class scene allemaal moet doen en of die class database wel nodig is.

Je kan om te beginnen dit doen:
- ga na welke eigenschappen een 'scene' heeft, zet die als property in de class. Zoals het nu is, staan ze in een array die jouw functie fetch_details teruggeeft, heeft zo dus geen relatie met een specifiek Scene object...
- ga na hoe je die eigenschappen kan invullen als je een nieuwe instance van die class maakt. Ga je parameters via de constructor meegeven? Maak je functies daar voor? Heb je hier een functie nodig die het object vult vanuit de database?
Voorbeeld:
PHP:

1
<?php
public function fetchSceneFromDatabase$db$sceneId )
?>

- welke bewerkingen kan je op een scene toepassen? Maak daar (relevante) functies voor in de class.
- kan je de scene ook weer opslaan in de database? Nog een functie van de class Scene.
- aanleren om fatsoenlijke foutafhandeling te gebruiken.

Ik zou in eerste instantie de array met velden voor een scene uit die class database halen en naar de class Scene zelf verhuizen. Als je meer onder de knie hebt van OOP en wat patterns daarvan kan je later altijd nog naar een volwaardige 'data abstraction layer' gaan (indien nodig).
 
Bedankt voor de opbouwende post :)

Het is inderdaad waar dat OOP voor mij enorm lastig lijkt nu.. Ben al jaren gewent aan pascal, en daar ging object oriented programmeren niet echt mee.

De applicatie die ik ga maken is in principe vergelijkbaar met iets als youtube. Dit is zoals de site nu is: http://www.phunbox.net/

De nieuwe site zal dan wel meer features hebben (gebruikers etc), maar kwa opbouw zal het er veel op lijken.

Daarom heb ik in mijn tekeningen deze classes bedacht:

- scene
- database
- backend
- user
- comment
- administration

Wat ik uiteindelijk wil, is dat ik de hele site opnieuw kan schrijven, op een manier die me beter instaat stelt dingen aan te passen, nieuwe dingen toe te voegen.. Een modulair ontwerp zeg maar.

Wat ik nu heb kwa functies in bijvoorbeeld scene is het volgende (komen nog wel meer bij.. maar deze zijn al geprogrammeerd):

new_scene($scene_file,$scene_title,$scene_author,$scene_description,$scene_password,$scene_response_to)
edit($scene_id,$scene_file,$scene_title,$scene_last_edit_by,$scene_description,$password)
details($scene_id)
delete($scene_id)
revive($scene_id)

Waar het OOP vooral naar voren komt is bijvoorbeeld bij de functie "new_scene":
PHP:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
    public function new_scene($scene_file,$scene_title,$scene_author,$scene_description,$scene_password,$scene_response_to)
    {
        $scene_id = scene::$database->new_id('scene');
        $scene_ip = scene::$backend->get_ip();
        if (scene::$backend->check_ban($scene_ip) == false)
        {
            $scene_filedetails = scene::$backend->file_upload($scene_id,$scene_file);
            scene::$database->add_scene
                        (
                            $scene_id,
                            $scene_ip,
                            $scene_filedetails['name'],
                            $scene_filedetails['size'],
                            $scene_title,
                            $scene_author,
                            $scene_description,
                            $scene_password,
                            $scene_response_to
                        );
        }
        return true;
    }
?>

Hier vind ik het mooi dat ik snel bepaalde functies kan aanroepen, bijvoorbeeld om te kijken of de persoon die een scene wil uploaden niet gebant is.


In feite zal er dus nooit meer dan 1 object van elke class hoeven te bestaan in een script.


Heb ik hier echt wel nut van OOP? Of kan ik beter gewoon een stapel includes maken met functies erin?

A closed mind is like a closed book; just a block of wood



© 1998-2008 Tweakers.net BV - Based on React - Hosted by True - Served by Aphaea

© 1998-2008 Tweakers.net BV - Based on React - Hosted by True - Served by Aphaea

[RSS][XML]

Update Tracker

Active Topics
Active Topics
Frontpage Nieuws
Frontpage Nieuws