Unloading a class

Is it possible to unload a class? If so, what’s the keyword?

Why would you ever want to do such a thing?


$o = new object();
$o = null;

There you go. Once all references to the object are removed its gone.

The class definition would still exist though…

I’m using two versions of a class that was provided by a vender that may not have intended that they be used together. I’ve requested clarification. In the meantime, I thought it might be possible to unload/unload the versions with code.

Is it possible to rename a class after it’s loaded?

My suggestion would be to ever so slightly alter the vendor code to wrap it in namespaces.

I looked at the manual. If I understand it correctly, there’s a way to encapsulate the require statements so they can still be used in this code. How do I use example #1 at http://www.php.net/manual/en/language.namespaces.rationale.php to encapsulate the require statements in this code?

<?php
require('BCGColor.php');
require('BCGDrawing.php');
require('BCGqrcode.barcode2d.php');

// QRCode Part
$code = new BCGqrcode();
$code->setScale(4);
$code->setErrorLevel(1);
$code->parse('Code 2D!');

// Drawing Part
$color_black = new BCGColor(0, 0, 0);
$color_white = new BCGColor(255, 255, 255);
$drawing = new BCGDrawing('', $color_white);
$drawing->setBarcode($code);
$drawing->draw();

header('Content-Type: image/png');

$drawing->finish(BCGDrawing::IMG_FORMAT_PNG);

?>

I couldn’t find where the manual demonstrated wrapping a namespace around a require statement. Nonetheless, I gave it a try, but it didn’t seem to work.

You’ll probably have to open each of the vendor files and at the top, add a line similar to this:

namespace VendorName\LibraryName\VersionX;

Another approach:


require('BCGColor.php'); 
require('BCGDrawing.php'); 
require('BCGqrcode.barcode2d.php');

namespace VendorName\\BCGColor\\v1;
{
    class VendorColor extends BCGColor
    {
    }
    class VendorDrawing extends BCGDrawing
    {
    }
    class VendorQRCode extends BCGqrcode
    {
    }
}

You would then use new VendorColor(), etc in your code instead of BCGColor, etc.

Assuming the vendor classes are not marked as final

Well… almost. Actually you would have VendorColor in addition to BCGColor. The reason that distinction is important is because we would still need to load a different version of the same library, and if that different version tries to re-declare classes, such as BCGColor, then PHP will throw a parse error.

Wouldn’t you load them under two different namespaces?

require('BCGColor.php');  
require('BCGDrawing.php');  
require('BCGqrcode.barcode2d.php'); 

namespace VendorName\\BCGColor\\v1; 
{ 
    class VendorColor extends BCGColor 
    { 
    } 
    class VendorDrawing extends BCGDrawing 
    { 
    } 
    class VendorQRCode extends BCGqrcode 
    { 
    } 
} 
require('BCGColor2.php');  
require('BCGDrawing2.php');  
require('BCGqrcode.barcode2d2.php'); 

namespace VendorName\\BCGColor\\v2; 
{ 
    class VendorColor extends BCGColor 
    { 
    } 
    class VendorDrawing extends BCGDrawing 
    { 
    } 
    class VendorQRCode extends BCGqrcode 
    { 
    } 
} 

And then you could use both

$version1 = new VendorName\\BCGColor\\v1\\VendorColor();
$version2 = new VendorName\\BCGColor\\v2\\VendorColor();

cpradio’s method will work unless you do need two variants of the class loaded at the same time. You won’t be able to define two different instances of the class with the same name.

Another (hacky way) would be to load a file into a namespace:


function loadIntoNamespace($file, $namespace) {
	eval('namespace ' . $namespace . '; ?>' . file_get_contents($file));	
}


loadIntoNamespace('BCGColor.php', 'Version1');
loadIntoNamespace('BCGColor.2.php', 'Version2');

$v1instance = new Version1\\BCGColor();
$v2instance = new Version2\\BCGColor();

Really, this should be included functionality in the language as it is useful at times. Especially in the transitional period between never having namespaces available and older code not using them and transitioning into new code which uses them.

That is a neat approach.

It works, certainly. But I wouldn’t recommend it unless there’s no other way. Any debugging information from the included files will display errors on lines in eval()'d code, making it hard to track down where notices/warnings/exceptions are coming from.

The problem is PHP will throw a parse error at your second set of require statements, because they would be re-declaring classes that were already declared in the first set of require statements.

Oh, yeah, I guess they would. I keep forgetting that about PHP and working with Third Parties (as namespaces aren’t required).