ホームページ > バックエンド開発 > PHPチュートリアル > php实现restful api有什么框架使用方便?

php实现restful api有什么框架使用方便?

WBOY
リリース: 2016-06-06 20:23:06
オリジナル
1823 人が閲覧しました

php框架比较多,想实现restful api用哪个比较流行

回复内容:

php框架比较多,想实现restful api用哪个比较流行

我目前在用 SlimFramework 做微信的开发及编写一些 Restful API .感觉还不错。你可以了解一下.

官方地址:http://www.slimframework.com
中文文档:http://tutorial.jingwentian.com/slim/ 注:版本:2.x

我是来说反例的,但凡用以下风格实现controller的,实现RESTFul都很不方便

<code>class Controller {
    public function actionFoo() {}
    public function actionBar() {}
}
</code>
ログイン後にコピー

因为RESTFul是对HTTP动作(GET/POST/PUT/DELETE/...)敏感的,用这种风格的Controller的框架来实现就不可避免的会出现以下这种代码

<code>class Controller {
    public function actionFoo() {
        if (is_get) {
            /* 一坨代码 */
        } else if (is_post) {
            /* 一坨代码 */
        } else if (is_put) {
            /* 一坨代码 */
        } else if (is_delete) {
            /* 一坨代码 */
        }
    }
}
</code>
ログイン後にコピー

很恶心吧,可惜的是,大部分的框架都是这种风格的Controller实现,差不多都成为标准了

当然了,Laravel也无法免俗。不过Laravel稍微把这个代码优化了一下,大概的逻辑差不多是这样

<code>class Controller {
    public function actionFoo() {
        if (is_get) {
            return $this->getAction();
        } else if (is_post) {
            return $this->postAction();
        } else if (is_put) {
            return $this->putAction();
        } else if (is_delete) {
            return $this->deleteAction();
        }
    }

    private function getAction() {}
    private function postAction() {}
    private function putAction() {}
    private function deleteAction() {}
}
</code>
ログイン後にコピー

Laravel里面真正的代码当然不可能是上面这样了,但是逻辑就是这么回事,框架帮你把不同的HTTP verb调用了不同的action,把这个路子套到了classic controller里面去

<code>// 就是这样,这是从Laravel手册里面copy的
class UserController extends BaseController {

    public function getIndex()
    {
        //
    }

    public function postProfile()
    {
        //
    }

}
</code>
ログイン後にコピー

的确能用,但是不足够好。因为本质上都是从classic controller的角度出发,然后对RESTFul进行迁就的设计

比如一个需求,根据http协议,对一个不支持post的url发起post,应该响应http 405 (method not allowed),这些框架应该怎么做才方便呢?

必须提 Yii2

因为框架使用的不是很多,所以不太好推荐哪个框架使用起来比较方便,目前自己使用的 YII 实现起来就很方便,但是无论题主最后使用哪个框架,API 都是要根据需求自己来设计实现的,建议题主读下这篇文章:

《Best Practices for Designing a Pragmatic RESTful API》

另外,@lenbo_ma 的博文也很值得一读:《HTTP API响应数据规范整理》

楼上吐槽php写API必要有一堆条件判断的朋友,restful这个难道不判断get/post/put/delete条件语句,还有更好的办法吗?

若是说真的好,golang最好

SlimFramework,挺有趣的!赞

一提到rest,就非得支持啥put、delete这些请求,感觉很无聊,我认为post和get就能应付的了我们所有的请求了。

Apigility by Zend Framework 2.

Phalcon C扩展 简单的路由,超高的效率

居然没看到symfony2的 symfony2

基于symfony2的一些web service的bundle

FOSRestBundle
FOSOAuthServerBundle
JMSSerializerBundle
NelmioApiDocBundle
RequestLimitBundle
RateLimitBundle
BazingaHateoasBundle
KnpJsonSchemaBundle
LexikJWTAuthenticationBundle
ResourceBundle
SerializedResponseBundle
NelmioCorsBundle
还有silex

推荐一个 recess 应该会对你有所启发,restful 关键不在于框架的选择,而是你如何理解、实现restful。相比于其他框架,我更喜欢 recess 使用 Annotation 来实现的Router的方式,但显然性能差了点。当然它能在 Annotation 数据跟权限的 Validation 更好了。

ToroPHP 居然没人推荐这个 专门为restful api设计的啊。

楼主的话有定的道理,laravel号称巨匠级,那是自称。用了symfony再看lavravel,其实很糙……包括orm,实在是很弱啊……内部写法太不OO了。
个人认为,laravel就是个阉割了的速成版symfony2。不知大家怎么看?

