randy
randy

Reputation: 1877

trying to use Symfony component and having name space issues

So i am starting a new project and want to use some of the Symfony Components. I have not used name spaces before with PHP, put i am familiar with the concept from my work in java.

i have this simple piece of code and when i run it i get the error: PHP Fatal error: Class 'Symfony\Component\CssSelector\XPath\Translator' not found in /home/me/scrapes/Symfony/Component/CssSelector/CssSelector/CssSelector.php on line 52

I am thinking it my lack of knowledge of the name space thing. /home/me/scrapes/Symfony/Component/CssSelector/CssSelector/XPath/Translator.php does exist.

<?php
set_include_path('/home/me/html/inc');
require 'functions.php';
require 'Symfony/Component/DomCrawler/Crawler/Crawler.php';
require 'Symfony/Component/CssSelector/CssSelector/CssSelector.php';

use Symfony\Component\DomCrawler\Crawler;
use Symfony\Component\CssSelector\CssSelector;

$crawler = new Crawler();
$crawler->addContent('<html><body><p>Hello World!</p></body></html>');
print $crawler->filter('body > p')->text();

curl_close($ch);    

require 'cleanup.php';
?>

thanks for any help

Upvotes: 2

Views: 918

Answers (1)

Ramon Kleiss
Ramon Kleiss

Reputation: 1749

I think this is caused because, if you look in the files you required (for example Symfony/Component/DomCrawler/Crawler/Crawler.php) you'll see that those files use their own use statements (to load other classes).

Namespaces

Let's start with the namespaces. A namespace is used to easily create classes with the same name in different packages. Let's say I have a package called Foo and a package called Bar. Both packages contain a Client class that is used to do some client work (one to call the Google Maps API for example and the other to call the Facebook Graph API). Let's also assume neither of the packages uses namespaces.

If I execute the following code:

<?php
require 'Foo/Client.php';
require 'Bar/Client.php';

This is not going to work, because both packages declare a Client class. Oops, how is PHP going to know which Client class to use if you do this?

<?php
$client = new Client();

It's not going to know which Client to use, so it gives up and throws an error.

If you use namespaces (declared using the namespace keyword in PHP at the top of your file, directly below <?php) you can prevent this from happening. The Foo package can create a Client class in the Foo namespace and the Bar package in the Bar namespace. Now we can actually use both files and create a client:

<?php
require 'Foo/Client.php'
require 'Bar/Client.php'

$fooClient = new Foo\Client();
$barClient = new Bar\Client();

This will work fine.

I think you might have encountered the Foo_Client notation in older PHP libraries. This is an old way to create namespaces before PHP natively supported them.

"But", I hear you say, "it's quite cumbersome to write Foo\Bar\Baz\Client() every time I want to instantiated a class".

It is, and that's where the use keyword comes in. When using the use keyword, I can tell PHP I want to use a specific client and just use the class name, like so:

<?php
require 'Foo/Bar/Baz/Client.php'
use Foo\Bar\Baz\Client;

$client = new Client();

This will work, if you use the use Foo\Bar\Baz\Client statement, because you tell PHP "Okay, I want to use the Client class from the Foo\Bar\Baz namespace to be used when I use the Client class.

Autoloading

Now, what happens if you use a lot of different classes and you seperated them into several files (which you should do). You get a lot of different require and use statements on the top of a file. That's where autoloading comes in.

There has been a spl_register_autoloader function for quite some time in PHP. This function is used by PHP to find out which files to use when you instantiate a class that is not known because you did not require the file. This function is used both when creating a class, or, and this is the key part when you use a class.

And that's what's happening in your code. You don't have an autoloader registered that can translate the use statements in the files you required to actual class declarations.

Great, how do I fix it?

To fix it, I suggest you read up on the PHP-FIG and PSR-4. These people created standards (which you can follow but are not obliged to). To create easy to use libraries, such as the Symfony component. After you've done that, read up on Composer. After you've done this, you can drop the require statements from your code and use Composer to autoload all the classes you need.

Upvotes: 5

Related Questions