Jump to content

Using book Learn PHP 8 have an error that is wrong


Markus1954

Recommended Posts

HI All;

Trying to learn php 8 and running into problem with the book. The author and publisher are difficult to get errata and help. So I am here  looking for help.

I am getting an error message and it doesn't make any sense.

Here is the error message.  syntax error, unexpected variable "$dog_error_message"

 And here is some of the code that I wrote; 

require_once("dog.php");
	
	$lab = new Dog;
	
	
	bool $dog_error_message = $lab->set_dog_name('Fred');
	print $dog_error_message ? 'Name update successful<br/> : 'Name update not successful<br/>';
	

Any help is appreciated. By the way the error is pointing to the line that starts with bool

Thanks 

Mark

Link to comment
Share on other sites

OK - I see your text answers my first question.  Now try removing the bool from that line.

It appears now that you are trying to make an assignment.  Since you don't want to change the type of the var $dog_error_message remove the bool from the statement.   You might want to use that somewhere but I don't think you want it here since you are simply trying to copy one value to another variable.  Would be silly to do that simply to get a boolean value when you are really trying to get the value returned from that function call, whatever it may be.

Edited by ginerjm
Link to comment
Share on other sites

There's a simple syntax error in the code you posted.

The code uses the ternary operator.  You have:

print $dog_error_message ? 'Name update successful<br/> : 'Name update not successful<br/>';

Due to missing a single quote, you have broken the ternary.  A ternary is in the form (boolean evaluation) ? (returned if true) : (returned if false)

Fix your quotes like this:

print $dog_error_message ? 'Name update successful<br/>' : 'Name update not successful<br/>';

 

Link to comment
Share on other sites

bool that everyone is concerned with is in the book. I put it there because the author put it there. 

I put in the missing apostrophe and the error moved to line 7. For those of you following along that would be the line with bool $dog_error_message.

 

I am using a book for php 8.

Link to comment
Share on other sites

So you are telling us that this line:

bool $dog_error_message = $lab->set_dog_name('Fred');

is now giving you the message.  I thought that was the problem originally.

To me - not a version 8 user yet -I wonder why the elongated code.  If the call to set_dog_name function is supposed to do something for you and you want to know it it succeeded or not, why don't you just put the call inside an if and do your 'things' from that instead of setting a variable and then checking it.  Of course, I am assuming (!) that the function is expected to return a boolean value already (so why the typecast?) so the following code should work very well:

	if ($lab->set_dog_name('Fred'))
		echo 'Name update successful<br/>';
	else
		echo 'Name update not successful<br/>';

 

Edited by ginerjm
Link to comment
Share on other sites

This is new in php 8. the set is something you do when you have a class and want to restrict access to the class. This is the new way of doing things in php 8 that makes it more secure.

This is the line that is currently getting the error message:  

syntax error, unexpected variable "$dog_error_message" in C:\Apache24\htdocs\Learn\lab.php on line 7

This is line 7 and 8

bool $dog_error_message = $lab->set_dog_name('Fred');
	print $dog_error_message ? 'Name update successful<br/>' : 'Name update not successful<br/>';

According to the author a set method allows values to be passed into the method. Then the values are verified before updating the properties in the object.

Edited by Markus1954
Link to comment
Share on other sites

And how does your latest response resolve the issue?  I told you how I would write it.  But apparently my old-style way of coding that has worked for 40+ years is no longer the preferred way.  I do fail to see how your sample does anything to improve security.  Perhaps in that (unknown) function there is something  about that but what we are trying to solve really has no relation to that.

As you write more you may start to see the value in writing code that is easy to read and interpret.  The sample you are showing us of the 'new way' of coding is NOT easy to interpret.  Fact.  So when you have to go back into this script  a couple of years from now, are you going to readily remember what it is doing?

Good luck with your progress.  I"ll step aside now.

Link to comment
Share on other sites

44 minutes ago, Markus1954 said:

something you do when you have a class

But in the code you've posted, you don't have a class. You can type method/function parameters and class properties, but as far as I've found trying to type variables in the global namespace doesn't work even in 8.0. What book are you using?

  • Great Answer 1
Link to comment
Share on other sites

Right. And I see where you instantiate an instance of that class in the global namespace, right before you try to type a variable in that same global namespace. The code you're showing isn't inside a class or a method/function signature. For instance,

<?php 
class Testing{
	private bool $truefalse;
}

is perfectly valid, because it's inside a class.

<?php
function testing(bool $truefalse){
	echo $truefalse;
}

is also perfectly valid as that's typing a function parameter. However,

<?php
bool $truefalse = false;

is not valid, as it's not within a class or function.

Link to comment
Share on other sites

Apparently you people are having a problem with my shortcut. So here is the complete 2 files.

