PHP知识点-1

Perl
• 阅读 2101

1.字符串的使用

可将字符串当作一个字符的集合来使用,可独立访问每个字符。仅适用于单字节字符(字母、数字、半角标点符号),像中文等不可用(utf8下,中文3字节表示)
$str = "abcd";
echo $str[3];   // d
echo $str{0};   // a
//另一种方式
也可以使用str_split把所有字符分割成数组。
$strArr = str_spilt($str);   //同样不适合中文
Array
(
    [0] => a
    [1] => b
    [2] => c
    [3] => d
)
function mb_str_split($str){
    return preg_split('/(?<!^)(?!$)/u', $str );   //反向预搜索
}
$str='博客';
mb_str_split($str);
打印结果如下:
Array
(
    [0] => 博
    [1] => 客
)

2.转换类型

平时 我们知道在变量前,加上(int), (string), (float) 之类的即可进行显示转换,下面介绍一种,可直接转换为null的 转换,。
(unset) //转换为NULL

$a = 'a';
$a = (unset)$a;  //此时$a 为 NULL
//换种方式
$a = 'a';
unset($a);
dd($a);
//报错
PHP Notice:  Undefined variable: a in test.php on line 39

Notice: Undefined variable: a in test.php on line 39

3.isset 和 empty, is_null 对变量的检测

3.1 isset 要检测变量不存在则, 返回 false; 但需要注意,变量是否本身为 Null值, 如果是,也返回 false; 都不满足则返回true了 。
为了更方便检测变量是否存在,可使用
建议用array_key_exists判断

$a = null;
$varExists = array_key_exists('a', get_defined_vars());
if($varExists){
        echo '变量a是存在的';
}

PHP知识点-1
3.2 empty, 检测变量不存在,与各个空值,0值都为true, 否则为 false
3.3 is_null
当参数满足下面三种情况时,is_null()将返回TRUE,其它的情况就是FALSE
1、它被赋值为NULL
2、它还没有赋值
3、它未定义,相当于unset(),将一个变量unset()后,不就是没有定义吗

4.static 的部分用法

我们都知道 static 可以直接定义静态变量和 静态方法, 无论是调用静态变量和静态方法, 用 :: 即可调用, 如果是本类,则使用self 调用, 如果是在类
外部,则使用类名进行调用, 但这里对其不进行过多赘述,这些都是比较常用。下面讲下不常用的。

static在类中的延迟静态绑定;

延迟静态绑定是指允许在一个静态继承的上下文中引用被调用类。
延迟绑定的意思为:static::不再为定义当前方法所在的类,而是实际运行时所在的类。
(总的意思就是子类继承了父类后,父类中使用了一个静态方法或变量,如static::A(), 但方法A不存在于父类中,
存在于子类中,这样写是正确的,不会因为方法不存在而报错,因为static 修饰的A 会在执行过程中,绑定到具体的子类
上,只要保证子类有此方法即可)
注:它可以用于(但不限于)静态方法的调用。
self::,代表本类(当前代码所在类)
    永远代表本类,因为在类编译时已经被确定。
    即,子类调用父类方法,self却不代表调用的子类。
parent:: 代表父类
static::,代表本类(调用该方法的类)
    用于在继承范围内引用静态调用的类。
    运行时,才确定代表的类。
    static::不再被解析为定义当前方法所在的类,而是在实际运行时计算的。
除了简单的static延迟绑定的用法,还有一种转发调用,
forward_static_call_array()(该函数只能在方法中调用)将转发调用信息(不过多赘述,类似于本节的第8点,PHP反射),
概括实例如下:
class A {
    public static function fooStatic() {
        static::who();
    }
    public static function who() {
        echo __CLASS__."aaa\n";
    }
}
class B extends A {
    public static function testStatic() {
        A::fooStatic();
        B::fooStatic();
        C::fooStatic();
        parent::fooStatic();
        self::fooStatic();
    }
    public static function who() {
        echo __CLASS__."bbb\n";
    }
}
class C extends B {
    public static function who() {
        echo __CLASS__."ccc\n";
    }
}
C::testStatic();
大家一起来得到答案:

5. array_merge 和 + , 合并数组

5.1 array_merge 合并两个或多个数组的时候, 如果键名是非数字,则会自动合并到一起,但若出现重复的键名,后面的会覆盖前面的。若键名为数字,其会根据前一个数组的索引值,自动给后面的更改索引值为前面的递增,也就是说会改变原有的键名。

