PHP面试题

Posted echo_return

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PHP面试题相关的知识,希望对你有一定的参考价值。

1,&引用(https://www.cnblogs.com/chrdai/p/11061174.html
        在php中,将变量 $a赋值给 $b,实际上就是将两个变量指向了同样的内存地址。

$a = range(1,100000);
var_dump(memory_get_usage()); // int(6698184)

$b = $a;
var_dump(memory_get_usage()); // int(6698184)

$a = range(1,200000);
var_dump(memory_get_usage()); // int(17184024)

        从上边可以看到,当 $b=$a时,并不是重新分配内存空间给 $b,而是将两个变量指向了同样的内存地址。而当给 $a重新赋值时,则是重新开辟一片内存空间给 $a

        变量间的引用赋值,就是将变量都指向同一个内存地址,当任意一个变量值发生变化时,就会将两个变量指向的内存地址都修改为新分配的内存地址。

$a = range(1,100000);
var_dump(memory_get_usage()); // int(6698208)

$b = &$a;
var_dump(memory_get_usage()); // int(6698208)

$a = range(1,100000);
var_dump(memory_get_usage()); // int(6698208)

        对于引用的变量执行 unset操作,也只会取消引用,而不会销毁内存空间。

$a = 1;
$b = & $a;
unset($b);
echo $a;

        对象的引用:

class A {
    public $name = 1;
    function getName(){
        echo $this->name;
    }
}
$a = new A;
$b = $a; // $b 与 $a 指向同一个内存空间地址
$b->name = 2;
$a->getName(); // 2

变量引用示例:

$d = [\'a\', \'b\', \'c\'];

foreach($d as $k => $v)
{
    $v = &$d[$k];
}

//最终程序执行完成之后 $d 的值是?

        第一次遍历:$d[0]被引用赋值给 $v,都指向了同一个值的内存地址 \'a\'。
        第二次遍历:$d[1]被引用赋值给 $v,由于之前$v$d[0]都指向了同一个地址,因此,这一次循环会将 $d[0]$v都被修改成了 $d[1]的值 b。
        第三次遍历:$d[2]被引用赋值给 $v,于之前$v$d[1]都指向了同一个地址,因此,这一次循环会将 $d[1]$v都被修改成了 $d[2]的值 c。
        因此最终 $d = [\'b\', \'c\', \'c\']

        函数引用

function t(&$a)
{
    $a++;
}

$a = 1;
t($a);
echo $a; // 2

        通过引用的形式传递给函数参数,必须是一个变量名,而不能是一个确定的值,否则会报错。

function &t()
{
    static $a = 0;
    $a++;
    echo $a;
    return $a;
}
$b = t(); // 输出:1
$b = 5;
$b = t(); // 输出:2
$b = &t(); // 输出3。$b=3
$b = 5; // $a = 5
$b = t(); // 输出:6

        通过 $b=t()形式调用的函数,并不是引用调用函数,和普通函数调用一样。$b=&t()这样的形式才是函数的引用调用。由于静态变量在函数结束后不会销毁的性质,因此,第一次调用函数时,会输出1,第二次调用时,输出2。第三次是引用调用函数,是将 return后的变量 $a的地址与 $b的内存地址指向同一个地址。因此,在给 $b赋值为5后,再次调用函数,就会输出6。

//官方示例:
class talker{
    private $data = \'Hi\';
    public function & get()
    {
        return $this->data;
    }
    public function out()
    {
        echo $this->data;
    }
}
$a = new talker();
$b = &$a->get();
$a->out();
$b = \'How\';
$a->out();
$b = \'are\';
$a->out();
$b = \'you\';
$a->out();

//最终输出:HiHowareare

2,PHP中的 COW ( Copy-on-Write写时复制 ) 机制
        写时复制,即在变量进行写入时,才会复制一份内存,这是内存优化的常用手段。
        在通过变量赋值的方式赋值变量时,不会申请新的内存给新的变量,只是使用一个计数器来共用内存。只有当其中某一个变量的值发生变化时,才会分配新的内存给变量的变量。
        常用场景有:变量的多次赋值;函数的参数传递,并在函数体内修改实参等。

3,静态变量
        静态变量仅在局部函数作用域中存在,且仅在函数第一次执行时创建,当函数执行完毕之后,静态变量的值不会丢失。

function t(){
    static $a = 1;
    $a++;
    echo $a;
}
t(); // 2
t(); // 3
t(); // 4

4,== 与 === 的区别
        两者均用于判断等号前后的值是否相等,区别在于 ===在判断值相等与否的同时,还会判断值的类型是否相等,仅当值与数据类型均相同时,===才会返回 true,其他情况就返回 false。而 ==在值相等的情况下就会返回 true,无论数据类型是否相同。

$a = 0;
$b = \'\';
var_dump($a == $b); // boolean true
var_dump($a === $b); // boolean false

5,isset 和 empty 的区别
isset():变量存在且值不为 NULL就返回 true,反之返回 false
empty():变量不存在或者变量值为 false时就返回 true,反之返回 false

$a = \'\';
$b = 0;
$c = false;
$d = 1;
$e = \'0\';
$f = \'0.0\';
$g = null;
var_dump(isset($m)); // boolean false
var_dump(isset($a)); // boolean true
var_dump(isset($b)); // boolean true
var_dump(isset($c)); // boolean true
var_dump(isset($d)); // boolean true
var_dump(isset($e)); // boolean true
var_dump(isset($f)); // boolean true
var_dump(isset($g)); // boolean false

var_dump(empty($m)); // boolean true
var_dump(empty($a)); // boolean true
var_dump(empty($b)); // boolean true
var_dump(empty($c)); // boolean true
var_dump(empty($d)); // boolean false
var_dump(empty($e)); // boolean true
var_dump(empty($f)); // boolean false
var_dump(empty($g)); // boolean true

6,魔术函数(魔术方法) 魔术方法都必须被声明为public

  • __construct():该方法在对象被实例化时会自动调用。
  • __destruct():当对象的所有引用被删除或者当对象被现实销毁时执行。
class A {
    function __construct()
    {
        echo \'我被自动执行了!\';
    }
}
$a = new A;

class B {
    public $name;
    
    public function __construct($name){
        $this->name = $name;
        echo \'你的名字是:\'.$this->name;
    }
    
    public function __destruct(){
        echo \'对象被销毁了\';
    }
}

$b = new B(\'Jeccy\');
  • __call($name, $arguments):在对象中调用一个不可访问(方法不存在或被定义为 protectedprivate)的方法时,会被调用。$name为不可访问的方法名,$arguments为访问时传的参数。
class B {
    public $name=22;
    protected function getName()
    {
        echo $this->name;
    }
    function __call($name, $arguments){
        var_dump($name);
        var_dump($arguments);
    }
}

$b = new B;

$b->getName(1,2); // string \'getName\'  Array ( [0] => 1 [1] => 2 )
$b->getAge(3,4); // string \'getAge\'  Array ( [0] => 3 [1] => 4 )
  • callStatic($name, $arguments):在静态上下文中访问一个不可访问(方法不存在或被定义为 protectedprivate)的方法时,会被调用。$name为不可访问的方法名,$arguments为访问时传的参数。
class B {
    public static function __callStatic($name, $arguments)
    {
        echo $name.\'<br>\';
        var_dump($arguments);
    }
}
$b = new B;
B::getAge(\'static method\');// getAge Array ( [0] => static method )
  • __get($name):服务不可访问(不存在或设置为非public)属性时,会被调用。$name为访问的属性的名称。
class B {
    private $name = \'jeccy\';
    public $age = 2;
    protected $sex = 1;
    public function __get($name)
    {
        echo \'属性\'.$name.\'不存在或不可被访问<br>\';
    }
}
$b = new B;
echo $b->name; // 属性name不存在或不可被访问
echo $b->age;  // 2
echo $b->sex;  // 属性sex不存在或不可被访问
echo $b->address; // 属性address不存在或不可被访问
  • __set(string $name, mixed $value):在给不可访问的属性赋值时,会被调用。$name为不可访问的属性的名称;$value为给属性赋的值。
class B {
    private $name = \'jeccy\';
    public $age = 2;
    protected $sex = 1;
    public function __set($name, $value)
    {
        $this->$name = $value;
    }
    public function getInfo()
    {
        echo \'name=\'.$this->name.\',\';
        echo \'age=\'.$this->age.\',\';
        echo \'sex=\'.$this->sex;
        echo \'sex=\'.$this->sex;
    }
}
$b = new B;
$b->name = \'mark\';
$b->age = 3;
$b->sex = 2;
$b->address = 2;
$b->getInfo(); // name=mark,age=3,sex=2,address=2

*__isset(string $name):当被不可访问属性调用 isset()empty()时,此方法会被调用。$name为访问的属性名。

class B {
    private $name = \'jeccy\';
    public $age = 2;
    protected $sex = 1;
    public function __isset($name)
    {
        echo isset($this->$name) ? $name.\'存在<br>\' : $name.\'不存在<br>\';
    }
    public function getInfo()
    {
        echo \'name=\'.$this->name.\',\';
        echo \'age=\'.$this->age.\',\';
        echo \'sex=\'.$this->sex;
    }
}
$b = new B;
isset($b->name); // name属性存在
isset($b->age); // age属性可以访问,故不会调用 __isset() 方法
isset($b->sex); // sex属性存在
isset($b->address); // address属性不存在
  • _unset(string $name):当对不可访问属性调用unset()时,会被调用。参数 $name是指要访问的变量名称。
class B {
    private $name = \'jeccy\';
    public $age = 2;
    protected $sex = 1;
    public function __unset($name)
    {
        unset($this->$name);
    }
    public function getInfo()
    {
        var_dump($this);
    }
}
$b = new B;
unset($b->name); // name存在
unset($b->age); // age属性可以访问,故不会调用 __isset() 方法
unset($b->sex); // sex存在
unset($b->address); // address不存在
$b->getInfo(); // D:wamp64wwwmineaa.php:14: object(_B_)[_1_]
  • __sleep():当在类外部对对象使用serialize()方法时,会调用此方法。可以用来对对象中的属性做一个处理操作,例如数据处理,或者是仅返回需要序列化的属性。该方法返回一个数组,由需要序列化的属性组成。
class B {
    private $name = \'jeccy\';
    public $age = 2;
    protected $sex = 1;
    public function __sleep()
    {
        return array(\'sex\',\'age\',\'name\');
    }
}
$b = new B;
echo serialize($b); // O:1:"B":3:{s:6:"*sex";i:1;s:3:"age";i:2;s:7:"Bname";s:5:"jeccy";}

7,静态属性和静态方法(参考:https://www.cnblogs.com/chrdai/p/6863090.html)

以上是关于PHP面试题的主要内容,如果未能解决你的问题,请参考以下文章

PHP面试题

PHP笔记题

Java进阶之光!2021必看-Java高级面试题总结

PHP面试题2

2019年最新PHP面试题

关于mysql面试题