PHP how to have declare a class member? - php

Slightly confused with PHP because it does not declare object variable types.
This is simplified code which does not work. I get why I get an error but not sure how in PHP I can specify that $pb is a PushBot object and so it has methods which can be used.
class Bot
{
public $pb;
//Constructor
function __construct(){
require_once('../PushBots.class.php');
// Application ID
$appID = '';
// Application Secret
$appSecret = '';
// Push The notification with parameters
$this ->pb = new PushBots();
$this ->pb->App($appID, $appSecret);
}
//Method. The $this->pb->Push() does not work
public function sendMessage(){
$this->pb->Push();
}
}
//Client calling the class
$bot = new Bot();
$bot->sendMessage();
The error I get is :
Parse error: syntax error, unexpected '$' for when the line
$this->pb->Push();
is called.
I guess its because it does not know that $pb is a PushBot object at this stage ?
Can I not declare it something like :
Public Pushbot $pb;

Parse error: syntax error, unexpected '$' for when the line
This is a parse error, meaning your code has not even been run yet. Check your code for any sytnax errors (the code you posted does not contain the syntax error).
how in PHP I can specify that $pb is a PushBot object
Although unrelated to the syntax error, if you were using some sort of dependency inversion you could use type-hinting to require a certain object to be passed:
// will cause fatal error if anything other than an object of type Pushbot is passed
function __construct(Pushbot $pb)

Related

how to get through this Fatal Error problem?

**Fatal error: Method Template::__toString() must not throw an exception, caught ParseError: syntax error, unexpected end of file in C:\xampp\htdocs\joblister\index.php on line 0**
i dont know where is the wrong part? can you guys help me? i kept trying but nothing can fix it.
<?php include_once 'config/init.php'; ?>
<?php
$job = new Job;
$template = new Template('templates/frontpage.php');
$template->title = 'Latest Jobs';
$template->jobs = $job->getAllJobs();
echo $template;
?>
this is because you are trying to echo an object not string ...
in the template class you either need to implement the magic function __toString() and define how the object should be printed or you may have your custom method in the class for example getHtml() .. which returns the built string and echo it like that
echo $template->getHtml();

PHP: How to catch Fatal error: Cannot declare class [myclassname], because the name is already in use

I am implementing a plugin controller CLASS for client created custom plugins.
Since the names of the classes of each plugin could very well end up clashing with other plugins already installed, I want to make sure we don't get fatal errors when a new plugin comes in.
I want to report to the user that the new plugin is clashing with an already installed one.
So basically atm I testing with 2 files both containing exactly the same code and am getting:
Fatal error: Cannot declare class [myclassname], because the name is already in use
I have tried catching this with no success using:
try {
include_once $file;
} catch (ClosedGeneratorException|DOMException|ErrorException|IntlException|LogicException|BadFunctionCallException|BadMethodCallException|DomainException|InvalidArgumentException|LengthException|OutOfRangeException|PharException|ReflectionException|RuntimeException|OutOfBoundsException|OverflowException|PDOException|RangeException|UnderflowException|UnexpectedValueException|SodiumException $ex) {
echo "Unable to load file.";
}
All these I got from Lists of Throwable and Exception tree as of 7.2.0 in https://www.php.net/manual/en/class.exception.php
The manual specifies that:
The thrown object must be an instance of the Exception class or a
subclass of Exception. Trying to throw an object that is not will
result in a PHP Fatal Error.
Is it possible that this is not an object of instance/suclass of the Exception class?
What am I missing?
Short answer: no, you're not missing anything. Declaring a duplicate class name can't be caught in any version of PHP (including 8.0.0 as far as the alpha releases). See https://3v4l.org/2TLA3
For some additional background, PHP does sometimes move errors like these underneath the Throwable hierarchy, so that they can be detected at runtime. PHP 7 added support for catching an attempt to instantiate a missing class, and 7.3 added support for catching an attempt to extend a missing class. See https://3v4l.org/BDnm9 for a brief demo of those.
In the end, to avoid this fatal error I decide to parse the files for the first available class declaration using tokens as follows:
public function getClassInFile($filenpath) {
$src = $this->uncommentFile($filenpath);
$class ='';
if (preg_match('/class[\s\n]+([a-zA-Z0-9_]+)[\s\na-zA-Z0-9_]+\{/', $src, $matches)) {
$class = $matches[1];
}
return $class;
}
public function uncommentFile($filenpath) {
$fileStr = file_get_contents($filenpath);
$newStr = '';
$commentTokens = array(T_COMMENT);
if (defined('T_DOC_COMMENT'))
$commentTokens[] = T_DOC_COMMENT; // PHP 5
if (defined('T_ML_COMMENT'))
$commentTokens[] = T_ML_COMMENT; // PHP 4
$tokens = token_get_all($fileStr);
foreach ($tokens as $token) {
if (is_array($token)) {
if (in_array($token[0], $commentTokens))
continue;
$token = $token[1];
}
$newStr .= $token;
}
return $newStr;
}
In this way, I can check whether the class I am expecting to find is in there, or if the class in there already exists, thus avoiding to include_once altogether in these cases.
Problem solved.

How to Unit Test Type Hint with PHPUnit

I want to test this method:
Class:
public function bind(\Elastica\ResultSet $result = null) {
if (!$result instanceof \Elastica\ResultSet) {
throw new \InvalidArgumentException('I need an instance of \Elastica\ResultSet');
}
$this->bindedData = $result->getResults();
$this->isBinded = true;
}
Test
public function testGetTransformedDataNotSuccesful() {
$this->object->bind(new \stdClass()); //This throws a Catchable fatal error
}
My question is:
How can i test this?
An alternative is not to Type Hint the method var.
Or shouldn't i test this.
Wouldn't it make sense that PHP throws an exception instead of throwing a fatal error ?
Throwing a fatal error is correct, as your method signature explicitly asks for a \Elastica\ResultSet but you provide an \stdClass.
Removing the typehint would also remove the fatal error - but that doesn't make much sense imho :)
edit
This test should pass
public function testGetTransformedDataNotSuccesful() {
$this->setExpectedException(get_class(new PHPUnit_Framework_Error("",0,"",1)));
$this->object->bind(new \stdClass()); //This throws a Catchable fatal error
}

Cannot access empty property - Joomla! JDatabaseMysqli

I was receiving the following fatal error, running Joomla 2.5, but only while trying to access the administrative view of a custom component I have created (which accessed the database):
Fatal Error: Cannot access empty property in \libraries\joomla\database\database\mysqli.php on line 498"
The context of line 498 is:
protected function fetchObject($cursor = null, $class = 'stdClass'
{
return mysqli_fetch_object($cursor ? $cursor : $this->cursor, $class);
}
Bizarrely, even after removing the $this->cursor statement like so:
protected function fetchObject($cursor = null, $class = 'stdClass'
{
return mysqli_fetch_object($cursor, $class);
}
I received the same error, despite the fact that that line no longer contains a member access operator.
How could I be receiving this error even though no properties are being accessed in that line?

PHP Unit Tests: Is it possible to test for a Fatal Error?

FWIW I'm using SimpleTest 1.1alpha.
I have a singleton class, and I want to write a unit test that guarantees that the class is a singleton by attempting to instantiate the class (it has a private constructor).
This obviously causes a Fatal Error:
Fatal error: Call to private FrontController::__construct()
Is there any way to "catch" that Fatal Error and report a passed test?
No. Fatal error stops the execution of the script.
And it's not really necessary to test a singleton in that way. If you insist on checking if constructor is private, you can use ReflectionClass:getConstructor()
public function testCannotInstantiateExternally()
{
$reflection = new \ReflectionClass('\My\Namespace\MyClassName');
$constructor = $reflection->getConstructor();
$this->assertFalse($constructor->isPublic());
}
Another thing to consider is that Singleton classes/objects are an obstacle in TTD since they're difficult to mock.
Here's a complete code snippet of Mchl's answer so people don't have to go through the docs...
public function testCannotInstantiateExternally()
{
$reflection = new \ReflectionClass('\My\Namespace\MyClassName');
$constructor = $reflection->getConstructor();
$this->assertFalse($constructor->isPublic());
}
You can use a concept like PHPUnit's process-isolation.
This means the test code will be executed in a sub process of php. This example shows how this could work.
<?php
// get the test code as string
$testcode = '<?php new '; // will cause a syntax error
// put it in a temporary file
$testfile = tmpfile();
file_put_contents($testfile, $testcode);
exec("php $tempfile", $output, $return_value);
// now you can process the scripts return value and output
// in case of an syntax error the return value is 255
switch($return_value) {
case 0 :
echo 'PASSED';
break;
default :
echo 'FAILED ' . $output;
}
// clean up
unlink($testfile);

Categories