This is the lab.php file:<?php declare(strict_types=1);
	require_once("dog.php");
	
	$lab = new Dog;
	
	
	bool $dog_error_message = $lab->set_dog_name('Fred');
	print $dog_error_message ? 'Name update successful<br/>' : 'Name update not successful<br/>';
	
	bool $dog_error_message = $lab->set_dog_weight(50);
	print $dog_error_message ? 'Weight update successful<br/>': 'Weight update not successful<br/>';
	
	bool $dog_error_message = $lab->set_dog_breed('Lab');
	print $dog_error_message ? 'Breed update successful<br/>' : 'Breed update unsuccessful<br/>';
	
	bool $dog_error_message = $lab->set_dog_color('Yellow');
	print $dog_error_message ? 'Color update successful<br/>' : 'Color update not successful<br/>';
	//Get properties
	
	$dog_properties = $lab->get_pr0perties();
	list($dog_weight, $dog_breed, $dog_color) = explode(',', $dog_properties);
	print "Dog weight is $dog_weight. Dog breed is $dog_breed. Dog color is $dog_color $dog_color.";
	?>
	
	
	this is the file with the class called dog.php:
<?php declare(strict_types=1);
 class Dog
 {
 
	private int $dog_weight = 0;
	private string $dog_breed = "no breed";
	private string $dog_color = "no color";
	private string $dog_name = "no name";
	
		
	function get_properties() : string
	{
		return "$this->dog_weight, $this->dog_breed, $this->dog_color";
							 
	}
 
 
 }
 ?>

 

Link to comment
Share on other sites

lab.php does not define a class. It uses a class - these are two very different things. Look at my previous examples and the use of the word 'class'. Then compare that to your own files; I think you'll see the important difference.

I don't have Learn PHP 8 from apress, but the source is available through github. What chapter is this lesson?

Edited by maxxd
Link to comment
Share on other sites

Doing my digging and it appears this is chapter 4. Code from the sample:

<?php
Require_once("e10dog.php");
$lab = new Dog;
// ------------------------------Set Properties--------------------------
$dog_error_message = $lab->set_dog_name('Fred');
print $dog_error_message == TRUE ? 'Name update successful<br/>' : 'Name update not successful<br/>';

Note the lack of 'bool' before $dog_error_message. I'm not trying to be a jackass here, but when you're learning a language you have to read the tutorials completely, follow them accurately, and listen to the people who know what they're talking about when they try to help with any confusion.

  • Great Answer 1
Link to comment
Share on other sites

Hello Marcus,

So to be clear, what we are talking about is variable typing and type hints.

Variable typing is only done within a class or trait.

The dog class has examples of variable typing.

I expanded the examples to make a point of what changed:

<?php
 class Dog
 { 
	private int $dog_weight = 0;
	private string $dog_breed = "no breed";
	private string $dog_color = "no color";
	private string $dog_name = "no name";
	
	public function __construct($dog_weight, $dog_breed, $dog_color, $dog_name) {
	    $this->dog_weight = $dog_weight;
	    $this->dog_breed = $dog_breed;
	    $this->dog_color = $dog_color;
	    $this->dog_name = $dog_name;
	}	
		
	public function get_properties() : string
	{
		return "$this->dog_weight, $this->dog_breed, $this->dog_color, $this->dog_name";							 
	} 
 }
 
 $fido = new Dog(42, 'Poodle', 'Brown', 'Fido');
 echo $fido->get_properties() . PHP_EOL;
 
 $spike = new Dog('Heavy', 'Mutt', 'Orange', 'Spike');
// Generates Fatal error: Uncaught TypeError: Cannot assign string to property Dog::$dog_weight of type int
 echo $spike->get_properties() . PHP_EOL;

The class variable definition lines like this one:  "private int $dog_weight = 0"  was first introduced in PHP 7.4.  Prior to that you could not include the "int" to tell php you wanted $dog_weight to be a int.

Furthermore, in my examples, if you try something like passing a string for the assignment, php will generate a runtime error now:  "Fatal error: Uncaught TypeError: Cannot assign string to property Dog::$dog_weight of type int"

Previously however, PHP did support type hinting for parameters that has a similar function.

<?php
class Dog
{ 
	private $dog_weight = 0;
	private $dog_breed = "no breed";
	private $dog_color = "no color";
	private $dog_name = "no name";
	
	public function __construct(int $dog_weight, string $dog_breed, string $dog_color, string $dog_name) {
	    $this->dog_weight = $dog_weight;
	    $this->dog_breed = $dog_breed;
	    $this->dog_color = $dog_color;
	    $this->dog_name = $dog_name;
	}

	public function get_properties() : string
	{
		return "$this->dog_weight, $this->dog_breed, $this->dog_color, $this->dog_name";
	} 
 }
 
 $fido = new Dog(42, 'Poodle', 'Brown', 'Fido');
 echo $fido->get_properties() . PHP_EOL;
 
 $spike = new Dog('Heavy', 'Mutt', 'Orange', 'Spike');
// Generates a Fatal error: Uncaught TypeError: Dog::__construct(): Argument #1 ($dog_weight) must be of type int, string given
 echo $spike->get_properties() . PHP_EOL;