YIIorYII2

其实 Laravel 做 RESTful 是很适合的。Laravel 4 中可以用 Route::resource 直接设置 RESTful 路由,而 Laravel 5 中引入了路由注释的功能,只需要在 Controller 指定@Resource("...")即可,而且每一个 Action 通过注释都可以反向生成路由。Laravel 生成 Controller 只需要一条命令就可以搞定:

<code>php artisan make:controller UserController
</code>
ログイン後にコピー

http://book.cakephp.org/3.0/en/development/rest.html CakePHP 3.0 对REST 支持很强大的。

推荐一款非常适合RESTful和微服务接口的框架 PHPRS@github

让你在这些场景下彻底摆脱MVC。

看个例子,这是一个可能的登录接口实现,只需要编写下面代码,无效额外的继承和配置:

<code class="PHP">/**
 * 用户鉴权
 * @path("/tokens/") 
 */
class Tokens
{ 
    /**
     * 登录
     * @route({"POST","/accounts/"}) 
     * @param({"account", "$._POST.account"}) 账号
     * @param({"password", "$._POST.password"}) 密码
     * @return({"body"})    也通过body返回token,同cookie中的token相同, {"token":"xxx"}
     * @return({"cookie","token","$token","+365 days","/"})  通过cookie返回token
     */
    public function createTokenByAccounts($account, $password, &$token){
        //验证用户
        $token = ...;
        return ['token'=>$token];
    } 
}</code>
ログイン後にコピー

框架通过@注释定义路由和绑定参数,另外还有一些有用的高级特性:依赖注入、自动化接口文档、接口缓存等。
虽然这个框架github上看上去比较新,但其实目前已经很稳定,可以用于线上环境。

Laravel +1

laravel +1

Laravel是有Resource Controller的

相关文档
http://www.golaravel.com/docs/4.1/controllers/#resource-controllers

这是通过generator自动创建的controller的代码
请参考一下注释中HTTP verb 和 url的匹配

class CommentsController extends \BaseController {

<code>/**
 * Display a listing of comments
 *
 * get comments
 *
 * @return Response
 */
public function index() {}

/**
 * Show the form for creating a new comment
 *
 * get comments/create
 *
 * @return Response
 */
public function create(){}

/**
 * Store a newly created comment in storage.
 *
 * post comments
 *
 * @return Response
 */
public function store() {}

/**
 * Display the specified comment.
 *
 * get comments/(:id)
 *
 * @param  int  $id
 * @return Response
 */
public function show($id){}

/**
 * Show the form for editing the specified comment.
 *
 * get comments/(:id)/edit
 *
 * @param  int  $id
 * @return Response
 */
public function edit($id){}

/**
 * Update the specified resource in storage.
 *
 * put comments/(:id)
 *
 * @param  int  $id
 * @return Response
 */
public function update($id){}

/**
 * Remove the specified resource from storage.
 *
 * delete comments/(:id);
 *
 * @param  int  $id
 * @return Response
 */
public function destroy($id){}
</code>
ログイン後にコピー

}

ZendFrame Work

laravel ++++++++1

YII或者YII2.除了这两个,没有之一。为什么?因为我看见laravel还是什么的竟然用if-else来做Restfull
关于实现RestFullAPI。看这里:
https://github.com/evan108108/RESTFullYii
这个是全部RESTFULL的,完全满足楼主的要求。看看它的这个扩展关于How it works说明:
How it works
RestfullYii adds a new set of RESTFul routes to your standard routes, but prepends '/api' .
So if you apply RestfullYii to the 'WorkController' you will get the following new routes by default.
[GET] http://yoursite.com/api/work (returns all works)
[GET] http://yoursite.com/api/work/1 (returns work with PK=1)
[POST] http://yoursite.com/api/work (create new work)
[PUT] http://yoursite.com/api/work/1 (update work with PK=1)
[DELETE] http://yoursite.com/api/work/1 (delete work with PK=1)
为什么我会推荐YII。先看看这位的回答:
http://segmentfault.com/q/1010000000500665#a-1020000000503507
这位兄台肯定没有见过纯面向对象的形式,以为所有的人都像他一样动不动就if-else。还有看到laravel 这样竟然用if-else的实现我就笑了。
YII实现Restfull没有用到所谓的if-else,所有的实现都是纯面向对象,读完他的代码,你就知道这设计的简直太他妈精妙了,然后你读别的框架的代码,你就会很高兴,因为他写的你完全看得懂,比如if-else。

