I'm learning PHP OOP and right now I built a basic calculator.
Here is my code at index.php:
require_once 'Calculator.class.php';
require_once 'Adder.class.php';
require_once 'Substract.class.php';
require_once 'Operator.interface.php';
require_once 'Multiplier.class.php';
require_once 'Devider.class.php';
$c = new Calculator;
$c->setOperation(new Adder);
$c->calculate(10,50); // 60
echo $c->getResult();
And this is the Calculator class file:
class Calculator
{
protected $result;
protected $operation;
public function setOperation(OperatorInterface $operation)
{
$this->operation = $operation;
// var_dump($operation);
}
public function calculate()
{
foreach(func_get_args() as $number)
{
$this->result = $this->operation->run($number,$this->result);
}
}
public function getResult()
{
return $this->result;
}
}
And this is the interface that is being called within this class file:
interface OperatorInterface
{
public function run($number,$result);
}
And this is the class Adder which is called from the index.php:
class Adder implements OperatorInterface
{
public function run($number,$result)
{
return $result + $number;
}
}
As you can see it looks nice and okay... however I get this weird error:
Fatal error: Interface 'OperatorInterface' not found on line 2 Adder.php
So line 2 of Adder Class is this:
class Adder implements OperatorInterface
Which means I have not include the interface properly. But I did include that.
So why am I getting this error?
Where did I make my mistake?
You need to include the Operator.interface.php file before the Adder.class.php file, otherwise when the compiler gets to the Adder class, it hasn't yet encountered anything called OperatorInterface, so it doesn't recognise it and can't verify that it's valid to declare that the Adder class implements it. Since it's also referenced in the Calculator class, you should include it before that as well.
require_once 'Operator.interface.php';
require_once 'Calculator.class.php';
require_once 'Adder.class.php';
require_once 'Substract.class.php';
require_once 'Multiplier.class.php';
require_once 'Devider.class.php';
It should be that simple - for future reference you should always order your includes so that dependencies between them can be satisfied, because they get processed in the order you supply them.
Related
I'm trying to unit-test my class-function using PHPUnit, but I keep running into Class not found error, even though it is present.
Here's my func.php where the class is defined:
<?php
class func {
public function url($var) {
//do something
return myvalue;
}
?>
And here's funcCase.php where the Test class is defined:
<?php
require 'func.php';
require 'PHPUnit.php';
class funcTest extends PHPUnit_TestCase {
// contains the object handle of the string class
var $box;
// constructor of the test suite
function funcTest($name) {
$this->PHPUnit_TestCase($name);
}
// called before the test functions will be executed
// this function is defined in PHPUnit_TestCase and overwritten
// here
function setUp() {
// create a new instance of String with the
// string 'abc'
$this->box = new func();
}
// called after the test functions are executed
// this function is defined in PHPUnit_TestCase and overwritten
// here
function tearDown() {
// delete your instance
unset($this->box);
}
// test the url
function testurl() {
$result = $this->box->url('myvalue');
$expected = 'myvalue';
echo $result;
$this->assertTrue($result == $expected);
}
}
?>
And the funcTest.php which runs the PHPTestSuite:
<?php
require_once 'funcCase.php';
require_once 'PHPUnit.php';
$suite = new PHPUnit_TestSuite("funcTest");
$result = PHPUnit::run($suite);
echo $result -> toString();
?>
When running the funcTest.php using phpunit funcTest.php I get this error:
TestCase funcTest->testurl() failed: expected TRUE, actual FALSE
Class 'funcTest' could not be found in 'C:\xampp\htdocs\funcTest.php'.
Why am I getting this if the funcTest class is defined and funcCase.php is included in funcTest.php?
I've a file called helper.php, in this file I've a list of functions (without class).
Now I need to include the content of helper file, into a property. For do this I've create a loader, this is an example:
class Loader
{
function include($helpName)
{
return include $helpName;
}
}
this Loader is used by my class like so:
class Foo
{
function __construct()
{
$this->load = new Loader();
$this->email = $this->load->include('helper.php');
$this->email->send();
}
}
unfortunately I get this error:
Fatal error: Call to a member function validate_email() on integer
if I print: var_dump($this->email); I'll get: int(1).
What am I doing wrong?
Unless you're specifically returning at the end of your class, it doesn't work that way. From the docs:
Handling Returns: include returns FALSE on failure and raises a warning. Successful includes, unless overridden by the included file, return 1.
I'd look into autoloading classes, or you can also create a class, and return that from your include.php.
public class Email
{
public function send()
{
echo 'Sending Email';
}
}
return new Email();
An example with autoloading:
//Create Email.php
public class Email
{
public function send()
{
echo 'Sending Email';
}
}
//Main file, set a register, so when it doesn't find a class, it will load from a file, and auto register it.
spl_autoload_register(function ($class_name) {
include $class_name . '.php';
});
class Foo
{
function __construct()
{
$this->load = new Loader();
//If Email class doesn't exist, it will load it from 'Email.php', and then initialize it.
$this->email = new Email();
$this->email->send();
}
}
Included code always runs in global scope. If you want your functions to be incorporated as methods of a class then you would need to create a new file wrapping the functions in
<?php
Class somename {
?>
And...
<?php
}
But writing self modifying code is inherently dangerous. And its ugly. And it will be sensitive to whether you explicitly end the included file with ?>
An alternative approach which sucks as much as that above, is to get a list of the defined functions, and invoke these from the _call() magic method:
Class somename {
public $included;
function _call($fn, $args)
{
return call_user_func_array($this->included[$fn]), $args);
}
}
$obj=new somename();
$before=get_defined_functions();
include('helper.php');
$obj->included=array_diff(get_defined_functions(), $before);
But you wil find that your included code will not run outside of a class if it references $this
Short version: do not do this
I'm trying to write my site in Controller-Model-View convention without using any framework but I have a problem with __autoload function.
Here's my source_folder/model/database.class.php file:
<?php
function __autoload($sName) {
$aName = explode('_',$sName);
if($aName[0] == 'Model')
include '/model/' . strtolower($aName[1]) . '.class.php';
else if($aName[0] == 'View')
include '/view/' . strtolower($aName[1]) . 'class.php';
else if($aName[0] == 'Controller')
include '/controller' . strtolower($aName[1]) . 'class.php';
}
/**
* Description of database
*
* #author Lysy
*/
class Model_Database {
private $oConfig = new Model_Config();
$this->oConfig->getConfigArray('database');
}
?>
And here's my source_folder/model/config.class.php file:
<?php
include_once '../config.php';
/**
* Description of config
*
* #author Lysy
*/
class Model_Config {
static function GetConfigArray($name) {
return $config[$name];
}
}
?>
The problem appears in line
private $oConfig = new Model_Config();
and it says syntax error, unexpected T_NEW.
I don't understand where lies the problem, because I'm using Netbeans IDE and when I type in private $oConfig = new M the program gives me a hint with Model_Config.
I'd be very glad to read some advices and probable solution to this problem, regards :)
EDIT:
I rewrited the class Model_Config to look like this:
class Model_Database {
private $oConfig;
__construct() {
$oConfig = new Model_Config();
};
$this->oConfig->getConfigArray('database');
}
But now there is a problem in line
__construct() {
Netbeans says that __construct() is unexpected, the error on the site stays the same, unexpected T_NEW
EDIT2: Oh sorry, too much C++, I keep forgeting about function word
You can't assign values to member variables using expressions. You have to do that in your constructor or inside of a method.
Does your Model_Config contains more than that static method or why do you use "new Model_Config()" ?
That error message and "private" looks like you want to create an object direcly in your property. If you want to add an Model_Config object to the property of a specific class, you should use dependency injection. Here in your constructor for excample:
<?php
class YourClass
{
private $oConfig;
public function __construct(Model_Config $oConfig)
{
$this->oConfig = $oConfig;
}
}
A nicer way of injection would be the usage of an interface as type hint. Maybe that method in your Model_Config shouldn't be static.
I have a php project that uses some functional elements, and some OOP elements, but it seems mixing the two is causing problems. Here are the files that are causing the errors:
DB.php
<?php
function parse_db_entry($from, &$to){
//Function code here
}
?>
User.php
<?php
require_once 'DB.php';
class User{
//Properties
public function __construct(){
//ctor
}
public static function load_user($email, $password){
$entry = //Make MySQL Request
$user = new User();
parse_db_entry($entry, $user);
return $user;
}
}
?>
Everything works as it should, except the call to parse_db_entry which throws:
Fatal error: Call to undefined function parse_db_entry()
I am able to access other things in DB.php, for instance if I made a class it there I am able to instantiate it without error, and if I move the function into User.php, it is functional as well. So what am I doing wrong? Why can't I call this method?
I've figured it out! Thanks to everyone who had ideas, but it seems the problem was something else.
When calling require_once 'DB.php', php was actually getting the file:
C:\xampp\php\pear\DB.php
instead of mine.
This may be a problem exclusive to XAMPP, but a simple rename of my file to DBUtil.php fixed everything.
This is a stretch, and I'm totally taking a shot in the dark here, but...
Are you sure parse_db_entry is in the global or User's namespace?
Note: I added a few lines here and there for testing/debugging.
DB.php:
<?php
namespace anotherWorld; // added this ns for illustrative purposes
function parse_db_entry($from, &$to){
echo 'called it';
}
?>
User.php:
<?php
namespace helloWorld; // added this ns for illustrative purposes
class User {
//Properties
public function __construct(){
//ctor
}
public static function load_user($email, $password){
$entry = //Make MySQL Request
$user = new User();
parse_db_entry($entry, $user);
return $user;
}
}
?>
test.php:
<?php
require_once 'DB.php';
require_once 'User.php';
use helloWorld\User;
$a = new User();
$a->load_user('email','pass');
echo 'complete';
?>
Yields Fatal error: Call to undefined function helloWorld\parse_db_entry() in User.php on line 13, however when removing the NS declaration in DB.php (namespace anotherWorld) thereby putting parse_db_entry in global NS it runs just fine.
To verify, use the __NAMESPACE__ constant.
If namespace is a problem, without compromising DB's namespace, here is an updated User.php:
<?php
namespace helloWorld;
use anotherWorld; // bring in the other NS
class User {
//Properties
public function __construct(){
//ctor
}
public static function load_user($email, $password){
$entry = //Make MySQL Request
$user = new User();
anotherWorld\parse_db_entry($entry, $user); // call the method from that NS
return $user;
}
}
?>
I've read some posts about namespaces and autoload in php 5.3+, but still haven't succeeded in creating one working :x maybe some of you have an idea of what's going wrong about my code ?
Thank you previously.
Autoloader.php class
<?php
namespace my;
class AutoLoader {
private $aExt;
private $sPath;
protected static $instance;
public static function getInstance() {
if(!self::$instance instanceof self ) {
self::$instance = new self();
}
return self::$instance;
}
function __construct($sPath = __DIR__, $exts = 'php') {
// define path and extensions to include
$this->setPath($sPath);
$this->setExtensions($exts);
}
public function getPath() {
return $this->sPath;
}
public function setPath($path){
$this->sPath = $path;
}
public function removePath() {
unset ($this->sPath);
}
public function addExtension($ext) {
// prepends period to extension if none found
$this->aExt[$ext] = (substr($ext, 0, 1) !== '.') ? '.'.$ext : $ext;
}
public function removeExtension($ext) {
unset ($this->aExt[$ext]);
}
public function getExtensions() {
return $this->aExt;
}
public function setExtensions($extensions) {
// convert
if (is_string($extensions)) {
$extensions = array($extensions);
}
// add
foreach($extensions as $ext) {
$this->addExtension($ext);
}
}
public function register() {
set_include_path($this->sPath);
// comma-delimited list of valid source-file extensions
spl_autoload_extensions(implode(',',$this->aExt));
// default behavior without callback
spl_autoload_register(array($this, 'autoload'));
}
public function autoload($sClassName) {
include_once($sClassName.'.php');
return;
}
}
$autoloader = new AutoLoader();
$autoloader->register();
?>
MyClass.php the class i am trying to load dinamically
<?php
namespace my\tools;
class MyClass {
function __construct() {}
function __destruct() {}
function test() {
echo 'ok';
}
}
?>
index.php the caller
<?php
include_once('../Libraries/php/my/AutoLoader.php');
new my\tools\MyClass();
?>
and finally the class structures on my disk
Libraries
|_php
|_my
| |_Autoloader.php
|
|_MyClass.php
That's a tad bit over-engineered, my friend.
You might want to take a look at simply using PSR-0 (PRS-0 is now depreciated, PSR-4 is the new one), an autoloader specification from a large number of PHP projects, like phpBB, Joomla, CakePHP, Zend Framework and lots more. It's built with namespaces in mind, but works well with or without them.
The advantage of PSR-0 (or PSR-4) is that it leads to a clean, simple, obvious directory structure that an increasing number of projects are supporting. This means using one autoloader instead of a single autoloader for every single set of code.
spl_autoload_register() expects a valid callback. You give ... something ^^ But not a callback. A callback is
// a closure
$cb = function ($classname) { /* load class */ }
// object method
$cb = array($object, 'methodName');
// static class method
$cb = array('className', 'methodName');
// function
$cb = 'functionName';
See manual: spl_autoload_register() for further information and examples.
After searching a little on PHP.net website, the solution were really simple :/
In fact php autoload function MUST be on root namespace /, mine was on first level of my package (my/), when i moved the class to root namespace everything worked fine.