5.2 + 合并数组, 使用+ 号 合并数组,键名相同的情况下,最先出现的键名会被保留, 并且即使键名是数字,也不会被重新编排,这个特性对部分业务场景会非常有用。

5.3 array_push, 仅仅是把对应值完全放到数组末尾, 原来的结构会被保留,整个作为一个新的值, 键名跟着前一个递增。这与array_merge 有所区别

5.4 array_combine, 两个参数, 第一个参数,作为新数组的键, 第二个参数作为新数组的值。 并不是给原有数组增添新值。所以其实他不同于 上面三个的作用。 光从名字上看容易混淆。

$a = ['a', 'b', 'c'];
$b = ['5' => 'test'];
$c = [1, 2, 3];

$arrayMerge   = array_merge($a, $b);
$arrayPlus    = $a + $b;
$arrayCombine = array_combine($a, $c);
array_push($a, $b);
// $arrayMerge
Array
(
    [0] => a
    [1] => b
    [2] => c
    [3] => test
)
// $arrayPlus
Array
(
    [0] => a
    [1] => b
    [2] => c
    [5] => test
)
// $arrayCombine
Array
(
    [a] => 1
    [b] => 2
    [c] => 3
)
// array_push
Array
(
    [0] => a
    [1] => b
    [2] => c
    [3] => Array
        (
            [5] => test
        )

)

6. 指针

数组的内部指针:
current/pos 返回当前被内部指针指向的数组单元的值,并不移动指针。
key         返回数组中当前单元的键名,并不移动指针
next        将数组中的内部指针向前移动一位,并返回移动后当前单元的值。先移动,再取值。
prev        将数组的内部指针倒回一位,并返回移动后当前单元的值先移动,再取值。
end         将数组的内部指针指向最后一个单元,并返回最后一个单元的值
reset       将数组的内部指针指向第一个单元,并返回第一个数组单元的值
each        返回数组中当前的键/值对并将数组指针向前移动一步。
            返回的是一个由键和值组成的长度为4的数组,下标0和key表示键,下标1和value表示值
在执行each()之后,数组指针将停留在数组中的下一个单元或者当碰到数组结尾时停留在最后一个单元。如果要再用 each 遍历数组,必须使用 reset()。
1. 以上指针操作函数,除了key(),若指针移出数组,则返回false。而key()移出则返回null。
2. 若指针非法,不能进行next/prev操作,能进行reset/end操作
3. current/next/prev     若遇到包含空单元(0或"")也会返回false。而each不会!

list    把数组中的值赋给一些变量。list()是语言结构,不是函数。
仅能用于数字索引的数组并假定数字索引从0开始
/* 可用于交换多个变量的值 */ 
list($a, $b) = array($b, $a);
例:list($drink, , $power) = array('coffee', 'brown', 'caffeine');
1. 复制数组,其指针位置也会被复制。
    特例:如果数组指针非法,则拷贝的数组指针会重置,而原数组的指针不变。
    【指针问题】
        谁第一个进行写操作,就会开辟一个新的值空间。与变量(数组变量)值传递给谁无关。
        数组函数current()被定义为写操作,故会出现问题。
        foreach遍历的是数组的拷贝,当被写时,才会开辟一个新的值空间。
            即,foreach循环体对原数组进行写操作时,才会出现指针问题。
            如果开辟新空间时指针非法,则会初始化指针。
2. 如果指针位置出现问题,则reset()初始化一下就可解决。

7. 序列化(串行化)

# 数据传输均是字符串类型
# 除了资源类型,均可序列化
# 序列化在存放数据时,会存放数据本身,也会存放数据类型
作用:1.在网络传输数据时;2.为了将数组或对象放在磁盘时
# 序列化
serialize        产生一个可存储的值的表示
string serialize ( mixed $value )
- 返回字符串,此字符串包含了表示value的字节流,可以存储于任何地方。
- 有利于存储或传递 PHP 的值,同时不丢失其类型和结构。
# 反序列化
unserialize        从已存储的表示中创建PHP的值
mixed unserialize ( string $str [, string $callback ] )
- 对单一的已序列化的变量进行操作,将其转换回PHP的值。

8.PHP反射

有时候我们我们为了能建立更好的代码结构,并能复用代码,就需要用到一些语言的特性来帮助我们完成任务,比如我们这次新建的仓库 trinity_middle_service, 我们需要利用PHP自带函数, 如call_user_func_array, 即可简单实现分发。使用方式如下:

class Order{
    public function getBasicInfo($orderId, $write = false)
    {
    }
}
$detailServiceInstance = new Order();
$functionName = 'getBasicInfo';
$params[0] = 1000001;    //或 $params['orderId'] = 1000001
$params[1] = true;       //或 $params['write'] = true
call_user_func_array([$detailServiceInstance, $functionName], $params);

从以上代码可看出, call_user_func_array 第一个参数是个数组, 该数组中0下标的值 为 一个类的实例, 1下标的 是这个实例中存在的方法; 第二个参数即 对应函数需要的参数了,该参数为数组形式,call_user_func_array 会自动 按顺序对应每一个参数,所以在这里,参数的顺序很重要,无论是使用数字键名或字符键名,都必须一一对应函数具体的参数,这样才能正确实现函数的分发。

8.1 反射的应用

使用call_user_func_array,我们可以简单的实现分发,并且各个参数,也都很清晰。但是如果需要更加灵活的运用这个函数,我们还需要引入PHP的反射机制,如 PHP自带的 ReflectionMethod 类,

我们可以通过这个类,来直接获取到某个类中具体方法的各类信息,如参数个数,参数名,是否有默认值等等。代码如下:
$object = new Order();
$functionName = 'getBasicInfo';
$reflectionObj = new \ReflectionMethod($object, $functionName);
//通过以上的代码后,就可以直接通过$reflectionObj获取相关信息了,如下
$reflectionObj->isPublic();   //可判断该方法是否为公有方法, 还有isPrivate, isProtected, isStatic等等
$reflectionObj->getParameters();   //可获取该方法所有参数,是个数组,可 foreach获取具体的参数
foreach($reflectionObj->getParameters() as $arg) {
    if(array_key_exists($arg->name, $params)) {
        $callParams[$arg->name] = $params[$arg->name];
    } else {
        $paramVal = null;
        if ($arg->isOptional()) {  // 或使用isDefaultValueAvailable, 检测是否有可用的默认值
            $paramVal = $arg->getDefaultValue();
        }
        $callParams[$arg->name] = $paramVal;
    }
}
具体参数: https://www.php.net/manual/zh/class.reflectionmethod.php

还有 ReflectionClass 可以获取一些类的信息,用法都是类似的。

8.2 调用不存在的方法

__call & __callStatic (魔术方法)
当调用类中一个不存在或者没有权限访问的方法的时候,就会自动调用__call()方法。和__call对应静态方法的调用是__callStatic, 配合PHP反射,对代码进行优化,可对一些特殊的基础业务功能做到,
如工单, trinity 内部都是用了类似方法。

9. move_uploaded_file

该函数是前端文件上传文件到后台后可能用到的函数,上传后,我们会通过$_FILES['file']'tmp_name', 使用

move_uploaded_file($tmp_name, $savePath);

会把临时存到数据库的 如: /tmp/phpwTJzUw 文件给移动走,导致如果后面的代码还要用到$_FILES全局变量的时候,会出现找不到文件的问题。

10.引用传递

在使用array_pop等函数时, array_pop的参数 是引用传递,在编码过程中有时候会把 参数直接写成函数返回值,这样在 5.3以后是不允许的, 会报出致命错误(严格模式下)。

You will see:
PHP Strict Standards:  Only variables should be passed by reference in - on line 3

Strict Standards: Only variables should be passed by reference in - on line 3
d
以上来自于: https://www.php.net/manual/zh/function.array-pop.php

按引用传递参数的函数在被按值传递调用时行为发生改变. 此前函数将接受按值传递的参数, 现在将抛出致命错误. 之前任何期待传递引用但是在调用时传递了常量或者字面值 的函数, 需要在调用前改为将该值赋给一个变量。
以上来自于:PHP手册附录从PHP 5.2.x 移植到 PHP 5.3.x 部分
https://www.php.net/manual/zh/migration53.incompatible.php

而实际上看起来没有错, 只需要把那个函数返回值赋值给一个变量,再把变量当做参数传入就可以了。
如,在代码中经常会写到:

error_reporting(E_STRICT);
$testArr = ['a','b','c','c','d'];
$popValue = array_pop(array_unique($testArr));  
// 以上代码会报错,必须使用
$testArr = ['a','b','c','c','d'];
$testArr = array_unique($testArr)
$popValue = array_pop($testArr);
点赞
收藏
评论区
推荐文章
风花雪月 风花雪月
4年前
报错'gb2312' codec can't decode byte 0x9e in position 4100: illegal multibyte sequence,“gb2312”编解码器无法解码位置4100中的字节0x9e:非法的多字节序列
“gb2312”编解码器无法解码位置4100中的字节0x9e:非法的多字节序列。处理方式:withopen(path,encoding"utf8",errors'ignore')asf:使用errors'ignore'去掉(忽略)字符并返回不带字符的字符串。
秋刀鱼 秋刀鱼
4年前
Java字符串:内存分析/方法梳理
近期在学习Java字符串,梳理总结一下,更多是关于内存角度去分析,希望对你有帮助。一、Java字符串的特性1.java.lang.String使用的final修饰,不能被修饰2.字符串底层封装了字符数组以及针对字符串数组的操作算法3.Java使用的是Unicode编码方式,任何一个字符对应两个字节的编码4.字符串一旦创建,对象内容不能改变,
Wesley13 Wesley13
4年前
PHP 截取字符串
1.截取GB2312中文字符串<?php//截取中文字符串functionmysubstr($str,$start,$len){$tmpstr"";$strlen$start$len;for($i0;
Stella981 Stella981
4年前
Lua学习笔记_String(一)
   Lua中的字符串可以包含一个字母也可以是一整本书。用一个字符串表示100K甚至1M的内容在Lua中并不罕见。     在Lua中,字符串是字节的序列。Lua内核中不关心这些字节是什么编码格式。Lua只是单纯地以8bit为单位保存它们,且每个字节可以是任意数字,包括0。这就意味着我们可以用字符串保存任意二进制数据。也可以将Unicode字符串保存为任
Stella981 Stella981
4年前
RedisTemplate操作命令
字符串操作redis储存的字符串都是以二进制的形式存在!字符串类型的内部编码有3种:int:8个字节的长整型。embstr:小于等于39个字节的字符串。raw:大于39个字节的字符串。Redis会根据当前值的类型和长度决定使用哪种内部编码实现。命令操作返回值set(K
Wesley13 Wesley13
4年前
PHP_50则
用单引号代替双引号来包含字符串,这样做会更快一些。因为PHP会在双引号包围的字符串中搜寻变量,单引号则不会,注意:只有echo能这么做,它是一种可以把多个字符串当作参数的“函数”(译注:PHP手册中说echo是语言结构,不是真正的函数,故把函数加上了双引号)。1、如果能将类的方法定义成static,就尽量定义成static,它的速度会提升将近4倍。
Wesley13 Wesley13
4年前
MySQL 数据类型
在MySQL中,有三种主要的类型:文本、数字和日期/时间类型。Text类型:数据类型描述备注CHAR(size)保存固定长度的字符串(可包含字母、数字以及特殊字符)。在括号中指定字符串的长度。最多255个字符。VARCHAR(size)保存可变长度的字符串(可包含字母、数字以及特殊字符)。在括号中指定字符串
Wesley13 Wesley13
4年前
VC++中关于TCHAR,WCHAR,LPSTR,LPWSTR,LPCTSTR的解释
一般来说,一个字符(character)占用1字节或是2字节,我们说1字节的字符是ANSI,他可以用来表示英语字母,而2字节的我们称之为Unicode,可以表示世界上所有的语言。。VC使用char和wchar\_t的内置数据类型来分别作为表示ANSI和Unicode字符。如果你想让你的C/C程序是字符集无关的,该怎么做呢?如果你用通
Wesley13 Wesley13
4年前
PHP心得
1,花括号“{}”可以像“\\”操作数组一样操作字符串,来获得指定位置的字符。2,PHP标签“<?php?”在独立PHP脚本内可以不写结束标签,这是为了避免意外的空格导致输出而报错。可以用注释来标明脚本结束。3,echo是语法结构,不是函数。后面跟多个字符串时用逗号“,”效率更好。4,数组中,1、'1'、true为
Wesley13 Wesley13
4年前
Java基础之字符串
5.1字符字符指的用单引号括起来的单个字母。java中,char表示字符的数据类型。一个字符在内存中占16位大小的空间(2个字节)。5.2字符串字符串或串是由零个或多个字符组成的有限序列,它是编程语言表示文本的数据类型。串的两个最基本的存储方式是顺序存储方式和链接存储方式5.2.1字符串声明与赋值String是字符串变量的类型
Wesley13 Wesley13
4年前
10条PHP编程习惯助你找工作
http://blog.csdn.net/yihan1029/article/details/417664131、使用单引号括起来的字符串当使用双引号来括字符串时,PHP(https://www.oschina.net/p/php)解释器会对其进行变量替换、转义等操作,如“\\n”。如果只想输出一个基本的字符串,用单引号会节