I'm writing some dummy code to learn some design patterns. Therefore I made a class Duck.php that implements FlyBehavior. When I call the index.php, I see a blank page, and the console tells me, there is a 500 Internal Server Error. If I outcomment implenets FlyBehavior, the error disappears. So I guess I'm missing something about how to correctly implement an interface.
Thank you!
PHP 5.4.10
Duck.php
<?php
class Duck implements FlyBehavior
{
public function flyWithWings(){
echo 'foo';
}
}
FlyBehavior.php
<?php
interface FlyBehavior {
public function flyWithWings();
}
index.php
<?php
ini_set('error_reporting', E_ALL);
include 'Duck.php';
$duck = new Duck();
echo '<br>Test';
Your problem is that you didn't include the interface in the class that implements it, you can do that by require_once
Or an alternate to this is to use dependency management , for example check composer
<?php
require_once('FlyBehaviour.php');
class Duck implements FlyBehavior
{
public function flyWithWings(){
echo 'foo';
}
}
?>
If you hate having to require/include all the class library every time manually - like I do; perhaps __autoload may be of interest to you:
http://www.php.net/manual/en/function.autoload.php
Setup your scripts like this:
/ index.php
/ libs / FlyBehavior.php
/ libs / Duck.php
I.e. place all your classes in a folder called libs and then setup audoloader on index.php
So, your index.php will look like this:
<?php
// Constants
define('CWD', getcwd());
// Register Autoloader
if (!function_exists('classAutoLoader')) {
function classAutoLoader($class) {
$classFile = CWD .'/libs/'. $class .'.php';
if (is_file($classFile) && !class_exists($class))
require_once $classFile;
}
}
spl_autoload_register('classAutoLoader');
// Rest if your script
ini_set('error_reporting', E_ALL);
ini_set('display_error', 'On');
// Test
$duck = new Duck();
$duck->flyWithWings();
?>
Now, all the required classes are automatically loaded (when you instantiate them for the first time) - meaning you don't have to require any of the class files manually in your script.
Try it out; will save you tons of time :)
Related
I can't seem to figure out to achieve the following result.
Important: this should work down to php 5.3
Ok, so imagine a situation: you develop a number of php modules, for example WordPress plugins, that are to be run on single setup but do not communicate or know about each other. But some (quite large) parts of codebase are the same and can be reused. How can I achieve the result, when all my modules have "inside of them" this shared library, scoped to each module and not causing conflicts in global space?
For example, see the following:
main.php (some host app, like WordPress)
<?php
require('plugins/first-module/first.php');
require('plugins/second-module/second.php');
$first = new Project1\App();
$first->go();
$second = new Project2\App();
$second->go();
?>
first.php (first module)
<?php
namespace Project1;
require('shared.php');
use CoreLib\Util\Logger\Log;
class App {
public function go() {
$logger = new Log();
$logger->say();
}
}
second.php (second module)
<?php
namespace Project2;
require('shared.php');
use CoreLib\Util\Logger\Log;
class App {
public function go() {
$logger = new Log();
$logger->say();
}
}
shared.php (shared lib)
<?php
namespace CoreLib\Util\Logger;
class Log {
public function say() {
echo 'It works!';
}
}
Right now I have an error, obviously, because of re-declaring Log class.
Any ideas?
I'm trying to autoload Classes, but I'm hindered by the scope. The Class is being loaded, but I'm using it out of scope. Here's the code to further explain what I'm trying to do.
AutoLoader.php
<?php
class AutoLoader {
private $namespace;
public function __construct($namespace) {
$this->namespace = $namespace;
spl_autoload_register(array($this, 'ClassLoader'));
}
private function ClassLoader($class) {
$class = "classes/{$this->namespace}/{$class}.php";
print("Loading class: {$class}");
include "{$class}";
}
}
?>
script.php
<?php
ini_set("display_errors", 1);
$loader = new AutoLoader("myspace");
$MyClassObj = new MyClass();
$result = $MyClassObj->MyClassFun();
?>
So when it comes down to script.php, I get the print out that it's loading the class and I don't get any errors that it can't find the file. So it looks like it's loading, but when I use the class to create a new object, it tells me it can't find the class. So I'm loading the include out of scope.
I included the AutoLoader in a separate file so I could load it into multiple files. Am I able to make this work or must the AutoLoader be part of script.php instead of separate?
edit: Including error, added error display to script.php.
Loading class: classes/myspace/MyClass.php
Fatal error: Class 'MyClass' not found in /usr/local/apache2/htdocs/scripts/script.php on line 5
edit: Including MyClass.php and directory structure
MyClass.php
<?php
class MyClass {
public function MyClassFun() {
$var = "hello world";
return $var;
}
}
?>
Directory Structure
htdocs/scripts/script.php
htdocs/classes/myspace/MyClass.php
htdocs/AutoLoader.php
If I change the class to MyClasse (misspelled) it will error on the include because it can't find the file. So using the proper MyClass I can only assume that it's finding the file since it's not producing an error. So the include looks good, but it still won't use it.
Which, now that I think about it more, is strange. The include is only occuring because of line 5 when I go to use the class. ClassLoader is being called by the spl_auto_register to search for the class. It's finding and including the class. Yet the same line 5 fails to actually use it.
I guess I don't understand that disconnect. Line 5 is properly calling the ClassLoader, but then fails to actually find the class once loaded.
I would like just to like to ask for a little elucidation about this three code snippets I found and how PHP behaves with them:
1) a php class (tmp.class.php) with a static method call:
<?php
class Dummy {
public function sayHello()
{
echo "HELLO FROM DUMMY";
}
public static function requireScript() {
require __DIR__ . "/tmp2.php";
}
}
Dummy::requireScript();
2) another file (tmp1.php), instantiating the previous defined class:
<?php
require_once __DIR__. "/tmp.class.php";
$obj = new Dummy;
?>
3) another file (tmp2.php), using the previous instance of the class:
<?php
require_once __DIR__ ."/tmp1.php";
$obj->sayHello();
?>
Now I know that as the requireScript() method has a require call in it, in fact the tmp2.php is included twice, am I right? But when I make the script run (open the tmp2.php file in the browser) I get a Notice: Undefined variable: obj and then of course a Fatal error because of the sayHello();
Shouldn't the $obj be available to the second required tmp2.php script? What is wrong with this code?
Thanks for attention!
In fact noone should build PHP application in that way. You shouldn't put require / include in many files. In simple application you should run require / include at the beginning of file to have everything you need. In more complex applications you should simple use Object Oriented Programming and use autoloader to load classes definitions when they are needed
I can't find information related to it, the thing is that I have a namespace like this:
// foo.php
namespace foo;
function blah()
{
}
And then I include it / use it
require_once 'foo.php';
foo\blah();
Now I want to do the same but without specifying 'foo' all the time (something like using namespace in C++), is that possible?
require_once 'foo.php'
// using namespace foo;
blah(); // ?
Thank's!
Are you sure that the required file is in the same folder level with the file calling it? You can make some checks by throwing a simple if statement to verify.
$file_fnc = '/path/to/foo/file';
if(file_exists($file_fnc)) {
require_once $file_fnc;
} else {
echo "File not found";
}
This will help you determine if your file is truly existing. If it exists then we continue debugging from there. Test it and reply
I am learning how to use namespaces and autoloading in PHP today, and I appear to have hit a roadblock. Things seem to work when I don't use spl_autoload_register but instead require_once.
My folder structure is bare minimal:
- index.php
- class/
- Users.php
In my index.php file I have:
<?php
require_once('class/Users.php');
echo User::get(1);
In my class/Users.php file I have:
<?php
Class User {
function get($id) {
return $id;
}
}
and this works absolutely fine, returning the ID of 1
Ideally I will want to use an Autoload function and I discovered spl_autoload_* and this is what I tried to do, but with no success:
In my class/Users.php file I have:
<?php
namespace Users; // Added a namespace
Class User {
function get($id) {
return $id;
}
}
In my index.php file I have:
<?php
// Changed to using spl_autoload_register using an anonymous function to load the class
spl_autoload_register(function($class){
include('class/' . $class . '.php');
});
echo Users\User::get(1); // Added the Users namespace
but I get an error:
`Class 'Users\User' not found in /Applications/MAMP/htdocs/index.php on line 7`
Not really sure what I'm doing wrong.
I think you should add \ infront of the namespace path.
Example
\Users\User::get(1);
If you have to use a base path, like Traversable() you would also need to do
new \Traversable()
The autoloader is called with the full class name as an argument, including the namespace. In your example this is Users\User, so you end up doing
include('class/Users\User.php');
This fails because the class definition is not in a directory named Users (by the way, include would emit a warning that it cannot find the file which includes the expanded filename, and this warning would make things clearer -- do you have disabled error reporting?)
It's a probably a good idea to have the autoloader fail on the spot when the file is not found so that the failure mode is more apparent. For example you could change it to
require('class/' . $class . '.php'); // require will end the script if file not found
or to something like
$result = #include('class/' . $class . '.php'); // see documentation for include
if ($result === false) {
die("Could not include: 'class/$class.php'");
}