This was available in PHP version 7.0.

This parameter type hinting has been heavily used, especially when passing objects as parameters, since version 7.0.

class Dog
 {
 
	private $dog_weight = 0;
	private $dog_breed = "no breed";
	private $dog_color = "no color";
	private $dog_name = "no name";
	
	public function __construct(int $dog_weight, string $dog_breed, string $dog_color, string $dog_name) {
	    $this->dog_weight = $dog_weight;
	    $this->dog_breed = $dog_breed;
	    $this->dog_color = $dog_color;
	    $this->dog_name = $dog_name;
	}
		
	public function get_properties() : string
	{
		return "$this->dog_weight, $this->dog_breed, $this->dog_color, $this->dog_name";
	}
 
 }
 
 class Cat
 {
     private $cat_breed = 'no breed';
     private $cat_name = 'no name';
     public function __construct(string $cat_breed, string $cat_name) {
         $this->cat_breed = $cat_breed;
         $this->cat_name= $cat_name;
     }
     
    public function get_properties() : string
	{
		return "$this->cat_breed, $this->cat_name";
	}
 }
 
 
 class Kennel
 {
     private $borders = [];
     
     public function addDog(Dog $dog) : void {
        $this->borders[] = $dog; 
     }
     
     public function getBorders() : string {
         $output = '';
         foreach($this->borders as $pet) {
             $output .= $pet->get_properties() . PHP_EOL;
         }
         return $output;
     }
 }
 
 $kennel = new Kennel();
 
 $fido = new Dog(42, 'Poodle', 'Brown', 'Fido');
 $kennel->addDog($fido);
 
 $sparky = new Dog(22, 'Mutt', 'Tan', 'Sparky');
 $kennel->addDog($sparky);
 
 $simba = new Cat('siamese', 'Simba');
 echo $simba->get_properties() . PHP_EOL;
 
 echo $kennel->getBorders();
 
 $kennel->addDog($simba);
//Generates Fatal error: Uncaught TypeError: Kennel::addDog(): Argument #1 ($dog) must be of type Dog, Cat given

 

What has never been possible is add a type to  a variable declaration outside of a class definition (as you attempted to do):

<?php
int $errorCode = 7;
//generates a Parse error: syntax error, unexpected '$errorCode' (T_VARIABLE) in 7.
//generates Parse error: syntax error, unexpected variable "$errorCode" in 8.

 

One other common type hint is to utilize an interface definition as a parameter type hint: 

<?php

interface HasFeet {
  public function setFeet(int $number);
  public function getFeet() : int;
}

class Duck implements HasFeet 
{
    private $nbrFeet;
    
    public function setFeet(int $number) {
        $this->nbrFeet = $number;
    }
    
    public function getFeet() : int {
        return $this->nbrFeet;
    }
}

class Mouse implements HasFeet 
{
    private $legs;
    
    public function setFeet(int $number) {
        $this->legs = $number;
    }
    
    public function getFeet() : int {
        return $this->legs;
    }
}

class Fish
{
    private $legs = 0;
    
    public function getFeet() : int {
        return $this->legs;
    }
}

class Catalog
{
    private $animals = [];
    
    public function addAnimal(HasFeet $animal) {
        $this->animals[] = $animal;
    }
    
    public function getAnimalFeetCount() : string {
        $output = '';
        foreach($this->animals as $animal) {
            $output .= 'A ' . get_class($animal) . " has {$animal->getFeet()} feet" . PHP_EOL;
        }
        return $output;
    }
}

$catalog = new Catalog();

$duck = new Duck();
$duck->setFeet(2);
$mouse = new Mouse();
$mouse->setFeet(4);

$catalog->addAnimal($duck);
$catalog->addAnimal($mouse);

echo $catalog->getAnimalFeetCount();

//Generates
//A Duck has 2 feet
//A Mouse has 4 feet
//
//Fatal error: Uncaught TypeError: Argument 1 passed to Catalog::addAnimal() must implement interface HasFeet, instance of Fish given

 

PHP 8 has added constructor variable definition through parameter scope & typing:

<?php

// Prior to 8.0 - Standard class variable initialization 
class Bike
{
    private $wheels = 0;
    
    public function __construct(int $wheels=2) {
        $this->wheels = $wheels;
    }
    
    public function getWheels() : int {
        return $this->wheels;
    }
}


// PHP 8.0 definition via parameter 
class Car
{
    public function __construct(private int $wheels=4) {
    }
    
    public function getWheels() : int {
        return $this->wheels;
    }    
}

$bike = new Bike();
echo $bike->getWheels() . PHP_EOL;

$car = new Car();
echo $car->getWheels() . PHP_EOL;

$truck = new Car(18);
echo $truck->getWheels() . PHP_EOL;

// In PHP 8.01+
// 2
// 4
// 18

So PHP 8 will relieve you of having to define attributes in the class definition, if you define them in the constructor.  This works for class parameters as well!

  • Like 1
  • Thanks 1
Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.