看了各个框架对RestfullAPI的实现,我才知道了哪些框架是真的牛逼,哪些框架是在装牛逼。
不多说,看一看YII如何实现Restfull,我只贴上将一个PUT动作封装成一个类的代码代码,楼主再去看看所谓的laravel 的代码,高下立见:

<code class="lang-php"><?php Yii::import('RestfullYii.actions.ERestBaseAction');

/**
 * Action For Rest Puts
 *
 * Provides the action for rest put behavior
 *
 * @category   PHP
 * @package    Starship
 * @subpackage Restfullyii/actions
 * @copyright  Copyright (c) 2013 Evan Frohlich (https://github.com/evan108108)
 * @license    https://github.com/evan108108   OSS
 * @version    Release: 1.2.0
 */
class EActionRestPUT extends ERestBaseAction
{
    /**
     * run
     *
     * Called by Yii for PUT verb
     * 
     * @param (Mixed/Int) (id) unique identifier of the resource
     * @param (Mixed) (param1) first param sent in the request; Often subresource name
     * @param (Mixed) (param2) Second param sent in the request: Often subresource ID
     */
    public function run($id=null, $param1=null, $param2=null) 
    {
        $this->finalRender(function($visibleProperties, $hiddenProperties) use($id, $param1, $param2) {
                switch ($this->getRequestActionType($id, $param1, $param2, 'put')) {
                    case 'RESOURCES':
                        throw new CHttpException('405', 'Method Not Allowed');
                        break;
                    case 'CUSTOM':
                        return $this->controller->emitRest("req.put.$id.render", [$this->controller->emitRest(ERestEvent::REQ_DATA_READ), $param1, $param2]);
                        break;
                    case 'SUBRESOURCES':
                        throw new CHttpException('405', 'Method Not Allowed');
                        break;
                    case 'SUBRESOURCE':
                        return $this->controller->emitRest(ERestEvent::REQ_PUT_SUBRESOURCE_RENDER, [
                            $this->handlePutSubresource($id, $param1, $param2),
                            $param1,
                            $param2,
                            $visibleProperties,
                            $hiddenProperties,
                        ]);
                        break;
                    case 'RESOURCE':
                        return $this->controller->emitRest(ERestEvent::REQ_PUT_RESOURCE_RENDER, [$this->handlePut($id), $this->getRelations(), $visibleProperties, $hiddenProperties]);
                        break;
                    default:
                        throw new CHttpException(404, "Resource Not Found");
                }
            }
        );
    }

    /**
     * handlePut
     *
     * Helper method for PUT actions
     *
     * @param (Mixed/Int) (id) unique identifier of the resource to put
     *
     * @return (Object) Returns the model of the updated resource
     */ 
    public function handlePut($id)
    {
        $model = $this->controller->emitRest(
            ERestEvent::MODEL_ATTACH_BEHAVIORS,
            $this->getModel($id)
        );
        $data = $this->controller->emitRest(ERestEvent::REQ_DATA_READ); 
        $restricted_properties = $this->controller->emitRest(ERestEvent::MODEL_RESTRICTED_PROPERTIES);
        $model = $this->controller->emitRest(ERestEvent::MODEL_APPLY_PUT_DATA, [$model, $data, $restricted_properties]);
        return $this->controller->emitRest(ERestEvent::MODEL_SAVE, [$model]);
    }

    /**
     * handlePutSubresource
     *
     * Helper method for PUT subresource actions
     *
     * @param (Mixed/Int) (id) unique identifier of the resource
     * @param (String) (subresource_name) name of the subresource
     * @param (Mixed/Int) (subresource_id) unique identifier of the subresource to put
     *
     * @return (Object) Returns the model containing the updated subresource
     */ 
    public function handlePutSubresource($id, $subresource_name, $subresource_id)
    {
        $model = $this->controller->emitRest(
            ERestEvent::MODEL_ATTACH_BEHAVIORS,
            $this->getModel($id)
        );
        $this->controller->emitRest(ERestEvent::MODEL_SUBRESOURCE_SAVE, [$model, $subresource_name, $subresource_id]);
        return $model;
    }
}
</code>
ログイン後にコピー

如果Laravel有这么优雅的代码,我立马把电脑吃了。来看看Laravel所谓的优雅代码:

<code class="lang-php"><?php class Blog_Controller extends Base_Controller
{
    public function action_index()
    {
            // lets get our posts and eager load the
        // author
        $blogs = Blog::with('author')->order_by('created_at', 'desc')->paginate(20);
        // show the home view, and include our
        // posts too
        //$posts->appends(array('a' => 'app'));
        //print_r($blogs);exit;
        return View::make('blog.index')->with('blogs', $blogs);
    }

    public function action_add()
    {
        $method = Request::method();
        if($method =='POST'){


            // let's setup some rules for our new data
            // I'm sure you can come up with better ones
       $rules = array(
        'title'     => 'required|min:3|max:128',
        'content'       => 'required',  
        'file' => 'mimes:jpg,gif,png'   
        );
        //
        //Input::upload('picture', 'path/to/pictures', 'filename.ext');
        //File::cpdir($directory, $destination);
        //File::rmdir($directory);
        //echo File::mime('gif'); // outputs 'image/gif'
        //if (File::is('jpg', 'path/to/file.jpg'))
        //{
        //File::extension('picture.png');File::delete('path/to/file');
        //File::append('path/to/file', 'appended file content');
        //}File::put('path/to/file', 'file contents');$contents = File::get('path/to/file');
        // make the validator
            // let's get the new post from the POST data
            // this is much safer than using mass assignment
        $image = Input::file();
        $pictrue = '';
        $title = Input::get('title');
        $content = Input::get('content');
        $description = Input::get('title');
        if(empty($description)) $description = substr($content,0, 120);
        $author_id =Input::get('author_id');
        $tags =Input::get('tags');
        if(!empty($image['file']['name'])){
            $ext = File::extension($image['file']['name']);//$image['file']['tmp_name']
            Input::upload('file', path('public').'data', md5(date('YmdHis').$image['file']['name']).'.'.$ext);
            $pictrue = md5(date('YmdHis').$image['file']['name']).'.'.$ext;
        }

        $new_blog = array(
        'title'     => $title,
        'description'   => $description,
        'content'       => $content,
        'author_id' => $author_id,
        'views' => 0,
        'pictrue'   => $pictrue,
        'tags'   => $tags
            );
        $v = Validator::make($new_blog, $rules);

        if ( $v->fails() )
        {
            // redirect back to the form with
            // errors, input and our currently
            // logged in user
            return Redirect::to('blog/add')
            ->with('user', Auth::user())
            ->with_errors($v)
            ->with_input();
        }


        // create the new post
        $blog = new Blog($new_blog);
        $blog->save();

        // redirect to viewing our new post
        return Redirect::to('blog/view/'.$blog->id);
        }
        else{
            // get the current user
            $user = Auth::user();

            // show the create post form, and send
            // the current user to identify the post author
            return View::make('blog.add')->with('user', $user);
        }


    }

    public function action_edit($id)
    {
        $method = Request::method();
        $user = Auth::user();

        $blog = Blog::find($id);
        if($user->id != $blog->author->id)
        {
            return View::make('blog.view')
            ->with('blog', $blog);
        }
        if($method =='POST')
        {

            // let's setup some rules for our new data
            // I'm sure you can come up with better ones
       $rules = array(
        'title'     => 'required|min:3|max:128',
        'content'       => 'required',  
        'file' => 'mimes:jpg,gif,png'   
        );
        //
        //Input::upload('picture', 'path/to/pictures', 'filename.ext');
        //File::cpdir($directory, $destination);
        //File::rmdir($directory);
        //echo File::mime('gif'); // outputs 'image/gif'
        //if (File::is('jpg', 'path/to/file.jpg'))
        //{
        //File::extension('picture.png');File::delete('path/to/file');
        //File::append('path/to/file', 'appended file content');
        //}File::put('path/to/file', 'file contents');$contents = File::get('path/to/file');
        // make the validator
            // let's get the new post from the POST data
            // this is much safer than using mass assignment
        $image = Input::file();
        $pictrue = '';
        $title = Input::get('title');
        $content = Input::get('content');
        $description = Input::get('title');
        if(empty($description)) $description = substr($content,0, 120);
        $author_id =Input::get('author_id');
        $tags =Input::get('tags');
        if(!empty($image['file']['name'])){
            $ext = File::extension($image['file']['name']);//$image['file']['tmp_name']
            Input::upload('file', path('public').'data', md5(date('YmdHis').$image['file']['name']).'.'.$ext);
            $pictrue = md5(date('YmdHis').$image['file']['name']).'.'.$ext;
        }

        $new_blog = array(
        'title'     => $title,
        'description'   => $description,
        'content'       => $content,
        'author_id' => $author_id,
        'views' => 0,
        'pictrue'   => $pictrue,
        'tags'   => $tags
            );
        $v = Validator::make($new_blog, $rules);

        if ( $v->fails() )
        {
            // redirect back to the form with
            // errors, input and our currently
            // logged in user
            return Redirect::to('blog/add')
            ->with('user', Auth::user())
            ->with_errors($v)
            ->with_input();
        }

        $blog->title = $title;
        $blog->description = $description;
        $blog->content = $content;
        $blog->author_id = $author_id;
        $blog->tags = $tags;
        if(!empty($pictrue)) $blog->pictrue = $pictrue;
        $blog->save();

        // redirect to viewing our new post
        return Redirect::to('blog/view/'.$blog->id);
        }
        else
        {

            // show the full view, and pass the post
            // we just aquired
            return View::make('blog.edit')->with('blog', $blog);
        }
    }

    public function action_view($id)
    {
        // get our post, identified by the route
        // parameter
        $blog = Blog::find($id);
        $blog->views += 1;
        $blog->save();
        // show the full view, and pass the post
        // we just aquired
        return View::make('blog.view')
        ->with('blog', $blog);
    }

    public function action_delete($id)
    {
    }

    public function action_search()
    {
        return View::make('blog.search');
    }
}
</code>
ログイン後にコピー

