webForumDet fria alternativet

Klasser och globala objekt

2 svar · 375 visningar · startad av Ramzeus

RamzeusMedlem sedan mars 200642 inlägg
#1

Jag har fram tills nyligen nästan uteslutande programmerat PHP med klassisk funktionsbaserad programmering.
Ny den senaste tiden har jag dock börjat titta på objektorienterad programmering i PHP. Främst i PHP5.

Jag håller för tillfället på med en administrationsapplikation som byggs nästan helt objektorienterat.
Allt har fungerat väldigt bra hittils och jag är ganska nöjd med de fördelar som den nya metoden innebär. Det är dock en sak som jag är lite fundersam på och som inte känns så bra, nämligen hur man gör med objekt och funktioner som är globala. Hur får man in pekarna till dessa på ett snyggt sätt i koden?

Här är ett exempel på vad jag menar:


// Här är det en del databasobjekt och andra saker som behöver vara globala
// eftersom det är flera olika klasser och funktioner som behöver använda dem.
$tpl = new Smarty();  // Templatemotor
$db = &MDB2::connect($cfg['db']['dsn']['default'], $cfg['db']['options']); // Databas

// Jag har en klass, CMS, som gör en massa saker.
// T.ex att kontrollera om en användare är inloggad och 
// tillhandahålla generella funktioner för själva administrationen.
class CMS 
{
    function __construct()
    {
        // Initiera saker...
    }

    public funtion doStufff()
    {
        // Här använder vi databasen och templatemotorn
    }
}

function specialMagicFunction()
{
    global $db, $tpl;
    // Här använder vi också databasen och templatemotorn
}

class AnotherClass 
{
    // Denna klass behöver också hantera saker i databasen
}

Min lösning på att hantera t.ex templatemotorn och databasen innuti klassen var att i konstruktorn ladda in de globala pekarna ($db och $tpl) för att sedan spara dom internt i klassen. Sedan accessas dom t.ex med $this->db och $this->tpl.

Så här kan initieringen med ovanstående metod se ut:

// Main CMS class
class CMS 
{
	private $auth=null;		// Auth handler
	private $tpl=null;		// Template handler
	private $db=null;		// Database handler
	private $cfg=null;		// Global configuration
	
	public $users=null;		// User information
	public $module=null;	// Module name

	// Init class
	function __construct($module=null, $_tpl=null, $_db=null)
	{
		global $cfg, $tpl, $db;
		if ($_tpl!==null)
			$this->tpl = $_tpl;	// Set from parameter
		else
			$this->tpl = $tpl;	// Set from global
		if ($_db!==null)
			$this->db = $_db;	// Set from parameter
		else
			$this->db = $db;	// Set from global
		$this->cfg = $cfg;
		// Init Auth
		$this->auth = new Auth($cfg['auth']['storageDriver'], $cfg['auth']['options'], 'ShowLogin');
		// Init Users
		$this->users = new UserData();

		if ($module !== null)
			$this->module = $module;
		else
			$this->module = $cfg['base']['default_module'];
		$this->tpl->assign("module", $this->module);
	}

    .......

}

Det jag undrar över är hur har ni andra löst detta? Använder ni de globala variablerna direkt i klasserna (vilket känns väldigt fel) eller hur har ni gjort?
Hur gör man liksom för att få klassen så fristående och oberoende som möjligt?

--

yos0nMedlem sedan dec. 200171 inlägg
#2

Jag har löst problemet precis som du, dvs stoppar in alla variabler objektet behöver antingen via konstruktorn eller via en set-metod efter att objektet har initialiserats. Det är väl den allmänt vedertagna lösningen när man jobbar objektorienterat. Hur som helst är globala variabler i mitt tycke aja baja, så allt är bättre än det.

Ett alternativ kan vara att använda någon sorts factory-lösning, dvs du har ett objekt vars enda uppgift är att tillhandahålla de objekt som behövs. Exempelvis har jag gjort en databasfactory, som tar emot en DSN och returnerar ett DB-objekt baserat på DSN:en.

Det fina är att factoryn håller reda på vilka objekt den har skapat: om DSN:en inte har efterfrågats tidigare skapar den ett nytt DB-objekt och sparar en referens till det objektet. Nästa gång samma DSN efterfrågas så returnerar den bara referensen, utan att skapa något nytt överflödigt objekt.

Dessutom kan man göra factoryn till en singleton, vilket gör att du slipper att skicka med en referens till factoryn i konstruktorn. I stället så kan man hämta ut factoryn direkt från dess klass, vilket blir ungefär som en global variabel, men mer i linje med den objektorienterade filosofin.

RamzeusMedlem sedan mars 200642 inlägg
#3

Aha, det var en smart lösning. Ska nog kika på det.

130 ms totalt · 3 externa anrop · v20260731065814-full.30151723
0 ms — hämta forumlista (cache)
0 ms — hämta statistik (cache)
127 ms — hämta tråd, inlägg och bilagor (db)