This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
Throw a NotImplementedError in PHP?
When writing base-classes, I often develop gradually, and only build what I need (Or, what I am testing). Yet I like my interface to be balanced. For every getter a setter. When implmenting CRUD, even when right now, I need only the R, I'd rather write the stubs for CUD laready.
I want these to throw some Not Implemented Exception. How can I raise such errors or exceptions?
For example:
class Resource {
/**
* get Issues a GET-request to Online, fetch with $this::$id
* #returns $this
*/
protected function get() {
if ($this->id) {
$attributes = http_build_query(array("id" => $this->id));
$url = "{$this->url}?{$attributes}";
$options = array_merge(array('method' => 'GET'));
$response = _http_request($url, $options);
$this->parse($response);
}
return $this;
}
/**
* post Place a new object on Online
*
* #param $attributes ....
* #returns Source $this
*/
protected function post($attributes = array()) {
throw new NotImplementedError();
}
/**
* put Updates an object on Online
*
* #param $attributes ....
* #returns $this
*/
protected function put($attributes = array()) {
throw new NotImplementedError();
}
/**
* delete Removes an object from Online, selected by $this::$id.
* #returns $this
*/
protected function delete() {
throw new NotImplementedError();
}
}
Have a look at this previous answer: Throw a NotImplementedError in PHP?
Very simply put, one doesn't exist in PHP, but you can easily create your own by extending an existing Exception. The previous answer suggests using BadMethodCallException to do this:
class NotImplementedException extends BadMethodCallException
{}
Then you can throw a NotImplementedException within your code.
As I see it you have 2 possibilities:
Derive from the exception class and implement a not implemented exception, that you can throw.
Define the not implemented methods as abstract. The compiler will then generate a error. Do not forget to mark the entire base class as abstract.
You can throw new NotImplementedException() - just like this one from the Symfony API.
Related
In TrainBoardingCard we have setTrainCode is it ok to use $this->trainCode = $trainCode inside constructor or we shoud always use setTrainCode like $this->setTrainCode($trainCode); as it could have some logic in future.
For both case what are the pros and cons? please let us know your preference with reasons.
class TrainBoardingCard extends BoardingCard
{
/**
* #var string
*/
private $trainCode;
/**
* #param string $trainCode
*/
public function __construct(string $trainCode)
{
$this->trainCode = $trainCode;
}
/**
* #return string
*/
public function getTrainCode(): string
{
return $this->trainCode;
}
/**
* #param string $trainCode
*/
public function setTrainCode(string $trainCode)
{
$this->trainCode = $trainCode;
}
}
It depends.
You could say there are two different schools of thought and they both deal with both setters and constructors.
The object must be created already valid state. This state can be changed with atomic operation from one valid state to another. This means, that you class doesn't actually have simple setters per se.
$client = new Client(
new FullName($name, $surname),
new Country($country);
new Address($city, street, $number));
// do something
$client->changeLocation(
new Country('UK'),
new Address('London', 'Downing St.', '10'));
Constructor is used only do pass in dependencies and not to impart state. The object's state by default is blank and it gets changed only by using setters externally.
$client new Client();
$client->setId(14);
$mapper = new DataMapper(new PDO('...'), $config);
$mapper->fetch($client);
if ($client->getCity() === 'Berlin') {
$client->setCity('London');
$mapper->store($client);
}
Or you can have a mix or both, but that would cause some confusion.
Not sure if this will make it better for you or worse :)
So I was reviewing the source code from PHPWord and I have looked all over and can't figure out how this snippet of code works.
class PHPWord_Shared_XMLWriter {
/**
* Internal XMLWriter
*
* #var XMLWriter
*/
private $_xmlWriter;
public function __construct($pTemporaryStorage = self::STORAGE_MEMORY, $pTemporaryStorageFolder = './') {
// Create internal XMLWriter
$this->_xmlWriter = new XMLWriter();
...
}
}
So according to my understanding of php the only way to access the $this->_xmlWriter methods is to call it like this:
$testClass= new PHPWord_Shared_XMLWriter();
$testClass->_xmlWriter->startDocument();
However, in this piece of code from theDocProps.php this line of code is implemented:
$objWriter = new PHPWord_Shared_XMLWriter(PHPWord_Shared_XMLWriter::STORAGE_MEMORY);
$objWriter->startDocument('1.0','UTF-8','yes');
How does this work? I can't replicate it, but it works when I use it in the file. TO BE CLEAR, there is no method defined by PHPWord_Shared_XMLWriter that is called startDocument(). I feel like I'm missing something really simple but I can't even search right for it.
Thanks!
You need to look at the entire definition of the class PHPWord_Shared_XMLWriter (source here). It uses the __call magic method to pass method calls to _xmlWriter:
/**
* Catch function calls (and pass them to internal XMLWriter)
*
* #param unknown_type $function
* #param unknown_type $args
*/
public function __call($function, $args)
{
try {
#call_user_func_array(array($this->_xmlWriter, $function), $args);
} catch (Exception $ex) {
// Do nothing!
}
}
By using call_user_func_array on $this->_xmlWriter, it causes all inaccessible or undefined methods to be passed to the _xmlWriter property.
From the docs:
__call( unknown_type $function, unknown_type $args )
Catch function calls (and pass them to internal XMLWriter)
Parameters
$function
unknown_type
$function
$args
unknown_type
$args
So far I feel like I've understood the concept and the advantages of OOP programming, and I've not really had any difficulties with understanding how to work with classes in PHP.
However, this has left me just a little confused. I think I may understand it, but I'm still uncertain.
I've been following a set of video tutorials (not sure on the rules on linking to outside resources, but I found them on youtube), and they're pretty self explanatory. Except, frustratingly, when the tutor decided to pass one class as a parameter within another class. At least I think that's what's happening;
Class Game
{
public function __construct()
{
echo 'Game Started.<br />';
}
public function createPlayer($name)
{
$this->player= New Player($this, $name);
}
}
Class Player
{
private $_name;
public function __construct(Game $g, $name)
{
$this->_name = $name;
echo "Player {$this->_name} was created.<br />";
}
}
Then I'm instantiating an object of the Game class and calling its method;
$game = new Game();
$game-> createPlayer('new player');
Rather frustratingly, the tutor doesn't really explain why he has done this, and hasn't displayed, as far as I can see, any calls in the code that would justify it.
Is the magic method constructor in Player passing in the Game class as a reference? Does this mean that the entire class is accessible within the Player class by reference? When referencing $this without pointing to any particular method or property, are you referencing the entire class?
If this is what is happening, then why would I want to do it? If I've created a Player inside my Game Class, then surely I can just access my Player Properties and Methods within the Game Class, right? Why would I want my Game Class inside my Player class as well? Could I then, for example, call createPlayer() within the Player class?
I apologise if my explanation has been at all confusing.
I guess my question boils down to; what is it that I'm passing as a parameter exactly, and why would I want to do it in every day OOP programming?
It's called type hinting and he's not passing the entire class as a parameter but ratter hinting the Class Player about the type of the first parameter
PHP 5 introduces type hinting. Functions are now able to force parameters to be objects (by specifying the name of the class in the function prototype), interfaces, arrays (since PHP 5.1) or callable (since PHP 5.4). However, if NULL is used as the default parameter value, it will be allowed as an argument for any later call.
(Extracted from php manual)
Does this mean that the entire class is accessible within the Player class by reference?
Not the entire class, but you can access the an instance of the class you are passing as a parameter
The method DOES expect to get the an object which is an instance of Game anything else, and it will error out.
You are passing an instance of Game just here: New Player($this, $name); The key word $this refers to the object instance you are in.
And last....I (and nobody else for that matter) has any idea why the author did it, as he is not using the Game instance after he passes it.
Why would u pass a Instance of a class?
Imagine a Class that accepts Users as input and according to some logic does something with them. (No comments in code, as function name and class name are supposed to be self-explanatory)
class User{
protected $name,$emp_type,$emp_id;
protected $department;
public function __construct($name,$emp_type,$emp_id){
$this->name = $name;
$this->emp_type = $emp_type;
$this->emp_id = $emp_id;
}
public function getEmpType(){
return $this->emp_type;
}
public function setDep($dep){
$this->department = $dep;
}
}
class UserHub{
public function putUserInRightDepartment(User $MyUser){
switch($MyUser->getEmpType()){
case('tech'):
$MyUser->setDep('tech control');
break;
case('recept'):
$MyUser->setDep('clercks');
break;
default:
$MyUser->setDep('waiting HR');
break;
}
}
}
$many_users = array(
0=>new User('bobo','tech',2847),
1=>new User('baba','recept',4443), many more
}
$Hub = new UserHub;
foreach($many_users as $AUser){
$Hub->putUserInRightDepartment($AUser);
}
/**
* Game class.
*/
class Game implements Countable {
/**
* Collect players here.
*
* #var array
*/
private $players = array();
/**
* Signal Game start.
*
*/
public function __construct(){
echo 'Game Started.<br />';
}
/**
* Allow count($this) to work on the Game object.
*
* #return integer
*/
public function Count(){
return count($this->players);
}
/**
* Create a player named $name.
* $name must be a non-empty trimmed string.
*
* #param string $name
* #return Player
*/
public function CreatePlayer($name){
// Validate here too, to prevent creation if $name is not valid
if(!is_string($name) or !strlen($name = trim($name))){
trigger_error('$name must be a non-empty trimmed string.', E_USER_WARNING);
return false;
}
// Number $name is also not valid
if(is_numeric($name)){
trigger_error('$name must not be a number.', E_USER_WARNING);
return false;
}
// Check if player already exists by $name (and return it, why create a new one?)
if(isset($this->players[$name])){
trigger_error("Player named '{$Name}' already exists.", E_USER_NOTICE);
return $this->players[$name];
}
// Try to create... this should not except but it's educational
try {
return $this->players[$name] = new Player($this, $name);
} catch(Exception $Exception){
// Signal exception
trigger_error($Exception->getMessage(), E_USER_WARNING);
}
// Return explicit null here to show things went awry
return null;
}
/**
* List Players in this game.
*
* #return array
*/
public function GetPlayers(){
return $this->players;
}
/**
* List Players in this game.
*
* #return array
*/
public function GetPlayerNames(){
return array_keys($this->players);
}
} // class Game;
/**
* Player class.
*/
class Player{
/**
* Stores the Player's name.
*
* #var string
*/
private $name = null;
/**
* Stores the related Game object.
* This allows players to point to Games.
* And Games can point to Players using the Game->players array().
*
* #var Game
*/
private $game = null;
/**
* Instantiate a Player assigned to a Game bearing a $name.
* $game argument is type-hinted and PHP makes sure, at compile time, that you provide a proper object.
* This is compile time argument validation, compared to run-time validations I do in the code.
*
* #param Game $game
* #param string $name
* #return Player
*/
public function __construct(Game $game, $name){
// Prevent object creation in case $name is not a string or is empty
if(!is_string($name) or !strlen($name = trim($name))){
throw new InvalidArgumentException('$name must be a non-empty trimmed string.');
}
// Prevent object creation in case $name is a number
if(is_numeric($name)){
throw new InvalidArgumentException('$name must not be a number.');
}
// Attach internal variables that store the name and Game
$this->name = $name;
$this->game = $game;
// Signal success
echo "Player '{$this->name}' was created.<br />";
}
/**
* Allow strval($this) to return the Player name.
*
* #return string
*/
public function __toString(){
return $this->name;
}
/**
* Reference back to Game.
*
* #return Game
*/
public function GetGame(){
return $this->game;
}
/**
* Allow easy access to private variable $name.
*
* #return string
*/
public function GetName(){
return $this->name;
}
} // class Player;
// Testing (follow main comment to understand this)
$game = new Game();
$player1 = $game->CreatePlayer('player 1');
$player2 = $game->CreatePlayer('player 2');
var_dump(count($game)); // number of players
var_dump($game->GetPlayerNames()); // names of players
Rewrote your code in a nicer way and added some missing variables that made that code pointless:
In player class you don't store the game.
In game class, you support only one player.
No error checking... anywhere.
Fixed all those plus:
Added exceptions (to prevent object creation)
Try{} catch(...){} Exception handling any OOP dev should know
Implemented Countable interface to allow count($game) players
Some more tricks that will give you a good read
Follow the comments and I hope your code will make more sense after you read it.
I'm just beginning with PHPUnit and TDD.
Among others, I can't really answer to this question: Is this a good test? Am i actually testing my code or something already tested (i.e. the framework or PHP itself)?
Little example, this is the test subject:
class DateMax extends Constraint
{
/**
* #var string
*/
public $limit;
/**
* #var string
*/
private $invalidLimit = 'Option "limit" should be a valid date/time string.';
public function __construct($options = null)
{
parent::__construct($options);
if(false === strtotime($this->limit)) {
throw new InvalidOptionsException($this->invalidLimit, ['limit']);
}
}
}
I want to test that InvalidOptionsException is expected when invalid "limit" options are passed, otherwise $constraint->limit holds the correct value:
/**
* #dataProvider getInvalidLimits
* #expectedException InvalidOptionsException
*/
public function testInvalidLimits($testLimit)
{
new DateMax($testLimit);
}
/**
* #dataProvider getValidLimits
*/
public function testValidLimits($testLimit)
{
$constraint = new DateMax($testLimit);
$this->assertEquals($testLimit, $constraint->limit);
}
/**
* #return array[]
*/
public function getInvalidLimits()
{
return array(array('invalid specification'), array('tomorr'));
}
/**
* #return array[]
*/
public function getValidLimits()
{
return array(array('now'), array('+1 day'),array('last Monday'));
}
So question is does this make any sense or I'm testing the framework/PHP itself?
Of course it has sense, because you override constructor of Constraint class and there is possibility that you'll break something inside it. So basing on your constructor logic basically you want to test two things:
check if you call parent's constructor with the same options, exactly once (you can use mock for this purpose, you don't care about setting appropriate limit value, because this should be tested in Constraint class)
check if an appropriate exception has been thrown when limit has wrong value (eg. null)
edit: Some use case where first test will be useful may be this one:
Let say at some moment you want to extend your DateMax constructor in this way:
public function __construct($options = null)
{
$this->optionsWithDecrementedValues = $this->doWeirdThings($options);
parent::__construct($options);
if(false === strtotime($this->limit)) {
throw new InvalidOptionsException($this->invalidLimit, ['limit']);
}
}
but for example you didn't notice that method "doWeirdThings" takes a reference as argument. So in fact it changes $options value, what you didn't expect, but first test fails so you won't miss it.
<?php
/**
* This class is sort of factory class that is responsible for loading
* classes, it check if this class is not defined then it includes the file
* So developer don't need to worry about including that file
* #author Haafiz
*/
class load{
public static $app_path= APP_PATH;
public static $model_path=MODEL_PATH;
/*
* #param string $model_name <>Name of class(model) that is required to instantiate/load</p>
* #param bool $continue_on_error this decide whether to have fatal error or continue on error loading
* $return object
*/
public static function model($model_name,$conitnue_on_error=0){
if(!class_exists($model_name)){
$model_filename= strtolower($model_name).".php";
try{
include self::$model_path.$model_filename;
}
catch(Exception $e){
if(!$continue_on_error){
die($e);
}
}
$model=new $model_name();
return $model;
}
}
}
?>
In above code have to face following error. Some people says in some other threads that problem is in using & , I am not using that. So what actually is prolem in my case? All seems to doing every thing correctly. Saw some other threads but didn't find any solution. So please if other people understand any thing by it.
thanks
Line 80 in php/PEAR/Config.php is indeed using a reference.
function Config()
{
$this->container =& new Config_Container('section', 'root');
} // end constructor
Please refer to this question about this problem and about updating your PEAR package.