Reputation: 1877
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
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).
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.
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.
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