屎一样的代码我不忍心看了。这他妈的就是面向过程的开发好么,话说这么多静态方法是啥意思?
laravel之所以这么火,靠的是营销和吹牛逼。看看laravel的首页就知道,花花绿绿的。
金玉其外,败絮其中。symfony不知道比laravel高了多少个等级,去看看symfony首页。

laravel在github上面的提交更新好高啊!当然了,是个程序员都能提,当然高了。laravel里面的代码比起YII里面的代码。真的渣的跟屎一样。
laravel用的人好多啊!因为laravel不需要费脑子,源代码一看就懂,自信心爆棚,觉得老子好聪明啊,全球最多人使用的框架,数百位工程师的结晶的源代码一看就懂(同时用几款框架的不在此列)
再来看看laravel首页说的那些傻叉言论。什么Restfull,什么企业级,什么稳定,什么开源的。他妈的要是一个PHP框架连这些最基本的要求都达不到,还用PHP框架干什么?laravel把这些拿出来,就是骗一些脑残的程序员,殊不知这些要求都是好的PHP框架最基本的。
Laravel更优雅,第一次看见laravel的时候惊呼:这不就是php版的rails吗?
看到这句话我笑了。

Laravel搞不好面向对象,就把操作弄成rails的形式,美其名曰,简洁。当然,我不得不承认Laravel还真他妈简洁。说实话有时候简洁快速真的很重要。就说ORM来说,YII生成一个model比起Laravel要复杂太多。
YII是纯面向对象的,不会这些奇淫技巧。
laravel的精髓在于ioc和facade 理解了思想就能更上一步。这他妈不是废话么?你把YII的Behavior理解了,你也能更上一步。而且IOC和facade这种东西就是奇淫技巧,没有一点用,耍花枪的真正上战场干不过耍大刀的。
而且百度和傻叉腾讯内部PHP项目基本上都是YII(腾讯也大量用thinkphp,比如腾讯家居)。
还有一点让某些程序员欲罢不能。laravel基本工作就是让你按照面向过程写代码,你需要的代码直接调用静态方法就行了。这就是为什么laravel会让程序员写代码感觉那么happy。面想过程起来真的很爽。
YII一开始就让程序员面向对象,面向对象写起来当然一点也没有面向过程写起来那么happy。
YII被广泛用于金融领域,试问哪个PHP框架可以做到?laravel的安全机制就是渣。经常被黑客们cookie伪造,解密。YII你来试试。

最近有人说YII会被Symfony取代,我只能说他们想多了。
YII被广泛用于那些对安全特性要求较高和稳定性要求较高的领域,比如OA系统(百度内部),百度商业基础平台,金融领域
补充一下,小米的php部分也是YII开发的。
多玩游戏也是YII开发的
其实我不想说奇虎360也是YII

腾讯大多数都是(与PHP相关的)

兄台去智联招聘搜搜吧!
搜YII几十页
搜所谓的laravel好像只有一页
去内推搜YII 会发现多如狗
去内推搜laravel会发现好像一页都没有占满
拉勾网laravel一个都搜不到
所以说
laravel玩玩可以,用来做企业级,我只能呵呵
刺痛某些程序员的G点的来了!一般用laravel的,基本上都是外包公司,没有自己的核心产品。因为laravel开发快,做起来像那么回事

<code><?php echo "hello,world";
?></code>
ログイン後にコピー
関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート