(codeigniter/Neo4j) PHP : namespace and autoloader - php

As i'm trying to install the Neo4jPHP library in codeigniter (v2.2.x), i'm having annoying issues regarding namespaces. I've been searching for 4 hours without success.
In short, there is a libraries directory in which Neo4jPHP must be copied. So in 'libraries/', there is a directory 'Everyman/Neo4j/', which contains all the Neo4j php classes.
Also, in the same 'libraries' directory, there is a class with an autoloader function, which aims at loading the Neo4j classes (which are in 'Everyman/Neo4j/').
Inside of 'libraries'
- libraries/
|-- Everyman/
|-- Neo4j/
|-- Client.php
|-- some_other_classes.php
|-- Neo4j.php
Then, somewhere in my code, in the global namespace, i try to instantiate the class client :
$client = new Client();
But i get the error Class 'Client' not found.
In the class client, the following namespace is specified : Everyman\Neo4j.
I'm must admit that i found 2 workarounds for this issue :
From the calling code, use the fully qualified name :
new Everyman\Neo4j\Client();
Or, in Client.php, remove the namespace.
In these 2 cases, it works. However, i would like to call the Client class with these 2 condition :
1. I don't want to modify anything from the Neo4jPhp library.
2. I really don't want to have to use the fully qualified name (Everyman\Neo4j\Client). I want to use "new Client()".
Do you guys have an idea how i could achieve this (yes, i don't have a very deep understanding of namespaces, and loaders).
In Neo4j.php (file with loader)
<?php
class Everyman{
public function __construct()
{
spl_autoload_register(array($this,'autoload'));
}
public function autoload($sClass){
$sLibPath = __DIR__.DIRECTORY_SEPARATOR;
//Below, i modified the instruction so that the class file
//can be found. However, the class is not found.
$sClassFile = 'Everyman'.DIRECTORY_SEPARATOR.'Neo4j'.str_replace('\\',DIRECTORY_SEPARATOR,$sClass).'.php';
$sClassPath = $sLibPath.$sClassFile;
if (file_exists($sClassPath)) {
require($sClassPath);
}
}
}
So that's it. I think i've given you all the information i have. If no one can help me, i'll have to use 'new Everyman\Ne4j\Client();' (which works).
It may seem stupid to ask for help, as i already have found 2 workarounds, but i really want to learn how to properly handle this issue (if possible).
Thanks.

It seems code like $client = new Everyman\Neo4j\Client('localhost', 7474); is the offical usage: https://github.com/jadell/neo4jphp#connection-test
So it is not work around.
I really don't want to have to use the fully qualified name (Everyman\Neo4j\Client). I want to use "new Client()".
I don't know what you really want. But then how about putting the code below in your code which you use Everyman\Neo4j\Client:
use Everyman\Neo4j\Client;
and
$client = new Client();
See http://php.net/manual/en/language.namespaces.importing.php

The supported way of installing neo4jphp is using Composer (https://getcomposer.org/). It is a good idea to learn how to use Composer, since a large number of PHP libraries can be installed using it. It also sets up the autoloading for you, so you don't have to worry about paths and namespaces yourself.
If you don't want to write new Everyman\Neo4j\Client() every time, you can put a use statement at the top of your script: use Everyman\Neo4j\Client; and then new Client();

Thank you for your answers.
For some reason, the 'use Everyman\Neo4j\Client' command didn't work, and i decided not to perform further inquiry into this issue.
So i decided to stick with the call to '$client = new Everyman\Neo4J\Client();', instead of trying to achieve '$client = new Client();'.
Thank you for your propositions.
Loïc.

Related

Php 7.4.3 Class not found

This is my project path configuration
./create.php
/Install/Install.php
create.php
<?php
use Install\Install;
echo "Starting";
$install = new Install();
This gives me the error
PHP Fatal error: Uncaught Error: Class 'Install\Install' not found in /project/create.php:6
Install.php
<?php
namespace Install;
class Install
{
//whatever
}
Can someone explain me what is happening there ?
Obviously I guess that using a require_once line with my filename would probably fix the issue...but I thought using namespace and use import could prevent me from doing that like we do in classic framework like symfony / magento ?
I've seen some post speaking about autoloading, but i'm a little bit lost. Haven't been able to find a clear explanation on the other stack topic neither.
PHP compiles code one file at a time. It doesn't have any native concept of a "project" or a "full program".
There are three concepts involved here, which complement rather than replacing each other:
Namespaces are just a way of naming things. They allow you to have two classes called Install and still tell the difference between them. The use statement just tells the compiler (within one file) which of those classes you want when you write Install. The PHP manual has a chapter on namespaces which goes into more detail on all of this.
Require and include are the only mechanisms that allow code in one file to reference code in another. At some point, you need to tell the compiler to load "Install.php".
Autoloading is a way for PHP to ask your code which file it should load, when you mention a class it hasn't seen the definition for yet. The first time a class name is encountered, any function registered with spl_autoload_register will be called with that class name, and then has a chance to run include/require to load the definition. There is a fairly brief overview of autoloading in the PHP manual.
So, in your example:
use Install\Install; just means "when I write Install, I really mean Install\Install"
new Install() is translated by the compiler to new Install\Install()
the class Install\Install hasn't been defined; if an autoload function has been registered, it will be called, with the string "Install\Install" as input
that autoload function can then look at that class name, and run require_once __DIR__ . '/some/path/Install.php';
You can write the autoload function yourself, or you can use an "off-the-shelf" implementation where you just have to configure the directory where your classes are, and then follow a convention for how to name them.
If you want to Use class from another file, you must include or require the file.
Use require('Install.php'); before use Install\Install;.
If you are planning to do a big project I would recommend to use PHP frameworks rather than coding from scratch.

Trying to add a library to Symfony using composer

I am trying to add the following library (link) to my Symfony project using composer.
I have run
composer require jaggedsoft/php-binance-api
without a problem but I am getting the following error when loading the page.
Attempted to load class "API" from namespace "App\Controller\Binance".
Did you forget a "use" statement for another namespace?
public function index(){
require '../vendor/autoload.php';
$api = new Binance\API("<api key>","<secret>");
}
Now i am guessing that I need to add a use statement but I am a bit stuck on what it is that I need to add.
To reiterate what I suggested in the comments (options 1 and 3 below):
The namespace of your file - although not explicitly written in your post - is:
App\Controller
without any use statement, the new Binance\API(...) is interpreted as:
App\Controller\Binance\API
which is the concatenation of App\Controller (your namespace) and Binance\API (the classname used).
which of course is not what you want to use, since this is something you tried to include from the binance package. This also explains the error message
Attempted to load class API from namespace App\Controller\Binance. Did you forget a use statement for another namespace?
which is exactly what went wrong. PHP tried to load App\Controller\Binance\API which is class API from namespace App\Controller\Binance.
Now there are A few different ways to fix this:
add use Binance; in the header of your file, then you can use new Binance\API(...)
add use Binance\API; in the header of your file, then you can use new API(...)
don't add a use statement, then you can use new \Binance\APi(...)
add use Binance as Something; in the header of your file, then you can use new Something\API(...); (aliasing the parent namespace Binance as Something may resolve name collisions)
add use Binance\API as BinanceApi; in the header of your file, then you can use new BinanceApi(...);
You decided to use option 1. Which is preferable, if the class (API in this case) isn't very expressive or unique on its own - so is option 5. However, if you use more classes from the Binance namespace, option 1 is preferable.
Option 3 will always work (and might seem preferable if any of the other options seem overkill for some reason) - you can actually get by without any use statement at all, but it can get frustrating to read and write.
Overall, all options are viable and it comes to taste which one to use. Mixing those options may lead to confusion. Inside Symfony I've mostly seen option 2 with the occasional alias (use ... as ...;), especially when using DoctrineORM annotations or when extending some Class which has the same Class name but in a different namespace:
namespace [package1];
use [package2]\[ClassName] as Base[ClassName];
class [ClassName] extends Base[ClassName] { ... }
I hope this explanation helps. The php docs for namespaces are actually helpful, when you understand the core concept of namespaces.

In yii2, how do I autoload my own PHP classes?

Inside my Controller I want a function to use mpdf e.g.
public function actionPdf(){
include("MPDF57/mpdf.php");
$mpdf=new mPDF('c');
$mpdf->SetDisplayMode('fullpage');
$mpdf->WriteHTML("<h1>Hello World!</h1>");
$mpdf->Output('filename.pdf', 'F');
}
}
This does not work, and throws an error:
Class 'app\controllers\mPDF' not found
What should I do If I want to autoload the class
(a). Just for this Controller Action
(b). To make it usable everywhere just by using the use statement.
I know it has to do something with namespaces but don't know how do I define a namespace, and where do I place this MPDF57 folder and then make it accessible.
I also tried this :
$name = "MPDF57/mpdf.php";
spl_autoload_register(function ($name) {
var_dump($name);
});
But this didn't work either. throws the same error when I call my controller Action.
Here is the namespace declaration and use statements inside :
namespace app\controllers;
use Yii;
use app\models\Regs;
use app\models\Voters;
use app\models\RegsSearch;
use yii\web\Controller;
use yii\web\NotFoundHttpException;
use yii\filters\VerbFilter;
use \yii\web\Response;
use yii\helpers\Html;
use kartik\mpdf\Pdf;
Yii has already had autoloader, you do need nothing to load your class.
Just create your class with correct namespace and it will be loaded where are you using it only.
Namspace should represent real path to PHP file. PHP file name and class name should be same.
You should simply use mpdf/mpdf package :
Install it using composer :
composer require "mpdf/mpdf" ">=6.0.0"
Use it like this :
$mpdf = new \mPDF();
Or you can use a yii2 extension like this one : https://github.com/kartik-v/yii2-mpdf
I've faced such problems in one of my previous projects. I'm not good at PHP or Yii2 - so follow my guide on your own risk :)
When you you add use path\to\ExternalLibrary that means the interface is ready to use inside current class (e.g. CurrentController.php).
That means your application knows how to bring your path to it's stage.
E.g. use common\models\Post lets you directly to use Post class, as $posts = new Post;
So if your library contains only one file, just put is some "canonic" path. To common\models\ for example. So you can use it like any other model interface.
But for sake of your project put it on vendor folder. Then install a random library with composer. And observe which files are modified (1-3 generally). Also try to understand the modification logic. When you get sure that you've grasped everything, copy and paste these parts and change the paths, names, etc. for your library.
The best way, I think, is to make your library PSR-4 compatible and ship it as a PHP package. Thus, others can also benefit from your work.
There are lots of guides about making php packages.
http://sitepoint.com/starting-new-php-package-right-way/
https://knpuniversity.com/screencast/question-answer-day/create-composer-package
http://jessesnet.com/development-notes/2015/create-php-composer-package/
http://culttt.com/2014/03/12/build-php-package/
If you are planning to be a good PHP developer, I recommend to look up Josh Lockhart's "Modern PHP: New Features and Good Practices" book ( free pdfs are available :) ). That will help you to understand the fundamentals of OO PHP including namespaces, interfaces etc. So, you will be able to handle such problems in modern way.

How to load classes in php

I need to understand how to load classes in php. I want to access classes methods by instantiate the class only with its name, for example:
$foo = new Foo();
$foo->method();
And not like this:
$foo = new \Class\Bar\Foo();
I'm in a Symfony 2.7 environment.
Thanks in advance!
EDIT
My bad, I should have specified that I'd like to use classes like this in the whole project, not only in a few files.
You should use those classes (i.e. import them) like:
use strrife\MyBundle\Entity as Entity;
...
$e = new Entity();
The official docs can be found here.
PS
If you're using some IDE (for example, PHPStorm which personally I highly recommend), then, when you type Entity and this class wasn't imported yet, it gives you a list of options to import that class from.
EDIT
You shouldn't do that.
Importing the classes like that in the entire project is actually a bad idea because that might cause naming conflicts (and probably will if you'd like to do that for Symfony classes).
As a workaround for your project classes you can add a few lines to composer.json specifying the autoload paths to all your project folders.
You can also:
put all your entities to one single folder (very bad)
or write a custom __autoload() function that would iterate through files and folders searching for your class (docs), but it'd bring the same problems + some performance issues.
But I highly discourage you from doing that because... well, namespaces bring order and structure and you're likely to end up with class redeclarations.

include external lib in laravel?

how to include external lib in laravel ? for example twitteroauth.php.
no need oauth other packages. because i am converting Symfony code to Laravel. Thanks.
Class 'App\Controllers\Front\TwitterOAuth' not found
.
require_once base_path().'/vendor/twitter/twitteroauth.php';
$twitterOAuth = new TwitterOAuth('app_twitter_consumer_key', 'app_twitter_consumer_secret');
Likely you have a namespace problem, Laravel is looking for the class inside the 'App\Controllers\Front' namespace.
If the class is not namespaced, use
$twitterOAuth = new \TwitterOAuth('app_twitter_consumer_key', 'app_twitter_consumer_secret');
(note the backslash before the classname)
otherwise you need to refer to its namespace, something like \Twitter\TwitterOAuth or similar, but only by looking at the class file you can tell.
You could also create an alias for the class. Inside the app\config\app.php file search for the aliases array and add your class:
'Twitter' => 'TwitterOAuth' #(or whatever namespace it's in)
By the way, why not using a specific package? Have you looked on http://packagist.org to see if there's a Twitter OAuth package already adapted for Laravel? That would make things a lot easier.

Categories